diff options
| -rw-r--r-- | audio/decoders/adpcm_intern.h | 6 | ||||
| -rw-r--r-- | video/coktel_decoder.cpp | 287 | ||||
| -rw-r--r-- | video/coktel_decoder.h | 16 | 
3 files changed, 116 insertions, 193 deletions
| diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h index f7162f5f2a..31747aabaf 100644 --- a/audio/decoders/adpcm_intern.h +++ b/audio/decoders/adpcm_intern.h @@ -43,7 +43,7 @@ namespace Audio {  class ADPCMStream : public RewindableAudioStream {  protected:  	Common::DisposablePtr<Common::SeekableReadStream> _stream; -	const int32 _startpos; +	int32 _startpos;  	const int32 _endpos;  	const int _channels;  	const uint32 _blockAlign; @@ -97,9 +97,7 @@ protected:  public:  	Ima_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) -		: ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { -		memset(&_status, 0, sizeof(_status)); -	} +		: ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {}  	/**  	 * This table is used by decodeIMA. diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp index 8ea2d08acb..ae0c35cd76 100644 --- a/video/coktel_decoder.cpp +++ b/video/coktel_decoder.cpp @@ -1505,23 +1505,6 @@ VMDDecoder::Frame::~Frame() {  	delete[] parts;  } - -const uint16 VMDDecoder::_tableDPCM[128] = { -	0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, -	0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120, -	0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0, -	0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230, -	0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280, -	0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0, -	0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, -	0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, -	0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0, -	0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480, -	0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, -	0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, -	0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 -}; -  VMDDecoder::VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType),  	_stream(0), _version(0), _flags(0), _frameInfoOffset(0), _partsPerFrame(0), _frames(0),  	_soundFlags(0), _soundFreq(0), _soundSliceSize(0), _soundSlicesCount(0), @@ -2402,33 +2385,36 @@ void VMDDecoder::blit24(const Graphics::Surface &srcSurf, Common::Rect &rect) {  }  void VMDDecoder::emptySoundSlice(uint32 size) { -	byte *sound = soundEmpty(size); +	byte *soundBuf = (byte *)malloc(size); -	if (sound) { +	if (soundBuf) {  		uint32 flags = 0; +		memset(soundBuf, 0, size);  		flags |= (_soundBytesPerSample == 2) ? Audio::FLAG_16BITS : 0;  		flags |= (_soundStereo > 0) ? Audio::FLAG_STEREO : 0; -		_audioStream->queueBuffer(sound, size, DisposeAfterUse::YES, flags); +		_audioStream->queueBuffer(soundBuf, size, DisposeAfterUse::YES, flags);  	}  }  void VMDDecoder::filledSoundSlice(uint32 size) { -	byte *sound = 0; +	if (!_audioStream) { +		_stream->skip(size); +		return; +	} + +	Common::SeekableReadStream *data = _stream->readStream(size); +	Audio::AudioStream *sliceStream = 0; +  	if (_audioFormat == kAudioFormat8bitRaw) -		sound = sound8bitRaw(size); +		sliceStream = create8bitRaw(data);  	else if (_audioFormat == kAudioFormat16bitDPCM) -		sound = sound16bitDPCM(size); +		sliceStream = create16bitDPCM(data);  	else if (_audioFormat == kAudioFormat16bitADPCM) -		sound = sound16bitADPCM(size); +		sliceStream = create16bitADPCM(data); -	if (sound) { -		uint32 flags = 0; -		flags |= (_soundBytesPerSample == 2) ? Audio::FLAG_16BITS : 0; -		flags |= (_soundStereo > 0) ? Audio::FLAG_STEREO : 0; - -		_audioStream->queueBuffer(sound, size, DisposeAfterUse::YES, flags); -	} +	if (sliceStream) +		_audioStream->queueAudioStream(sliceStream);  }  void VMDDecoder::filledSoundSlices(uint32 size, uint32 mask) { @@ -2475,173 +2461,120 @@ uint8 VMDDecoder::evaluateMask(uint32 mask, bool *fillInfo, uint8 &max) {  	return n;  } -byte *VMDDecoder::soundEmpty(uint32 &size) { -	if (!_audioStream) -		return 0; +Audio::AudioStream *VMDDecoder::create8bitRaw(Common::SeekableReadStream *stream) { +	int flags = Audio::FLAG_UNSIGNED; -	byte *soundBuf = (byte *)malloc(size); -	memset(soundBuf, 0, size); +	if (_soundStereo != 0) +		flags |= Audio::FLAG_STEREO; -	return soundBuf; +	return Audio::makeRawStream(stream, _soundFreq, flags, DisposeAfterUse::YES);  } -byte *VMDDecoder::sound8bitRaw(uint32 &size) { -	if (!_audioStream) { -		_stream->skip(size); -		return 0; +class DPCMStream : public Audio::AudioStream { +public: +	DPCMStream(Common::SeekableReadStream *stream, int rate, int channels) { +		_stream = stream; +		_rate = rate; +		_channels = channels;  	} -	byte *soundBuf = (byte *)malloc(size); -	_stream->read(soundBuf, size); -	unsignedToSigned(soundBuf, size); - -	return soundBuf; -} - -byte *VMDDecoder::sound16bitDPCM(uint32 &size) { -	if (!_audioStream) { -		_stream->skip(size); -		return 0; +	~DPCMStream() { +		delete _stream;  	} -	int32 init[2]; +	int readBuffer(int16 *buffer, const int numSamples); +	bool isStereo() const { return _channels == 2; } +	int getRate() const { return _rate; } +	bool endOfData() const { return _stream->pos() >= _stream->size() || _stream->eos() || _stream->err(); } -	init[0] = _stream->readSint16LE(); -	size -= 2; - -	if (_soundStereo > 0) { -		init[1] = _stream->readSint16LE(); -		size -= 2; -	} - -	byte *data  = new byte[size]; -	byte *sound = 0; - -	if (_stream->read(data, size) == size) -		sound = deDPCM(data, size, init); - -	delete[] data; +private: +	Common::SeekableReadStream *_stream; +	int _channels; +	int _rate; +	int _buffer[2]; +}; -	return sound; -} +int DPCMStream::readBuffer(int16 *buffer, const int numSamples) { +	static const uint16 tableDPCM[128] = { +		0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, +		0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120, +		0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0, +		0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230, +		0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280, +		0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0, +		0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, +		0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, +		0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0, +		0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480, +		0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, +		0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, +		0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 +	}; + +	assert((numSamples % _channels) == 0); + +	int samples = 0; + +	// Our starting position +	if (_stream->pos() == 0) { +		for (int i = 0; i < _channels; i++) +			*buffer++ = _buffer[i] = _stream->readSint16LE(); + +		samples += _channels; +	} + +	while (!endOfData() && samples < numSamples) { +		for (int i = 0; i < _channels; i++) { +			byte data = _stream->readByte(); + +			if (data & 0x80) +				_buffer[i] -= tableDPCM[data & 0x7f]; +			else +				_buffer[i] += tableDPCM[data]; + +			*buffer++ = _buffer[i] = CLIP<int32>(_buffer[i], -32768, 32767); +		} -byte *VMDDecoder::sound16bitADPCM(uint32 &size) { -	if (!_audioStream) { -		_stream->skip(size); -		return 0; +		samples += _channels;  	} -	int32 init = _stream->readSint16LE(); -	size -= 2; - -	int32 index = _stream->readByte(); -	size--; - -	byte *data  = new byte[size]; -	byte *sound = 0; - -	if (_stream->read(data, size) == size) -		sound = deADPCM(data, size, init, index); - -	delete[] data; - -	return sound; +	return samples;  } -byte *VMDDecoder::deDPCM(const byte *data, uint32 &size, int32 init[2]) { -	if (!data || (size == 0)) -		return 0; - -	int channels = (_soundStereo > 0) ? 2 : 1; - -	uint32 inSize  = size; -	uint32 outSize = size + channels; - -	int16 *out   = (int16 *)malloc(outSize * 2); -	byte  *sound = (byte *)out; - -	if (!out) -		return 0; - -	int channel = 0; - -	for (int i = 0; i < channels; i++) { -		*out++ = TO_BE_16(init[channel]); +Audio::AudioStream *VMDDecoder::create16bitDPCM(Common::SeekableReadStream *stream) { +	return new DPCMStream(stream, _soundFreq, (_soundStereo == 0) ? 1 : 2); +} -		channel = (channel + 1) % channels; +class VMD_ADPCMStream : public Audio::DVI_ADPCMStream { +public: +	VMD_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, +			int rate, int channels) : Audio::DVI_ADPCMStream(stream, disposeAfterUse, stream->size(), rate, channels, 0) { +		// FIXME: Using the same predictor/index for two channels probably won't work +		// properly However, we have no samples of this, so an assert is here for now. +		// Also, since the DPCM stereo has a second predictor, I'm lead to believe +		// all VMD with ADPCM are mono unless they changed the code in a later +		// revision. +		assert(channels == 1); +		_startPredictorValue = stream->readSint16LE(); +		_startIndexValue = stream->readByte(); +		_startpos = 3; +		reset();  	} -	while (inSize-- > 0) { -		if (*data & 0x80) -			init[channel] -= _tableDPCM[*data++ & 0x7F]; -		else -			init[channel] += _tableDPCM[*data++]; - -		init[channel] = CLIP<int32>(init[channel], -32768, 32767); -		*out++        = TO_BE_16(init[channel]); - -		channel = (channel + 1) % channels; +protected: +	virtual void reset() { +		Audio::DVI_ADPCMStream::reset(); +		_status.ima_ch[0].last = _startPredictorValue; +		_status.ima_ch[0].stepIndex = _startIndexValue;  	} -	size = outSize * 2; -	return sound; -} - -// Yet another IMA ADPCM variant -byte *VMDDecoder::deADPCM(const byte *data, uint32 &size, int32 init, int32 index) { -	if (!data || (size == 0)) -		return 0; - -	uint32 outSize = size * 2; - -	int16 *out   = (int16 *)malloc(outSize * 2); -	byte  *sound = (byte *) out; - -	index = CLIP<int32>(index, 0, 88); - -	int32 predictor = Audio::Ima_ADPCMStream::_imaTable[index]; - -	uint32 dataByte = 0; -	bool newByte = true; - -	size *= 2; -	while (size -- > 0) { -		byte code = 0; - -		if (newByte) { -			dataByte = *data++; -			code = (dataByte >> 4) & 0xF; -		} else -			code = dataByte & 0xF; - -		newByte = !newByte; - -		index += Audio::ADPCMStream::_stepAdjustTable[code]; -		index  = CLIP<int32>(index, 0, 88); - -		int32 value = predictor / 8; - -		if (code & 4) -			value += predictor; -		if (code & 2) -			value += predictor / 2; -		if (code & 1) -			value += predictor / 4; - -		if (code & 8) -			init -= value; -		else -			init += value; - -		init = CLIP<int32>(init, -32768, 32767); - -		predictor = Audio::Ima_ADPCMStream::_imaTable[index]; - -		*out++ = TO_BE_16(init); -	} +private: +	int32 _startPredictorValue; +	int32 _startIndexValue; +}; -	size = outSize * 2; -	return sound; +Audio::AudioStream *VMDDecoder::create16bitADPCM(Common::SeekableReadStream *stream) { +	return new VMD_ADPCMStream(stream, DisposeAfterUse::YES, _soundFreq, (_soundStereo == 0) ? 1 : 2);  }  Graphics::PixelFormat VMDDecoder::getPixelFormat() const { diff --git a/video/coktel_decoder.h b/video/coktel_decoder.h index 8ad1456037..b99a44f332 100644 --- a/video/coktel_decoder.h +++ b/video/coktel_decoder.h @@ -437,9 +437,6 @@ private:  		~Frame();  	}; -	// Tables for the audio decompressors -	static const uint16 _tableDPCM[128]; -  	Common::SeekableReadStream *_stream;  	byte   _version; @@ -508,15 +505,10 @@ private:  	uint8 evaluateMask(uint32 mask, bool *fillInfo, uint8 &max); -	// Generating sound slices -	byte *soundEmpty     (uint32 &size); -	byte *sound8bitRaw   (uint32 &size); -	byte *sound16bitDPCM (uint32 &size); -	byte *sound16bitADPCM(uint32 &size); - -	// Sound decompression -	byte *deDPCM (const byte *data, uint32 &size, int32 init[2]); -	byte *deADPCM(const byte *data, uint32 &size, int32 init, int32 index); +	// Generating audio streams +	Audio::AudioStream *create8bitRaw   (Common::SeekableReadStream *stream); +	Audio::AudioStream *create16bitDPCM (Common::SeekableReadStream *stream); +	Audio::AudioStream *create16bitADPCM(Common::SeekableReadStream *stream);  	bool getPartCoords(int16 frame, PartType type, int16 &x, int16 &y, int16 &width, int16 &height);  }; | 
