[Scummvm-cvs-logs] CVS: scummvm/sound adpcm.cpp,1.10,1.11 adpcm.h,1.5,1.6 wave.cpp,1.9,1.10

Eugene Sandulenko sev at users.sourceforge.net
Tue Oct 18 22:00:14 CEST 2005


Update of /cvsroot/scummvm/scummvm/sound
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3971/sound

Modified Files:
	adpcm.cpp adpcm.h wave.cpp 
Log Message:
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 ;)


Index: adpcm.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/adpcm.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- adpcm.cpp	19 Oct 2005 03:25:00 -0000	1.10
+++ adpcm.cpp	19 Oct 2005 04:59:18 -0000	1.11
@@ -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;
-
-	int16 stepAdjust(byte);
-	int16 decode(byte);
 
-public:
-	ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size);
-	~ADPCMInputStream() {};
+ADPCMInputStream::ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int channels)
+	: _stream(stream), _channels(channels), _type(type) {
 
-	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 @@
 	// 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 @@
 			
 			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 @@
 	}
 	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 @@
 };
 
 // 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 @@
 	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 @@
 
 	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;
-}

Index: adpcm.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/adpcm.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- adpcm.h	18 Oct 2005 01:30:23 -0000	1.5
+++ adpcm.h	19 Oct 2005 04:59:18 -0000	1.6
@@ -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 @@
 // 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

Index: wave.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/wave.cpp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- wave.cpp	18 Oct 2005 01:30:23 -0000	1.9
+++ wave.cpp	19 Oct 2005 04:59:18 -0000	1.10
@@ -161,7 +161,7 @@
 		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);





More information about the Scummvm-git-logs mailing list