diff options
| -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);  | 
