[Scummvm-cvs-logs] scummvm master -> 6bbff583146843baade8f6268a2e1ea92be416ba

DrMcCoy drmccoy at drmccoy.de
Sun Nov 27 16:12:36 CET 2011


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
6bbff58314 VIDEO: Rewrite VMD audio streaming


Commit: 6bbff583146843baade8f6268a2e1ea92be416ba
    https://github.com/scummvm/scummvm/commit/6bbff583146843baade8f6268a2e1ea92be416ba
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-11-27T06:52:05-08:00

Commit Message:
VIDEO: Rewrite VMD audio streaming

Audio is now decoded in AudioStream classes instead of being decoded ahead of time and then queued.

Changed paths:
    audio/decoders/adpcm_intern.h
    video/coktel_decoder.cpp
    video/coktel_decoder.h



diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h
index f7162f5..31747aa 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 8ea2d08..ae0c35c 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 8ad1456..b99a44f 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);
 };






More information about the Scummvm-git-logs mailing list