aboutsummaryrefslogtreecommitdiff
path: root/video/coktel_decoder.cpp
diff options
context:
space:
mode:
authorMatthew Hoops2011-04-25 12:45:33 -0400
committerSven Hesse2011-11-27 15:52:05 +0100
commit6bbff583146843baade8f6268a2e1ea92be416ba (patch)
treee80281c7d7a99a9a2c523e0b6684d17089797280 /video/coktel_decoder.cpp
parent5518721a17e751a2ac6deefe56ef0ce446f184ab (diff)
downloadscummvm-rg350-6bbff583146843baade8f6268a2e1ea92be416ba.tar.gz
scummvm-rg350-6bbff583146843baade8f6268a2e1ea92be416ba.tar.bz2
scummvm-rg350-6bbff583146843baade8f6268a2e1ea92be416ba.zip
VIDEO: Rewrite VMD audio streaming
Audio is now decoded in AudioStream classes instead of being decoded ahead of time and then queued.
Diffstat (limited to 'video/coktel_decoder.cpp')
-rw-r--r--video/coktel_decoder.cpp287
1 files changed, 110 insertions, 177 deletions
diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp
index 8ea2d08acb..ae0c35cd76 100644
--- a/video/coktel_decoder.cpp
+++ b/video/coktel_decoder.cpp
@@ -1505,23 +1505,6 @@ VMDDecoder::Frame::~Frame() {
delete[] parts;
}
-
-const uint16 VMDDecoder::_tableDPCM[128] = {
- 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
- 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
- 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
- 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230,
- 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280,
- 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0,
- 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320,
- 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370,
- 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0,
- 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480,
- 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700,
- 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00,
- 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
-};
-
VMDDecoder::VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType),
_stream(0), _version(0), _flags(0), _frameInfoOffset(0), _partsPerFrame(0), _frames(0),
_soundFlags(0), _soundFreq(0), _soundSliceSize(0), _soundSlicesCount(0),
@@ -2402,33 +2385,36 @@ void VMDDecoder::blit24(const Graphics::Surface &srcSurf, Common::Rect &rect) {
}
void VMDDecoder::emptySoundSlice(uint32 size) {
- byte *sound = soundEmpty(size);
+ byte *soundBuf = (byte *)malloc(size);
- if (sound) {
+ if (soundBuf) {
uint32 flags = 0;
+ memset(soundBuf, 0, size);
flags |= (_soundBytesPerSample == 2) ? Audio::FLAG_16BITS : 0;
flags |= (_soundStereo > 0) ? Audio::FLAG_STEREO : 0;
- _audioStream->queueBuffer(sound, size, DisposeAfterUse::YES, flags);
+ _audioStream->queueBuffer(soundBuf, size, DisposeAfterUse::YES, flags);
}
}
void VMDDecoder::filledSoundSlice(uint32 size) {
- byte *sound = 0;
+ if (!_audioStream) {
+ _stream->skip(size);
+ return;
+ }
+
+ Common::SeekableReadStream *data = _stream->readStream(size);
+ Audio::AudioStream *sliceStream = 0;
+
if (_audioFormat == kAudioFormat8bitRaw)
- sound = sound8bitRaw(size);
+ sliceStream = create8bitRaw(data);
else if (_audioFormat == kAudioFormat16bitDPCM)
- sound = sound16bitDPCM(size);
+ sliceStream = create16bitDPCM(data);
else if (_audioFormat == kAudioFormat16bitADPCM)
- sound = sound16bitADPCM(size);
+ sliceStream = create16bitADPCM(data);
- if (sound) {
- uint32 flags = 0;
- flags |= (_soundBytesPerSample == 2) ? Audio::FLAG_16BITS : 0;
- flags |= (_soundStereo > 0) ? Audio::FLAG_STEREO : 0;
-
- _audioStream->queueBuffer(sound, size, DisposeAfterUse::YES, flags);
- }
+ if (sliceStream)
+ _audioStream->queueAudioStream(sliceStream);
}
void VMDDecoder::filledSoundSlices(uint32 size, uint32 mask) {
@@ -2475,173 +2461,120 @@ uint8 VMDDecoder::evaluateMask(uint32 mask, bool *fillInfo, uint8 &max) {
return n;
}
-byte *VMDDecoder::soundEmpty(uint32 &size) {
- if (!_audioStream)
- return 0;
+Audio::AudioStream *VMDDecoder::create8bitRaw(Common::SeekableReadStream *stream) {
+ int flags = Audio::FLAG_UNSIGNED;
- byte *soundBuf = (byte *)malloc(size);
- memset(soundBuf, 0, size);
+ if (_soundStereo != 0)
+ flags |= Audio::FLAG_STEREO;
- return soundBuf;
+ return Audio::makeRawStream(stream, _soundFreq, flags, DisposeAfterUse::YES);
}
-byte *VMDDecoder::sound8bitRaw(uint32 &size) {
- if (!_audioStream) {
- _stream->skip(size);
- return 0;
+class DPCMStream : public Audio::AudioStream {
+public:
+ DPCMStream(Common::SeekableReadStream *stream, int rate, int channels) {
+ _stream = stream;
+ _rate = rate;
+ _channels = channels;
}
- byte *soundBuf = (byte *)malloc(size);
- _stream->read(soundBuf, size);
- unsignedToSigned(soundBuf, size);
-
- return soundBuf;
-}
-
-byte *VMDDecoder::sound16bitDPCM(uint32 &size) {
- if (!_audioStream) {
- _stream->skip(size);
- return 0;
+ ~DPCMStream() {
+ delete _stream;
}
- int32 init[2];
+ int readBuffer(int16 *buffer, const int numSamples);
+ bool isStereo() const { return _channels == 2; }
+ int getRate() const { return _rate; }
+ bool endOfData() const { return _stream->pos() >= _stream->size() || _stream->eos() || _stream->err(); }
- init[0] = _stream->readSint16LE();
- size -= 2;
-
- if (_soundStereo > 0) {
- init[1] = _stream->readSint16LE();
- size -= 2;
- }
-
- byte *data = new byte[size];
- byte *sound = 0;
-
- if (_stream->read(data, size) == size)
- sound = deDPCM(data, size, init);
-
- delete[] data;
+private:
+ Common::SeekableReadStream *_stream;
+ int _channels;
+ int _rate;
+ int _buffer[2];
+};
- return sound;
-}
+int DPCMStream::readBuffer(int16 *buffer, const int numSamples) {
+ static const uint16 tableDPCM[128] = {
+ 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
+ 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
+ 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
+ 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230,
+ 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280,
+ 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0,
+ 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320,
+ 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370,
+ 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0,
+ 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480,
+ 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700,
+ 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00,
+ 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
+ };
+
+ assert((numSamples % _channels) == 0);
+
+ int samples = 0;
+
+ // Our starting position
+ if (_stream->pos() == 0) {
+ for (int i = 0; i < _channels; i++)
+ *buffer++ = _buffer[i] = _stream->readSint16LE();
+
+ samples += _channels;
+ }
+
+ while (!endOfData() && samples < numSamples) {
+ for (int i = 0; i < _channels; i++) {
+ byte data = _stream->readByte();
+
+ if (data & 0x80)
+ _buffer[i] -= tableDPCM[data & 0x7f];
+ else
+ _buffer[i] += tableDPCM[data];
+
+ *buffer++ = _buffer[i] = CLIP<int32>(_buffer[i], -32768, 32767);
+ }
-byte *VMDDecoder::sound16bitADPCM(uint32 &size) {
- if (!_audioStream) {
- _stream->skip(size);
- return 0;
+ samples += _channels;
}
- int32 init = _stream->readSint16LE();
- size -= 2;
-
- int32 index = _stream->readByte();
- size--;
-
- byte *data = new byte[size];
- byte *sound = 0;
-
- if (_stream->read(data, size) == size)
- sound = deADPCM(data, size, init, index);
-
- delete[] data;
-
- return sound;
+ return samples;
}
-byte *VMDDecoder::deDPCM(const byte *data, uint32 &size, int32 init[2]) {
- if (!data || (size == 0))
- return 0;
-
- int channels = (_soundStereo > 0) ? 2 : 1;
-
- uint32 inSize = size;
- uint32 outSize = size + channels;
-
- int16 *out = (int16 *)malloc(outSize * 2);
- byte *sound = (byte *)out;
-
- if (!out)
- return 0;
-
- int channel = 0;
-
- for (int i = 0; i < channels; i++) {
- *out++ = TO_BE_16(init[channel]);
+Audio::AudioStream *VMDDecoder::create16bitDPCM(Common::SeekableReadStream *stream) {
+ return new DPCMStream(stream, _soundFreq, (_soundStereo == 0) ? 1 : 2);
+}
- channel = (channel + 1) % channels;
+class VMD_ADPCMStream : public Audio::DVI_ADPCMStream {
+public:
+ VMD_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse,
+ int rate, int channels) : Audio::DVI_ADPCMStream(stream, disposeAfterUse, stream->size(), rate, channels, 0) {
+ // FIXME: Using the same predictor/index for two channels probably won't work
+ // properly However, we have no samples of this, so an assert is here for now.
+ // Also, since the DPCM stereo has a second predictor, I'm lead to believe
+ // all VMD with ADPCM are mono unless they changed the code in a later
+ // revision.
+ assert(channels == 1);
+ _startPredictorValue = stream->readSint16LE();
+ _startIndexValue = stream->readByte();
+ _startpos = 3;
+ reset();
}
- while (inSize-- > 0) {
- if (*data & 0x80)
- init[channel] -= _tableDPCM[*data++ & 0x7F];
- else
- init[channel] += _tableDPCM[*data++];
-
- init[channel] = CLIP<int32>(init[channel], -32768, 32767);
- *out++ = TO_BE_16(init[channel]);
-
- channel = (channel + 1) % channels;
+protected:
+ virtual void reset() {
+ Audio::DVI_ADPCMStream::reset();
+ _status.ima_ch[0].last = _startPredictorValue;
+ _status.ima_ch[0].stepIndex = _startIndexValue;
}
- size = outSize * 2;
- return sound;
-}
-
-// Yet another IMA ADPCM variant
-byte *VMDDecoder::deADPCM(const byte *data, uint32 &size, int32 init, int32 index) {
- if (!data || (size == 0))
- return 0;
-
- uint32 outSize = size * 2;
-
- int16 *out = (int16 *)malloc(outSize * 2);
- byte *sound = (byte *) out;
-
- index = CLIP<int32>(index, 0, 88);
-
- int32 predictor = Audio::Ima_ADPCMStream::_imaTable[index];
-
- uint32 dataByte = 0;
- bool newByte = true;
-
- size *= 2;
- while (size -- > 0) {
- byte code = 0;
-
- if (newByte) {
- dataByte = *data++;
- code = (dataByte >> 4) & 0xF;
- } else
- code = dataByte & 0xF;
-
- newByte = !newByte;
-
- index += Audio::ADPCMStream::_stepAdjustTable[code];
- index = CLIP<int32>(index, 0, 88);
-
- int32 value = predictor / 8;
-
- if (code & 4)
- value += predictor;
- if (code & 2)
- value += predictor / 2;
- if (code & 1)
- value += predictor / 4;
-
- if (code & 8)
- init -= value;
- else
- init += value;
-
- init = CLIP<int32>(init, -32768, 32767);
-
- predictor = Audio::Ima_ADPCMStream::_imaTable[index];
-
- *out++ = TO_BE_16(init);
- }
+private:
+ int32 _startPredictorValue;
+ int32 _startIndexValue;
+};
- size = outSize * 2;
- return sound;
+Audio::AudioStream *VMDDecoder::create16bitADPCM(Common::SeekableReadStream *stream) {
+ return new VMD_ADPCMStream(stream, DisposeAfterUse::YES, _soundFreq, (_soundStereo == 0) ? 1 : 2);
}
Graphics::PixelFormat VMDDecoder::getPixelFormat() const {