diff options
author | Eugene Sandulenko | 2005-10-19 04:59:18 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2005-10-19 04:59:18 +0000 |
commit | 4306c9344cd00edff5b9a04152d68a1a7b0862aa (patch) | |
tree | 02978ce48b40c00efe4be9b5fc85e7a68edd4114 | |
parent | 13246d0dadd236fb36eeeb12228e53101cdabc43 (diff) | |
download | scummvm-rg350-4306c9344cd00edff5b9a04152d68a1a7b0862aa.tar.gz scummvm-rg350-4306c9344cd00edff5b9a04152d68a1a7b0862aa.tar.bz2 scummvm-rg350-4306c9344cd00edff5b9a04152d68a1a7b0862aa.zip |
Improved IMA ADPCM decoder. It appeared that MS violated yet another standard
and nibbles order in samples appeared to be swapped. Had to untemplate
whole thing over again because I have no idea how to speicalize one of two
parameters in templates.
Now voices are clean but have some ticks, looks like overload. ITE wasn't
broken ;)
svn-id: r19166
-rw-r--r-- | saga/sndres.cpp | 2 | ||||
-rw-r--r-- | scumm/sound.cpp | 2 | ||||
-rw-r--r-- | sound/adpcm.cpp | 115 | ||||
-rw-r--r-- | sound/adpcm.h | 32 | ||||
-rw-r--r-- | sound/wave.cpp | 2 |
5 files changed, 81 insertions, 72 deletions
diff --git a/saga/sndres.cpp b/saga/sndres.cpp index e508a00673..e84ea60242 100644 --- a/saga/sndres.cpp +++ b/saga/sndres.cpp @@ -216,7 +216,7 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff buffer.buffer = NULL; free(soundResource); } else { - voxStream = makeADPCMStream(readS, soundResourceLength, kADPCMOki); + voxStream = new ADPCMInputStream(&readS, soundResourceLength, kADPCMOki); buffer.buffer = (byte *)malloc(buffer.size); voxSize = voxStream->readBuffer((int16*)buffer.buffer, soundResourceLength * 2); if (voxSize != soundResourceLength * 2) { diff --git a/scumm/sound.cpp b/scumm/sound.cpp index 4cbea0ebce..dbbb0f11c9 100644 --- a/scumm/sound.cpp +++ b/scumm/sound.cpp @@ -316,7 +316,7 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) { } if (type == 17) { - AudioStream *voxStream = makeADPCMStream(stream, size, kADPCMIma); + AudioStream *voxStream = new ADPCMInputStream(&stream, size, kADPCMIma, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1); sound = (char *)malloc(size * 2); size = voxStream->readBuffer((int16*)sound, size * 2); diff --git a/sound/adpcm.cpp b/sound/adpcm.cpp index 83fcb82847..b38cadd733 100644 --- a/sound/adpcm.cpp +++ b/sound/adpcm.cpp @@ -20,9 +20,7 @@ */ #include "common/stdafx.h" -#include "common/stream.h" -#include "sound/audiostream.h" #include "sound/adpcm.h" @@ -31,47 +29,51 @@ // See also <http://www.comptek.ru/telephony/tnotes/tt1-13.html> // // In addition, also IMA ADPCM is supported. -template <typesADPCM TYPE> -class ADPCMInputStream : public AudioStream { -private: - Common::SeekableReadStream *_stream; - uint32 _endpos; - struct adpcmStatus { - int16 last; - int16 stepIndex; - } _status; +ADPCMInputStream::ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int channels) + : _stream(stream), _channels(channels), _type(type) { - int16 stepAdjust(byte); - int16 decode(byte); - -public: - ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size); - ~ADPCMInputStream() {}; - - int readBuffer(int16 *buffer, const int numSamples); + _status.last = 0; + _status.stepIndex = 0; + _endpos = stream->pos() + size; +} - bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); } - bool isStereo() const { return false; } - int getRate() const { return 22050; } -}; +int ADPCMInputStream::readBuffer(int16 *buffer, const int numSamples) { + switch (_type) { + case kADPCMOki: + return readBufferOKI(buffer, numSamples); + break; + case kADPCMIma: + if (_channels == 1) + return readBufferMSIMA1(buffer, numSamples); + else + return readBufferMSIMA2(buffer, numSamples); + break; + default: + error("Unsupported ADPCM encoding"); + break; + } + return 0; +} -template <> -int16 ADPCMInputStream<kADPCMOki>::decode(byte code); -template <> -int16 ADPCMInputStream<kADPCMIma>::decode(byte code); +int ADPCMInputStream::readBufferOKI(int16 *buffer, const int numSamples) { + int samples; + byte data; -template <typesADPCM TYPE> -ADPCMInputStream<TYPE>::ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size) - : _stream(stream) { + assert(numSamples % 2 == 0); - _status.last = 0; - _status.stepIndex = 0; - _endpos = stream->pos() + size; + // Since we process high and low nibbles separately never check buffer end + // on low nibble + for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { + data = _stream->readByte(); + buffer[samples] = decodeOKI((data >> 4) & 0x0f); + buffer[samples + 1] = decodeOKI(data & 0x0f); + } + return samples; } -template <typesADPCM TYPE> -int ADPCMInputStream<TYPE>::readBuffer(int16 *buffer, const int numSamples) { + +int ADPCMInputStream::readBufferMSIMA1(int16 *buffer, const int numSamples) { int samples; byte data; @@ -81,17 +83,16 @@ int ADPCMInputStream<TYPE>::readBuffer(int16 *buffer, const int numSamples) { // on low nibble for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { data = _stream->readByte(); - buffer[samples] = decode((data >> 4) & 0x0f); - buffer[samples + 1] = decode(data & 0x0f); + buffer[samples] = decodeMSIMA(data & 0x0f); + buffer[samples + 1] = decodeMSIMA((data >> 4) & 0x0f); } return samples; } -// Microsoft as usual tries to implement it differently. Though we don't -// use this now -#if 0 -template <> -int ADPCMInputStream<kADPCMIma>::readBuffer(int16 *buffer, const int numSamples) { + +// Microsoft as usual tries to implement it differently. This method +// is used for stereo data. +int ADPCMInputStream::readBufferMSIMA2(int16 *buffer, const int numSamples) { int samples; uint32 data; int nibble; @@ -102,7 +103,7 @@ int ADPCMInputStream<kADPCMIma>::readBuffer(int16 *buffer, const int numSamples) for (nibble = 0; nibble < 8; nibble++) { byte k = ((data & 0xf0000000) >> 28); - buffer[samples + channel + nibble * 2] = decode(k); + buffer[samples + channel + nibble * 2] = decodeMSIMA(k); data <<= 4; } } @@ -110,11 +111,9 @@ int ADPCMInputStream<kADPCMIma>::readBuffer(int16 *buffer, const int numSamples) } return samples; } -#endif // adjust the step for use on the next sample. -template <typesADPCM TYPE> -int16 ADPCMInputStream<TYPE>::stepAdjust(byte code) { +int16 ADPCMInputStream::stepAdjust(byte code) { static const int16 adjusts[] = {-1, -1, -1, -1, 2, 4, 6, 8}; return adjusts[code & 0x07]; @@ -131,8 +130,7 @@ static const int16 okiStepSize[49] = { }; // Decode Linear to ADPCM -template <> -int16 ADPCMInputStream<kADPCMOki>::decode(byte code) { +int16 ADPCMInputStream::decodeOKI(byte code) { int16 diff, E, SS, samp; SS = okiStepSize[_status.stepIndex]; @@ -179,8 +177,7 @@ static const uint16 imaStepTable[89] = { 32767 }; -template <> -int16 ADPCMInputStream<kADPCMIma>::decode(byte code) { +int16 ADPCMInputStream::decodeMSIMA(byte code) { int32 diff, E, SS, samp; SS = imaStepTable[_status.stepIndex]; @@ -208,21 +205,3 @@ int16 ADPCMInputStream<kADPCMIma>::decode(byte code) { return samp; } - -AudioStream *makeADPCMStream(Common::SeekableReadStream &stream, uint32 size, typesADPCM type) { - AudioStream *audioStream; - - switch (type) { - case kADPCMOki: - audioStream = new ADPCMInputStream<kADPCMOki>(&stream, size); - break; - case kADPCMIma: - audioStream = new ADPCMInputStream<kADPCMIma>(&stream, size); - break; - default: - error("Unsupported ADPCM encoding"); - break; - } - - return audioStream; -} diff --git a/sound/adpcm.h b/sound/adpcm.h index 9dba798642..d26a2ccceb 100644 --- a/sound/adpcm.h +++ b/sound/adpcm.h @@ -24,6 +24,8 @@ #include "common/stdafx.h" #include "common/scummsys.h" +#include "common/stream.h" +#include "sound/audiostream.h" class AudioStream; @@ -35,6 +37,34 @@ enum typesADPCM { // TODO: Switch from a SeekableReadStream to a plain ReadStream. This requires // some internal refactoring but is definitely possible and will increase the // flexibility of this code. -AudioStream *makeADPCMStream(Common::SeekableReadStream &stream, uint32 size, typesADPCM type); +class ADPCMInputStream : public AudioStream { +private: + Common::SeekableReadStream *_stream; + uint32 _endpos; + int _channels; + typesADPCM _type; + + struct adpcmStatus { + int16 last; + int16 stepIndex; + } _status; + + int16 stepAdjust(byte); + int16 decodeOKI(byte); + int16 decodeMSIMA(byte); + +public: + ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int channels = 2); + ~ADPCMInputStream() {}; + + int readBuffer(int16 *buffer, const int numSamples); + int readBufferOKI(int16 *buffer, const int numSamples); + int readBufferMSIMA1(int16 *buffer, const int numSamples); + int readBufferMSIMA2(int16 *buffer, const int numSamples); + + bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); } + bool isStereo() const { return false; } + int getRate() const { return 22050; } +}; #endif diff --git a/sound/wave.cpp b/sound/wave.cpp index 611057b5b5..1bc71a4297 100644 --- a/sound/wave.cpp +++ b/sound/wave.cpp @@ -161,7 +161,7 @@ AudioStream *makeWAVStream(Common::SeekableReadStream &stream) { return 0; if (type == 17) // IMA ADPCM - return makeADPCMStream(stream, size, kADPCMIma); + return new ADPCMInputStream(&stream, size, kADPCMIma, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1); byte *data = (byte *)malloc(size); assert(data); |