aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2005-10-19 04:59:18 +0000
committerEugene Sandulenko2005-10-19 04:59:18 +0000
commit4306c9344cd00edff5b9a04152d68a1a7b0862aa (patch)
tree02978ce48b40c00efe4be9b5fc85e7a68edd4114
parent13246d0dadd236fb36eeeb12228e53101cdabc43 (diff)
downloadscummvm-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.cpp2
-rw-r--r--scumm/sound.cpp2
-rw-r--r--sound/adpcm.cpp115
-rw-r--r--sound/adpcm.h32
-rw-r--r--sound/wave.cpp2
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);