diff options
author | Sven Hesse | 2007-08-01 12:24:04 +0000 |
---|---|---|
committer | Sven Hesse | 2007-08-01 12:24:04 +0000 |
commit | 35052de25feca6ff2a27c4f2434280939e20dd09 (patch) | |
tree | bc78733dd3cb5f927c0965e2ad98cd75a517e261 /engines/gob | |
parent | 5d7daad632f757621476e29b8de1ee47512948ba (diff) | |
download | scummvm-rg350-35052de25feca6ff2a27c4f2434280939e20dd09.tar.gz scummvm-rg350-35052de25feca6ff2a27c4f2434280939e20dd09.tar.bz2 scummvm-rg350-35052de25feca6ff2a27c4f2434280939e20dd09.zip |
Support for (still a bit glitchy) 16bit sound
svn-id: r28383
Diffstat (limited to 'engines/gob')
-rw-r--r-- | engines/gob/coktelvideo.cpp | 158 | ||||
-rw-r--r-- | engines/gob/coktelvideo.h | 15 |
2 files changed, 138 insertions, 35 deletions
diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp index 864a760ea8..cd497293af 100644 --- a/engines/gob/coktelvideo.cpp +++ b/engines/gob/coktelvideo.cpp @@ -109,7 +109,7 @@ bool Imd::load(Common::SeekableReadStream &stream) { // Sound if (_features & kFeaturesSound) { _soundFreq = _stream->readSint16LE(); - _soundSliceSize = _stream->readUint16LE(); + _soundSliceSize = _stream->readSint16LE(); _soundSlicesCount = _stream->readSint16LE(); if (_soundFreq < 0) @@ -540,6 +540,7 @@ CoktelVideo::State Imd::processFrame(uint16 frame) { assert(soundBuf); memset(soundBuf, 0, _soundSliceSize); + _audioStream->queueBuffer(soundBuf, _soundSliceSize); } } @@ -819,6 +820,22 @@ void Imd::deLZ77(byte *dest, byte *src) { } } +const uint16 Vmd::_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 +}; + Vmd::Vmd() { clear(false); } @@ -880,7 +897,7 @@ bool Vmd::load(Common::SeekableReadStream &stream) { } _soundFreq = _stream->readSint16LE(); - _soundSliceSize = _stream->readUint16LE(); + _soundSliceSize = _stream->readSint16LE(); _soundSlicesCount = _stream->readSint16LE(); _soundFlags = _stream->readUint16LE(); _hasSound = (_soundFreq != 0); @@ -888,11 +905,26 @@ bool Vmd::load(Common::SeekableReadStream &stream) { if (_hasSound) { _features |= kFeaturesSound; - _soundSliceLength = (uint16) (1000.0 / ((double) _soundFreq / (double) _soundSliceSize)); + _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0); + if (_soundStereo > 0) { + warning("TODO: VMD stereo"); + unload(); + return false; + } + + if (_soundSliceSize < 0) { + _soundBytesPerSample = 2; + _soundSliceSize = -_soundSliceSize; + } + + _soundSliceLength = (uint16) (1000.0 / + ((double) _soundFreq / (double) _soundSliceSize)); + _frameLength = _soundSliceLength; _soundStage = 1; - _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0); + _audioStream = Audio::makeAppendableAudioStream(_soundFreq, + (_soundBytesPerSample == 2) ? Audio::Mixer::FLAG_16BITS : 0); } else _frameLength = 1000 / 12; // 12 FPS for a video without sound @@ -1004,8 +1036,12 @@ void Vmd::clear(bool del) { } _hasVideo = true; + _partsPerFrame = 0; _frames = 0; + + _soundBytesPerSample = 1; + _soundStereo = 0; } CoktelVideo::State Vmd::processFrame(uint16 frame) { @@ -1027,39 +1063,23 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { Part &part = _frames[frame].parts[i]; if (part.type == kPartTypeAudio) { - byte *soundBuf; - // Next sound slice data if (part.flags == 1) { - if (_soundEnabled) { - soundBuf = new byte[part.size]; - assert(soundBuf); - - _stream->read(soundBuf, part.size); - unsignedToSigned(soundBuf, part.size); - - _audioStream->queueBuffer(soundBuf, part.size); - } else + if (_soundEnabled) + filledSoundSlice(part.size); + else _stream->skip(part.size); // Initial sound data (all slices) } else if (part.flags == 2) { if (_soundEnabled) { - _stream->skip(4); // Unknown - - soundBuf = new byte[part.size - 4]; - assert(soundBuf); - - _stream->read(soundBuf, part.size - 4); - unsignedToSigned(soundBuf, part.size - 4); + uint32 mask = _stream->readUint32LE(); + filledSoundSlices(part.size - 4, mask); - _audioStream->queueBuffer(soundBuf, part.size - 4); - - if (_soundStage == 1) { + if (_soundStage == 1) startSound = true; - } } else _stream->skip(part.size); @@ -1067,15 +1087,11 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { // Empty sound slice } else if (part.flags == 3) { - if (_soundEnabled && (part.size > 0)) { - soundBuf = new byte[part.size]; - assert(soundBuf); - - memset(soundBuf, 0, part.size); - - _audioStream->queueBuffer(soundBuf, part.size); - } else + if (_soundEnabled && (part.size > 0)) + emptySoundSlice(part.size); + else _stream->skip(part.size); + } } else if (part.type == kPartTypeVideo) { @@ -1194,4 +1210,78 @@ uint32 Vmd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) { return 1; } +void Vmd::emptySoundSlice(uint32 size) { + byte *soundBuf = new byte[size]; + assert(soundBuf); + + memset(soundBuf, 0, size); + + _audioStream->queueBuffer(soundBuf, size); +} + +void Vmd::soundSlice8bit(uint32 size) { + byte *soundBuf = new byte[size]; + assert(soundBuf); + + _stream->read(soundBuf, size); + unsignedToSigned(soundBuf, size); + + _audioStream->queueBuffer(soundBuf, size); +} + +void Vmd::soundSlice16bit(uint32 size, int16 &init) { + byte *dataBuf = new byte[size]; + byte *soundBuf = new byte[size * 2]; + + _stream->read(dataBuf, size); + deDPCM(soundBuf, dataBuf, init, size); + _audioStream->queueBuffer(soundBuf, size * 2); + + delete[] dataBuf; +} + +void Vmd::filledSoundSlice(uint32 size) { + if (_soundBytesPerSample == 1) { + soundSlice8bit(size); + } else if (_soundBytesPerSample == 2) { + int16 init = _stream->readSint16LE(); + soundSlice16bit(size - 1, init); + } +} + +void Vmd::filledSoundSlices(uint32 size, uint32 mask) { + if (_soundBytesPerSample == 1) { + soundSlice8bit(size); + return; + } + + for (int i = 0; i < (_soundSlicesCount - 1); i++) { + + if (mask & 1) + emptySoundSlice(_soundSliceSize * 2); + else { + int16 init = _stream->readSint16LE(); + soundSlice16bit(_soundSliceSize, init); + } + + mask >>= 1; + } + +} + +void Vmd::deDPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n) { + int16 *out = (int16 *) soundBuf; + + int32 s = init; + for (uint32 i = 0; i < n; i++) { + if(dataBuf[i] & 0x80) + s -= _tableDPCM[dataBuf[i] & 0x7F]; + else + s += _tableDPCM[dataBuf[i]]; + + s = CLIP(s, -32768, 32767); + *out++ = TO_BE_16(s); + } +} + } // End of namespace Gob diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h index 39228c7bca..a4e5452cce 100644 --- a/engines/gob/coktelvideo.h +++ b/engines/gob/coktelvideo.h @@ -225,7 +225,7 @@ protected: uint16 _soundFlags; int16 _soundFreq; - uint16 _soundSliceSize; + int16 _soundSliceSize; int16 _soundSlicesCount; uint16 _soundSliceLength; @@ -285,14 +285,27 @@ protected: ~Frame() { delete[] parts; } } PACKED_STRUCT; + static const uint16 _tableDPCM[128]; + bool _hasVideo; + uint16 _partsPerFrame; Frame *_frames; + byte _soundBytesPerSample; + byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo) + void clear(bool del = true); State processFrame(uint16 frame); uint32 renderFrame(int16 left, int16 top, int16 right, int16 bottom); + + void emptySoundSlice(uint32 size); + void soundSlice8bit(uint32 size); + void soundSlice16bit(uint32 size, int16 &init); + void filledSoundSlice(uint32 size); + void filledSoundSlices(uint32 size, uint32 mask); + void deDPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n); }; } // End of namespace Gob |