[Scummvm-cvs-logs] CVS: scummvm/sound adpcm.cpp,1.8.2.1,1.8.2.2 adpcm.h,1.4.2.1,1.4.2.2 wave.cpp,1.8.2.1,1.8.2.2 wave.h,1.4.2.1,1.4.2.2

Eugene Sandulenko sev at users.sourceforge.net
Thu Oct 20 19:26:18 CEST 2005


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

Modified Files:
      Tag: branch-0-8-0
	adpcm.cpp adpcm.h wave.cpp wave.h 
Log Message:
Backport IMA ADPCM fixes. This fixes bunch of latter HE games.


Index: adpcm.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/adpcm.cpp,v
retrieving revision 1.8.2.1
retrieving revision 1.8.2.2
diff -u -d -r1.8.2.1 -r1.8.2.2
--- adpcm.cpp	18 Oct 2005 02:11:26 -0000	1.8.2.1
+++ adpcm.cpp	21 Oct 2005 02:25:20 -0000	1.8.2.2
@@ -20,9 +20,7 @@
  */
 
 #include "common/stdafx.h"
-#include "common/stream.h"
 
-#include "sound/audiostream.h"
 #include "sound/adpcm.h"
 
 
@@ -31,64 +29,102 @@
 // 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:
-	bool _evenPos;
-	byte _lastByte;
-	Common::SeekableReadStream *_stream;
-	uint32 _endpos;
 
-	struct adpcmStatus {
-		int16 last;
-		int16 stepIndex;
-	} _status;
+ADPCMInputStream::ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int channels, uint32 blockAlign)
+	: _stream(stream), _channels(channels), _type(type), _blockAlign(blockAlign) {
 
-	int16 stepAdjust(byte);
-	int16 decode(byte);
+	_status.last = 0;
+	_status.stepIndex = 0;
+	_endpos = stream->pos() + size;
 
-public:
-	ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size);
-	~ADPCMInputStream() {};
+	if (type == kADPCMIma && blockAlign == 0)
+		error("ADPCMInputStream(): blockAlign isn't specifiled for MS ADPCM IMA");
+}
 
-	int readBuffer(int16 *buffer, const int numSamples);
+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;
+}
 
-	bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); }
-	bool isStereo() const	{ return false; }
-	int getRate() const	{ return 22050; }
-};
+int ADPCMInputStream::readBufferOKI(int16 *buffer, const int numSamples) {
+	int samples;
+	byte data;
 
+	assert(numSamples % 2 == 0);
 
-template <typesADPCM TYPE>
-ADPCMInputStream<TYPE>::ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size)
-	: _stream(stream), _evenPos(true) {
+	for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
+		data = _stream->readByte();
+		buffer[samples] = TO_LE_16(decodeOKI((data >> 4) & 0x0f));
+		buffer[samples + 1] = TO_LE_16(decodeOKI(data & 0x0f));
+	}
+	return samples;
+}
 
-	_status.last = 0;
-	_status.stepIndex = 0;
-	_endpos = stream->pos() + size;
+
+int ADPCMInputStream::readBufferMSIMA1(int16 *buffer, const int numSamples) {
+	int samples;
+	byte data;
+	int blockLen;
+	int i;
+
+	assert(numSamples % 2 == 0);
+
+	samples = 0;
+
+	while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
+		// read block header
+		_status.last = _stream->readSint16LE();
+		_status.stepIndex = _stream->readSint16LE();
+
+		blockLen = MIN(_endpos - _stream->pos(), _blockAlign - 4);
+
+		for (i = 0; i < blockLen && !_stream->eos() && _stream->pos() < _endpos; i++, samples += 2) {
+			data = _stream->readByte();
+			buffer[samples] = TO_LE_16(decodeMSIMA(data & 0x0f));
+			buffer[samples + 1] = TO_LE_16(decodeMSIMA((data >> 4) & 0x0f));
+		}
+	}
+	return samples;
 }
 
-template <typesADPCM TYPE>
-int ADPCMInputStream<TYPE>::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;
 
-	// Since we process high and low nibbles separately never check buffer end
-	// on low nibble
-	for (samples = 0; !_evenPos || samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples++) {
-		if (_evenPos) {
-			_lastByte = _stream->readByte();
-			buffer[samples] = decode((_lastByte >> 4) & 0x0f);
-		} else {
-			buffer[samples] = decode(_lastByte & 0x0f);
+	for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos;) {
+		for (int channel = 0; channel < 2; channel++) {
+			data = _stream->readUint32LE();
+			
+			for (nibble = 0; nibble < 8; nibble++) {
+				byte k = ((data & 0xf0000000) >> 28);
+				buffer[samples + channel + nibble * 2] = TO_LE_16(decodeMSIMA(k));
+				data <<= 4;
+			}
 		}
-		_evenPos = !_evenPos;
+		samples += 16;
 	}
 	return samples;
 }
 
 // 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];
@@ -105,8 +141,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];
@@ -153,27 +188,27 @@
 	32767
 };
 
-template <>
-int16 ADPCMInputStream<kADPCMIma>::decode(byte code) {
+int16 ADPCMInputStream::decodeMSIMA(byte code) {
 	int32 diff, E, SS, samp;
 
 	SS = imaStepTable[_status.stepIndex];
-	E = SS/8;
-	if (code & 0x01)
-		E += SS/4;
-	if (code & 0x02)
-		E += SS/2;
+	E = SS >> 3;
 	if (code & 0x04)
 		E += SS;
+	if (code & 0x02)
+		E += SS >> 1;
+	if (code & 0x01)
+		E += SS >> 2;
 	diff = (code & 0x08) ? -E : E;
 	samp = _status.last + diff;
 
-	if (samp < -32768)
-		samp = -32768;
-	else if (samp > 32767)
-		samp = 32767;
+	if (samp < -0x8000)
+		samp = -0x8000;
+	else if (samp > 0x7fff)
+		samp = 0x7fff;
 
 	_status.last = samp;
+
 	_status.stepIndex += stepAdjust(code);
 	if (_status.stepIndex < 0)
 		_status.stepIndex = 0;
@@ -182,21 +217,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.4.2.1
retrieving revision 1.4.2.2
diff -u -d -r1.4.2.1 -r1.4.2.2
--- adpcm.h	18 Oct 2005 02:11:26 -0000	1.4.2.1
+++ adpcm.h	21 Oct 2005 02:25:20 -0000	1.4.2.2
@@ -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,35 @@
 // 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;
+	uint32 _blockAlign;
+
+	struct adpcmStatus {
+		int32 last;
+		int32 stepIndex;
+	} _status;
+
+	int16 stepAdjust(byte);
+	int16 decodeOKI(byte);
+	int16 decodeMSIMA(byte);
+
+public:
+	ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int channels = 2, uint32 blockAlign = 0);
+	~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.8.2.1
retrieving revision 1.8.2.2
diff -u -d -r1.8.2.1 -r1.8.2.2
--- wave.cpp	18 Oct 2005 02:11:26 -0000	1.8.2.1
+++ wave.cpp	21 Oct 2005 02:25:20 -0000	1.8.2.2
@@ -28,7 +28,7 @@
 #include "sound/wave.h"
 #include "sound/adpcm.h"
 
-bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType) {
+bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType, int *blockAlign_) {
 	const uint32 initialPos = stream.pos();
 	byte buf[4+1];
 
@@ -79,6 +79,9 @@
 
 	if (wavType != 0)
 		*wavType = type;
+
+	if (blockAlign_ != 0)
+		*blockAlign_ = blockAlign;
 #if 0
 	printf("WAVE information:\n");
 	printf("  total size: %d\n", wavLength);
@@ -161,7 +164,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);

Index: wave.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/wave.h,v
retrieving revision 1.4.2.1
retrieving revision 1.4.2.2
diff -u -d -r1.4.2.1 -r1.4.2.2
--- wave.h	18 Oct 2005 02:11:26 -0000	1.4.2.1
+++ wave.h	21 Oct 2005 02:25:20 -0000	1.4.2.2
@@ -34,7 +34,7 @@
  * all information about the data necessary for playback.
  * Currently this only support uncompressed raw PCM data.
  */
-extern bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType = 0);
+extern bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType = 0, int *blockAlign = 0);
 
 AudioStream *makeWAVStream(Common::SeekableReadStream &stream);
 





More information about the Scummvm-git-logs mailing list