[Scummvm-cvs-logs] SF.net SVN: scummvm: [22526] scummvm/trunk/sound

eriktorbjorn at users.sourceforge.net eriktorbjorn at users.sourceforge.net
Thu May 18 14:47:04 CEST 2006


Revision: 22526
Author:   eriktorbjorn
Date:     2006-05-18 14:46:07 -0700 (Thu, 18 May 2006)
ViewCVS:  http://svn.sourceforge.net/scummvm/?rev=22526&view=rev

Log Message:
-----------
Added player for the Kyra 3 VQA cutscenes, based on my earlier prototype. It
could use some cleanup, and there are a couple of TODOs sprinkled throughout
the code, but it seems to work reasonably well. Until the Kyra 3 main menu is
implemented, it won't actually be used though.

It uses the appendable audio stream class, which I have moved out of the SCUMM
engine.

Modified Paths:
--------------
    scummvm/trunk/engines/kyra/kyra.h
    scummvm/trunk/engines/kyra/kyra3.cpp
    scummvm/trunk/engines/kyra/module.mk
    scummvm/trunk/engines/kyra/sound_digital.cpp
    scummvm/trunk/engines/kyra/wsamovie.h
    scummvm/trunk/engines/scumm/imuse_digi/dimuse.cpp
    scummvm/trunk/engines/scumm/imuse_digi/dimuse.h
    scummvm/trunk/engines/scumm/imuse_digi/dimuse_track.cpp
    scummvm/trunk/engines/scumm/smush/smush_mixer.cpp
    scummvm/trunk/engines/scumm/smush/smush_mixer.h
    scummvm/trunk/engines/scumm/smush/smush_player.cpp
    scummvm/trunk/engines/scumm/smush/smush_player.h
    scummvm/trunk/engines/scumm/sound.cpp
    scummvm/trunk/engines/scumm/sound.h
    scummvm/trunk/sound/audiostream.cpp
    scummvm/trunk/sound/audiostream.h

Added Paths:
-----------
    scummvm/trunk/engines/kyra/vqa.cpp
Modified: scummvm/trunk/engines/kyra/kyra.h
===================================================================
--- scummvm/trunk/engines/kyra/kyra.h	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/kyra/kyra.h	2006-05-18 21:46:07 UTC (rev 22526)
@@ -1023,6 +1023,8 @@
 	int setupGameFlags() { _game = GI_KYRA3; return 0; }
 	
 	int go();
+
+	void playVQA(const char *filename);
 private:
 	int init();
 

Modified: scummvm/trunk/engines/kyra/kyra3.cpp
===================================================================
--- scummvm/trunk/engines/kyra/kyra3.cpp	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/kyra/kyra3.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -109,4 +109,19 @@
 		_musicSoundChannel = _soundDigital->playSound(handle, true, -1);
 	}
 }
+
+void KyraEngine_v3::playVQA(const char *filename) {
+	VQAMovie vqa(this, _system);
+
+	// TODO: Save the palette
+
+	vqa.open(filename, 0, NULL);
+	if (vqa.opened()) {
+		vqa.play();
+		vqa.close();
+	}
+
+	// TODO: Restore the palette
 }
+
+} // end of namespace Kyra

Modified: scummvm/trunk/engines/kyra/module.mk
===================================================================
--- scummvm/trunk/engines/kyra/module.mk	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/kyra/module.mk	2006-05-18 21:46:07 UTC (rev 22526)
@@ -23,6 +23,7 @@
 	staticres.o \
 	text.o \
 	timer.o \
+	vqa.o \
 	wsamovie.o
 
 MODULE_DIRS += \

Modified: scummvm/trunk/engines/kyra/sound_digital.cpp
===================================================================
--- scummvm/trunk/engines/kyra/sound_digital.cpp	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/kyra/sound_digital.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -30,7 +30,7 @@
 // this code is based on
 
 // TODO: cleanup of whole AUDStream
-// FIXME: sound 'stutters' a bit, maybe a problem while converting int8 samples to int16?
+
 class AUDStream : public Audio::AudioStream {
 public:
 	AUDStream(Common::File *file, bool loop = false);

Added: scummvm/trunk/engines/kyra/vqa.cpp
===================================================================
--- scummvm/trunk/engines/kyra/vqa.cpp	                        (rev 0)
+++ scummvm/trunk/engines/kyra/vqa.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -0,0 +1,721 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Player for Kyrandia 3 VQA movies, based on the information found at
+// http://multimedia.cx/VQA_INFO.TXT
+//
+// The benchl.vqa movie (or whatever it is) is not supported. It does not have
+// a FINF chunk.
+//
+// The junk2.vqa movie does not work. The offset to the first frame is strange,
+// so we don't find the palette.
+
+#include "common/stdafx.h"
+#include "common/system.h"
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "kyra/sound.h"
+#include "kyra/wsamovie.h"
+
+namespace Kyra {
+
+VQAMovie::VQAMovie(KyraEngine *vm, OSystem *system) : Movie(vm) {
+	_system = system;
+}
+
+VQAMovie::~VQAMovie() {
+	if (_opened)
+		close();
+}
+
+void VQAMovie::initBuffers() {
+	for (int i = 0; i < ARRAYSIZE(_buffers); i++) {
+		_buffers[i].data = NULL;
+		_buffers[i].size = 0;
+	}
+}
+
+void *VQAMovie::allocBuffer(int num, uint32 size) {
+	assert(num >= 0 && num < ARRAYSIZE(_buffers));
+	assert(size > 0);
+
+	if (size > _buffers[num].size) {
+		/*
+		 * We could use realloc() here, but we don't actually need the
+		 * old contents of the buffer.
+		 */
+		free(_buffers[num].data);
+		_buffers[num].data = malloc(size);
+		_buffers[num].size = size;
+	}
+
+	assert(_buffers[num].data);
+
+	return _buffers[num].data;
+}
+
+void VQAMovie::freeBuffers() {
+	for (int i = 0; i < ARRAYSIZE(_buffers); i++) {
+		free(_buffers[i].data);
+		_buffers[i].data = NULL;
+		_buffers[i].size = 0;
+	}
+}
+
+uint32 VQAMovie::readTag() {
+	// Some tags have to be on an even offset, so they are padded with a
+	// zero byte. Skip that.
+
+	uint32 tag = _file.readUint32BE();
+
+	if (!(tag & 0xFF000000)) {
+		tag = (tag << 8) | _file.readByte();
+	}
+
+	return tag;
+}
+
+// Chunk types ending in a 'Z' are decoded using this function.
+
+int VQAMovie::decodeFormat80(byte *inbuf, byte *outbuf) {
+	byte *src = inbuf;
+	byte *dst = outbuf;
+
+	while (1) {
+		int relPos, pos;
+		int count;
+		byte color;
+		int i;
+
+		byte command = *src++;
+
+		switch (command) {
+		case 0x80:
+			return dst - outbuf;
+
+		case 0xFF:
+			/* 11111111 <count> <pos> */
+			count = src[0] | (src[1] << 8);
+			pos = src[2] | (src[3] << 8);
+			src += 4;
+			for (i = 0; i < count; i++)
+				dst[i] = outbuf[i + pos];
+			break;
+
+		case 0xFE:
+			/* 11111110 <count> <color> */
+			count = src[0] | (src[1] << 8);
+			color = src[2];
+			src += 3;
+			memset(dst, color, count);
+			break;
+
+		default:
+			if (command >= 0xC0) {
+				/* 11 <count - 3> <pos> */
+				count = (command & 0x3F) + 3;
+				pos = src[0] | (src[1] << 8);
+				src += 2;
+				for (i = 0; i < count; i++)
+					dst[i] = outbuf[pos + i];
+			} else if (command >= 0x80) {
+				/* 10 <count> */
+				count = command & 0x3F;
+				memcpy(dst, src, count);
+				src += count;
+			} else {
+				/* 0 <count - 3> <relative pos> */
+				count = ((command & 0x70) >> 4) + 3;
+				relPos = ((command & 0x0F) << 8) | src[0];
+				src++;
+				for (i = 0; i < count; i++)
+					dst[i] = dst[i - relPos];
+			}
+			break;
+		}
+
+		dst += count;
+	}
+}
+
+inline int16 clip8BitSample(int16 sample) {
+	if (sample > 255)
+		return 255;
+	if (sample < 0)
+		return 0;
+	return sample;
+}
+
+void VQAMovie::decodeSND1(byte *inbuf, uint32 insize, byte *outbuf, uint32 outsize) {
+	const int8 WSTable2Bit[] = { -2, -1, 0, 1 };
+	const int8 WSTable4Bit[] = {
+		-9, -8, -6, -5, -4, -3, -2, -1,
+		 0,  1,  2,  3,  4,  5,  6,  8
+	};
+
+	byte code;
+	int8 count;
+	uint16 input;
+
+	int16 curSample = 0x80;
+
+	while (outsize > 0) {
+		input = *inbuf++ << 2;
+		code = (input >> 8) & 0xff;
+		count = (input & 0xff) >> 2;
+
+		switch (code) {
+		case 2:
+			if (count & 0x20) {
+				/* NOTE: count is signed! */
+				count <<= 3;
+				curSample += (count >> 3);
+				*outbuf++ = curSample;
+				outsize--;
+			} else {
+				for (; count >= 0; count--) {
+					*outbuf++ = *inbuf++;
+					outsize--;
+				}
+				curSample = *(outbuf - 1);
+			}
+			break;
+		case 1:
+			for (; count >= 0; count--) {
+				code = *inbuf++;
+
+				curSample += WSTable4Bit[code & 0x0f];
+				curSample = clip8BitSample(curSample);
+				*outbuf++ = curSample;
+
+				curSample += WSTable4Bit[code >> 4];
+				curSample = clip8BitSample(curSample);
+				*outbuf++ = curSample;
+
+				outsize -= 2;
+			}
+			break;
+		case 0:
+			for (; count >= 0; count--) {
+				code = *inbuf++;
+
+				curSample += WSTable2Bit[code & 0x03];
+				curSample = clip8BitSample(curSample);
+				*outbuf++ = curSample;
+
+				curSample += WSTable2Bit[(code >> 2) & 0x03];
+				curSample = clip8BitSample(curSample);
+				*outbuf++ = curSample;
+
+				curSample += WSTable2Bit[(code >> 4) & 0x03];
+				curSample = clip8BitSample(curSample);
+				*outbuf++ = curSample;
+
+				curSample += WSTable2Bit[(code >> 6) & 0x03];
+				curSample = clip8BitSample(curSample);
+				*outbuf++ = curSample;
+
+				outsize -= 4;
+			}
+			break;
+		default:
+			for (; count >= 0; count--) {
+				*outbuf++ = curSample;
+				outsize--;
+			}
+		}
+	}
+}
+
+void VQAMovie::open(const char *filename, int dummy1, uint8 *dummy2) {
+	debugC(9, kDebugLevelMovie, "VQAMovie::open('%s')", filename);
+	close();
+
+	if (!_file.open(filename))
+		return;
+
+	if (_file.readUint32BE() != MKID_BE('FORM')) {
+		warning("VQAMovie::open: Cannot find `FORM' tag");
+		return;
+	}
+
+	// For now, we ignore the size of the FORM chunk.
+	_file.readUint32BE();
+
+	if (_file.readUint32BE() != MKID_BE('WVQA')) {
+		warning("WQAMovie::open: Cannot find `WVQA' tag");
+		return;
+	}
+
+	bool foundHeader = false;
+	bool foundFrameInfo = false;
+
+	// The information we need is stored in two chunks: VQHD and FINF. We
+	// need both of them before we can begin decoding the movie.
+
+	while (!foundHeader || !foundFrameInfo) {
+		uint32 tag = readTag();
+		uint32 size = _file.readUint32BE();
+
+		switch (tag) {
+		case MKID_BE('VQHD'):	// VQA header
+			_header.version     = _file.readUint16LE();
+			_header.flags       = _file.readUint16LE();
+			_header.numFrames   = _file.readUint16LE();
+			_header.width       = _file.readUint16LE();
+			_header.height      = _file.readUint16LE();
+			_header.blockW      = _file.readByte();
+			_header.blockH      = _file.readByte();
+			_header.frameRate   = _file.readByte();
+			_header.cbParts     = _file.readByte();
+			_header.colors      = _file.readUint16LE();
+			_header.maxBlocks   = _file.readUint16LE();
+			_header.unk1        = _file.readUint32LE();
+			_header.unk2        = _file.readUint16LE();
+			_header.freq        = _file.readUint16LE();
+			_header.channels    = _file.readByte();
+			_header.bits        = _file.readByte();
+			_header.unk3        = _file.readUint32LE();
+			_header.unk4        = _file.readUint16LE();
+			_header.maxCBFZSize = _file.readUint32LE();
+			_header.unk5        = _file.readUint32LE();
+
+			// Version 1 VQA files have some implicit defaults
+
+			if (_header.version == 1) {
+				if (_header.flags & 1) {
+					if (_header.freq == 0)
+						_header.freq = 22050;
+					if (_header.channels == 0)
+						_header.channels = 1;
+					if (_header.bits == 0)
+						_header.bits = 8;
+				}
+			}
+
+			setX((320 - _header.width) / 2);
+			setY((200 - _header.height) / 2);
+
+			// HACK: I've only seen 8-bit mono audio in Kyra 3
+
+			assert(_header.bits == 8);
+			assert(_header.channels == 1);
+
+			_frameInfo = new uint32[_header.numFrames];
+			_frame = new byte[_header.width * _header.height];
+
+			size = 0xf00 * _header.blockW * _header.blockH;
+			_codeBook = new byte[size];
+			_partialCodeBook = new byte[size];
+			memset(_codeBook, 0, size);
+			memset(_partialCodeBook, 0, size);
+
+			_numVectorPointers = (_header.width / _header.blockW) * (_header.height * _header.blockH);
+			_vectorPointers = new uint16[_numVectorPointers];
+			memset(_vectorPointers, 0, _numVectorPointers * sizeof(uint16));
+
+			_partialCodeBookSize = 0;
+			_numPartialCodeBooks = 0;
+
+			if (_header.flags & 1) {
+				// A 2-second buffer ought to be enough
+				_stream = Audio::makeAppendableAudioStream(_header.freq, Audio::Mixer::FLAG_UNSIGNED, 2 * _header.freq * _header.channels);
+				_sound = new Audio::SoundHandle;
+			} else {
+				_sound = NULL;
+				_stream = NULL;
+			}
+
+			foundHeader = true;
+			break;
+
+		case MKID_BE('FINF'):	// Frame info
+			if (!foundHeader) {
+				warning("VQAMovie::open: Found `FINF' before `VQHD'");
+				return;
+			}
+
+			if (size != 4 * (uint32)_header.numFrames) {
+				warning("VQAMovie::open: Expected size %d for `FINF' chunk, but got %d", 4 * _header.numFrames, size);
+				return;
+			}
+
+			foundFrameInfo = true;
+
+			for (int i = 0; i < _header.numFrames; i++) {
+				_frameInfo[i] = 2 * _file.readUint32LE();
+			}
+			break;
+
+		default:
+			warning("VQAMovie::open: Unknown tag `%c%c%c%c'", (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xFF, tag & 0xFF);
+			_file.seek(size, SEEK_CUR);
+			break;
+		}
+	}
+
+	initBuffers();
+
+	_opened = true;
+}
+
+void VQAMovie::close() {
+	debugC(9, kDebugLevelMovie, "VQAMovie::close()");
+	if (_opened) {
+		delete [] _frameInfo;
+		delete [] _frame;
+		delete [] _codeBook;
+		delete [] _partialCodeBook;
+		delete [] _vectorPointers;
+
+		if (_sound) {
+			_vm->_mixer->stopHandle(*_sound);
+			delete _sound;
+			_stream = NULL;
+			_sound = NULL;
+		}
+
+		_frameInfo = NULL;
+		_frame = NULL;
+		_codeBook = NULL;
+		_partialCodeBook = NULL;
+		_vectorPointers = NULL;
+		_stream = NULL;
+
+		if (_file.isOpen())
+			_file.close();
+
+		freeBuffers();
+
+		_opened = false;
+	}
+}
+
+void VQAMovie::displayFrame(int frameNum) {
+	debugC(9, kDebugLevelMovie, "VQAMovie::displayFrame(%d)", frameNum);
+	if (frameNum >= _header.numFrames || !_opened)
+		return;
+
+	bool foundSound = _stream ? false : true;
+	bool foundFrame = false;
+	uint i;
+
+	_file.seek(_frameInfo[frameNum] & 0x7FFFFFFF);
+
+	while (!foundSound || !foundFrame) {
+		uint32 tag = readTag();
+		uint32 size = _file.readUint32BE();
+
+		if (_file.eof()) {
+			// This happens at the last frame. Apparently it has
+			// no sound?
+			break;
+		}
+
+		byte *inbuf, *outbuf;
+		uint32 insize, outsize;
+		byte *pal;
+		uint32 end;
+
+		switch (tag) {
+		case MKID_BE('SND0'):	// Uncompressed sound
+			foundSound = true;
+			inbuf = (byte *)allocBuffer(0, size);
+			_file.read(inbuf, size);
+			_stream->append(inbuf, size);
+			break;
+
+		case MKID_BE('SND1'):	// Compressed sound, almost like AUD
+			foundSound = true;
+			outsize = _file.readUint16LE();
+			insize = _file.readUint16LE();
+
+			inbuf = (byte *)allocBuffer(0, insize);
+			_file.read(inbuf, insize);
+
+			if (insize == outsize) {
+				_stream->append(inbuf, insize);
+			} else {
+				outbuf = (byte *)allocBuffer(1, outsize);
+				decodeSND1(inbuf, insize, outbuf, outsize);
+				_stream->append(outbuf, outsize);
+			}
+			break;
+
+		case MKID_BE('SND2'):	// Compressed sound
+			foundSound = true;
+			warning("VQAMovie::displayFrame: `SND2' is not implemented");
+			_file.seek(size, SEEK_CUR);
+			break;
+
+		case MKID_BE('VQFR'):
+			foundFrame = true;
+			end = _file.pos() + size - 8;
+
+			while (_file.pos() < end) {
+				tag = readTag();
+				size = _file.readUint32BE();
+
+				switch (tag) {
+				case MKID_BE('CBF0'):	// Full codebook
+					_file.read(_codeBook, size);
+					break;
+
+				case MKID_BE('CBFZ'):	// Full codebook
+					inbuf = (byte *)allocBuffer(0, size);
+					_file.read(inbuf, size);
+					decodeFormat80(inbuf, _codeBook);
+					break;
+
+				case MKID_BE('CBP0'):	// Partial codebook
+					_compressedCodeBook = false;
+					_file.read(_partialCodeBook + _partialCodeBookSize, size);
+					_partialCodeBookSize += size;
+					_numPartialCodeBooks++;
+					break;
+
+				case MKID_BE('CBPZ'):	// Partial codebook
+					_compressedCodeBook = true;
+					_file.read(_partialCodeBook + _partialCodeBookSize, size);
+					_partialCodeBookSize += size;
+					_numPartialCodeBooks++;
+					break;
+
+				case MKID_BE('CPL0'):	// Palette
+					assert(size <= 3 * 256);
+
+					inbuf = (byte *)allocBuffer(0, size);
+					pal = _palette;
+					_file.read(inbuf, size);
+
+					for (i = 0; i < size / 3; i++) {
+						*pal++ = 4 * (0x3F & *inbuf++);
+						*pal++ = 4 * (0x3F & *inbuf++);
+						*pal++ = 4 * (0x3F & *inbuf++);
+						*pal++ = 0;
+					}
+
+					break;
+
+				case MKID_BE('CPLZ'):	// Palette
+					inbuf = (byte *)allocBuffer(0, size);
+					outbuf = (byte *)allocBuffer(1, 3 * 256);
+					pal = _palette;
+					_file.read(inbuf, size);
+					size = decodeFormat80(inbuf, outbuf);
+
+					for (i = 0; i < size / 3; i++) {
+						*pal++ = 4 * (0x3F & *outbuf++);
+						*pal++ = 4 * (0x3F & *outbuf++);
+						*pal++ = 4 * (0x3F & *outbuf++);
+						*pal++ = 0;
+					}
+
+					break;
+
+				case MKID_BE('VPT0'):	// Frame data
+					assert(size / 2 <= _numVectorPointers);
+
+					for (i = 0; i < size / 2; i++)
+						_vectorPointers[i] = _file.readUint16LE();
+					break;
+
+				case MKID_BE('VPTZ'):	// Frame data
+					inbuf = (byte *)allocBuffer(0, size);
+					outbuf = (byte *)allocBuffer(1, 2 * _numVectorPointers);
+
+					_file.read(inbuf, size);
+					size = decodeFormat80(inbuf, outbuf);
+
+					assert(size / 2 <= _numVectorPointers);
+
+					for (i = 0; i < size / 2; i++)
+						_vectorPointers[i] = READ_LE_UINT16(outbuf + 2 * i);
+					break;
+
+				default:
+					warning("VQAMovie::displayFrame: Unknown `VQFR' sub-tag `%c%c%c%c'", (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xFF, tag & 0xFF);
+					_file.seek(size, SEEK_CUR);
+					break;
+				}
+
+			}
+
+			break;
+
+		default:
+			warning("VQAMovie::displayFrame: Unknown tag `%c%c%c%c'", (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xFF, tag & 0xFF);
+			_file.seek(size, SEEK_CUR);
+			break;
+		}
+	}
+
+	// The frame has been decoded
+
+	if (_frameInfo[frameNum] & 0x80000000) {
+		_system->setPalette(_palette, 0, 256);
+	}
+
+	int blockPitch = _header.width / _header.blockW;
+
+	for (int by = 0; by < _header.height / _header.blockH; by++) {
+		for (int bx = 0; bx < blockPitch; bx++) {
+			byte *dst = _frame + by * _header.width * _header.blockH + bx * _header.blockW;
+			int val = _vectorPointers[by * blockPitch + bx];
+
+			if ((val & 0xFF00) == 0xFF00) {
+				// Solid color
+				for (i = 0; i < _header.blockH; i++) {
+					memset(dst, 255 - (val & 0xFF), _header.blockW);
+					dst += _header.width;
+				}
+			} else {
+				// Copy data from _vectorPointers. I'm not sure
+				// why we don't use the three least significant
+				// bits of 'val'.
+				byte *src = &_codeBook[(val >> 3) * _header.blockW * _header.blockH];
+
+				for (i = 0; i < _header.blockH; i++) {
+					memcpy(dst, src, _header.blockW);
+					src += _header.blockW;
+					dst += _header.width;
+				}
+			}
+		}
+	}
+
+	if (_numPartialCodeBooks == _header.cbParts) {
+		if (_compressedCodeBook) {
+			decodeFormat80(_partialCodeBook, _codeBook);
+		} else {
+			memcpy(_codeBook, _partialCodeBook, _partialCodeBookSize);
+		}
+		_numPartialCodeBooks = 0;
+		_partialCodeBookSize = 0;
+	}
+
+	_system->copyRectToScreen(_frame, _header.width, _x, _y, _header.width, _header.height);
+}
+
+void VQAMovie::play() {
+	uint32 startTick;
+
+	if (!_opened)
+		return;
+
+	startTick = _system->getMillis();
+
+	// First, handle any sound chunk that apears before the first frame.
+	// At least in some versions, it will contain half a second of audio,
+	// presumably to lessen the risk of audio underflow.
+	//
+	// In most movies, we will find a CMDS tag. The purpose of this is
+	// currently unknown.
+	//
+	// In cow1_0.vqa, cow1_1.vqa, jung0.vqa, and jung1.vqa we will find a
+	// VQFR tag. A frame before the first frame? Weird. It doesn't seem to
+	// be needed, though.
+
+	byte *inbuf, *outbuf;
+	uint32 insize, outsize;
+
+	if (_stream) {
+		while (_file.pos() < (_frameInfo[0] & 0x7FFFFFFF)) {
+			uint32 tag = readTag();
+			uint32 size = _file.readUint32BE();
+
+			if (_file.eof()) {
+				warning("VQAMovie::play: Unexpected EOF");
+				break;
+			}
+
+			switch (tag) {
+			case MKID_BE('SND0'):	// Uncompressed sound
+				inbuf = (byte *)allocBuffer(0, size);
+				_file.read(inbuf, size);
+				_stream->append(inbuf, size);
+				break;
+
+			case MKID_BE('SND1'):	// Compressed sound
+				outsize = _file.readUint16LE();
+				insize = _file.readUint16LE();
+
+				inbuf = (byte *)allocBuffer(0, insize);
+				_file.read(inbuf, insize);
+
+				if (insize == outsize) {
+					_stream->append(inbuf, insize);
+				} else {
+					outbuf = (byte *)allocBuffer(1, outsize);
+					decodeSND1(inbuf, insize, outbuf, outsize);
+					_stream->append(outbuf, outsize);
+				}
+				break;
+
+			case MKID_BE('SND2'):	// Compressed sound
+				warning("VQAMovie::play: `SND2' is not implemented");
+				_file.seek(size, SEEK_CUR);
+				break;
+
+			default:
+				warning("VQAMovie::play: Unknown tag `%c%c%c%c'", (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xFF, tag & 0xFF);
+				_file.seek(size, SEEK_CUR);
+				break;
+			}
+		}
+	}
+
+	_vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, _sound, _stream);
+
+	for (int i = 0; i < _header.numFrames; i++) {
+		displayFrame(i);
+
+		// TODO: We ought to sync this to how much sound we've played.
+		// TODO: Implement frame skipping?
+
+		while (_system->getMillis() < startTick + (i * 1000) / _header.frameRate) {
+			OSystem::Event event;
+
+			while (_system->pollEvent(event)) {
+				switch (event.type) {
+				case OSystem::EVENT_KEYDOWN:
+					if (event.kbd.ascii == 27)
+						return;
+					break;
+				case OSystem::EVENT_QUIT:
+					_vm->quitGame();
+					break;
+				default:
+					break;
+				}
+			}
+
+			_system->delayMillis(10);
+		}
+
+		_system->updateScreen();
+	}
+
+	// TODO: Wait for the sound to finish?
+}
+
+} // end of namespace Kyra


Property changes on: scummvm/trunk/engines/kyra/vqa.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Modified: scummvm/trunk/engines/kyra/wsamovie.h
===================================================================
--- scummvm/trunk/engines/kyra/wsamovie.h	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/kyra/wsamovie.h	2006-05-18 21:46:07 UTC (rev 22526)
@@ -25,6 +25,11 @@
 
 #include "kyra/resource.h"
 
+namespace Audio {
+class AppendableAudioStream;
+class SoundHandle;
+} // end of namespace Audio
+
 namespace Kyra {
 class KyraEngine;
 
@@ -103,6 +108,83 @@
 	int16 _yAdd;
 };
 
+// Kyra 3 VQA movies. Should perhaps be in another header file.
+
+class VQAMovie : public Movie {
+public:
+	VQAMovie(KyraEngine *vm, OSystem *system);
+	~VQAMovie();
+
+	int frames() { return _opened ? _header.numFrames : -1; }
+
+	void displayFrame(int frameNum);
+
+	// Only the first parameter is used.
+	virtual void open(const char *filename, int offscreen, uint8 *palette);
+	void close();
+	void play();
+
+protected:
+	OSystem *_system;
+
+	struct VQAHeader {
+		uint16 version;
+		uint16 flags;
+		uint16 numFrames;
+		uint16 width;
+		uint16 height;
+		uint8 blockW;
+		uint8 blockH;
+		uint8 frameRate;
+		uint8 cbParts;
+		uint16 colors;
+		uint16 maxBlocks;
+		uint32 unk1;
+		uint16 unk2;
+		uint16 freq;
+		uint8 channels;
+		uint8 bits;
+		uint32 unk3;
+		uint16 unk4;
+		uint32 maxCBFZSize;
+		uint32 unk5;
+	};
+
+	struct Buffer {
+		void *data;
+		uint32 size;
+	};
+
+	Buffer _buffers[2];
+
+	void initBuffers();
+	void *allocBuffer(int num, uint32 size);
+	void freeBuffers();
+
+	int decodeFormat80(byte *inbuf, byte *outbuf);
+	void decodeSND1(byte *inbuf, uint32 insize, byte *outbuf, uint32 outsize);
+
+	Common::File _file;
+
+	VQAHeader _header;
+	uint32 *_frameInfo;
+	byte *_codeBook;
+	byte *_partialCodeBook;
+	bool _compressedCodeBook;
+	int _partialCodeBookSize;
+	int _numPartialCodeBooks;
+	uint32 _numVectorPointers;
+	uint16 *_vectorPointers;
+
+	byte _palette[4 * 256];
+	byte *_frame;
+
+	Audio::AppendableAudioStream *_stream;
+	Audio::SoundHandle *_sound;
+
+	uint32 readTag();
+};
+
 } // end of namespace Kyra
 
 #endif

Modified: scummvm/trunk/engines/scumm/imuse_digi/dimuse.cpp
===================================================================
--- scummvm/trunk/engines/scumm/imuse_digi/dimuse.cpp	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/imuse_digi/dimuse.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -187,7 +187,7 @@
 
 			int32 streamBufferSize = track->iteration;
 			track->stream2 = NULL;
-			track->stream = makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize);
+			track->stream = Audio::makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize);
 
 			const int pan = (track->pan != 64) ? 2 * track->pan - 127 : 0;
 			const int vol = track->vol / 1000;

Modified: scummvm/trunk/engines/scumm/imuse_digi/dimuse.h
===================================================================
--- scummvm/trunk/engines/scumm/imuse_digi/dimuse.h	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/imuse_digi/dimuse.h	2006-05-18 21:46:07 UTC (rev 22526)
@@ -79,7 +79,7 @@
 
 		ImuseDigiSndMgr::soundStruct *soundHandle;
 		Audio::SoundHandle handle;
-		AppendableAudioStream *stream;
+		Audio::AppendableAudioStream *stream;
 		Audio::AudioStream *stream2;
 
 		Track();

Modified: scummvm/trunk/engines/scumm/imuse_digi/dimuse_track.cpp
===================================================================
--- scummvm/trunk/engines/scumm/imuse_digi/dimuse_track.cpp	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/imuse_digi/dimuse_track.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -178,7 +178,7 @@
 		// setup 1 second stream wrapped buffer
 		int32 streamBufferSize = track->iteration;
 		track->stream2 = NULL;
-		track->stream = makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize);
+		track->stream = Audio::makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize);
 		_vm->_mixer->playInputStream(type, &track->handle, track->stream, -1, vol, pan, false);
 		track->started = true;
 	}
@@ -357,7 +357,7 @@
 
 	// setup 1 second stream wrapped buffer
 	int32 streamBufferSize = fadeTrack->iteration;
-	fadeTrack->stream = makeAppendableAudioStream(_sound->getFreq(fadeTrack->soundHandle), fadeTrack->mixerFlags, streamBufferSize);
+	fadeTrack->stream = Audio::makeAppendableAudioStream(_sound->getFreq(fadeTrack->soundHandle), fadeTrack->mixerFlags, streamBufferSize);
 	_vm->_mixer->playInputStream(type, &fadeTrack->handle, fadeTrack->stream, -1, fadeTrack->vol / 1000, fadeTrack->pan, false);
 	fadeTrack->started = true;
 	fadeTrack->used = true;

Modified: scummvm/trunk/engines/scumm/smush/smush_mixer.cpp
===================================================================
--- scummvm/trunk/engines/scumm/smush/smush_mixer.cpp	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/smush/smush_mixer.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -129,7 +129,7 @@
 
 				if (_mixer->isReady()) {
 					if (!_channels[i].stream) {
-						_channels[i].stream = makeAppendableAudioStream(rate, flags, 500000);
+						_channels[i].stream = Audio::makeAppendableAudioStream(rate, flags, 500000);
 						_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_channels[i].handle, _channels[i].stream);
 					}
 					_mixer->setChannelVolume(_channels[i].handle, vol);

Modified: scummvm/trunk/engines/scumm/smush/smush_mixer.h
===================================================================
--- scummvm/trunk/engines/scumm/smush/smush_mixer.h	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/smush/smush_mixer.h	2006-05-18 21:46:07 UTC (rev 22526)
@@ -41,7 +41,7 @@
 		int id;
 		SmushChannel *chan;
 		Audio::SoundHandle handle;
-		AppendableAudioStream *stream;
+		Audio::AppendableAudioStream *stream;
 	} _channels[NUM_CHANNELS];
 
 	int _soundFrequency;

Modified: scummvm/trunk/engines/scumm/smush/smush_player.cpp
===================================================================
--- scummvm/trunk/engines/scumm/smush/smush_player.cpp	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/smush/smush_player.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -522,7 +522,7 @@
 					} while (--count);
 
 					if (!_IACTstream) {
-						_IACTstream = makeAppendableAudioStream(22050, Audio::Mixer::FLAG_STEREO | Audio::Mixer::FLAG_16BITS, 400000);
+						_IACTstream = Audio::makeAppendableAudioStream(22050, Audio::Mixer::FLAG_STEREO | Audio::Mixer::FLAG_16BITS, 400000);
 						_vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_IACTchannel, _IACTstream);
 					}
 					_IACTstream->append(output_data, 0x1000);

Modified: scummvm/trunk/engines/scumm/smush/smush_player.h
===================================================================
--- scummvm/trunk/engines/scumm/smush/smush_player.h	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/smush/smush_player.h	2006-05-18 21:46:07 UTC (rev 22526)
@@ -62,7 +62,7 @@
 	int32 _frame;
 
 	Audio::SoundHandle _IACTchannel;
-	AppendableAudioStream *_IACTstream;
+	Audio::AppendableAudioStream *_IACTstream;
 
 	Audio::SoundHandle _compressedFileSoundHandle;
 	bool _compressedFileMode;

Modified: scummvm/trunk/engines/scumm/sound.cpp
===================================================================
--- scummvm/trunk/engines/scumm/sound.cpp	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/sound.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -2109,147 +2109,4 @@
 }
 
 
-#pragma mark -
-#pragma mark --- Appendable audio stream ---
-#pragma mark -
-
-
-/**
- * Wrapped memory stream.
- */
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-class AppendableMemoryStream : public AppendableAudioStream {
-protected:
-	Common::Mutex _mutex;
-
-	byte *_bufferStart;
-	byte *_bufferEnd;
-	byte *_pos;
-	byte *_end;
-	bool _finalized;
-	const int _rate;
-
-	inline bool eosIntern() const { return _end == _pos; };
-public:
-	AppendableMemoryStream(int rate, uint bufferSize);
-	~AppendableMemoryStream();
-	int readBuffer(int16 *buffer, const int numSamples);
-
-	bool isStereo() const		{ return stereo; }
-	bool endOfStream() const	{ return _finalized && eosIntern(); }
-	bool endOfData() const		{ return eosIntern(); }
-
-	int getRate() const			{ return _rate; }
-
-	void append(const byte *data, uint32 len);
-	void finish()				{ _finalized = true; }
-};
-
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::AppendableMemoryStream(int rate, uint bufferSize)
- : _finalized(false), _rate(rate) {
-
-	// Verify the buffer size is sane
-	if (is16Bit && stereo)
-		assert((bufferSize & 3) == 0);
-	else if (is16Bit || stereo)
-		assert((bufferSize & 1) == 0);
-
-	_bufferStart = (byte *)malloc(bufferSize);
-	_pos = _end = _bufferStart;
-	_bufferEnd = _bufferStart + bufferSize;
-}
-
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::~AppendableMemoryStream() {
-	free(_bufferStart);
-}
-
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
-	Common::StackLock lock(_mutex);
-
-	int samples = 0;
-	while (samples < numSamples && !eosIntern()) {
-		// Wrap around?
-		if (_pos >= _bufferEnd)
-			_pos = _pos - (_bufferEnd - _bufferStart);
-
-		const byte *endMarker = (_pos > _end) ? _bufferEnd : _end;
-		const int len = MIN(numSamples, samples + (int)(endMarker - _pos) / (is16Bit ? 2 : 1));
-		while (samples < len) {
-			*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _pos, isLE);
-			_pos += (is16Bit ? 2 : 1);
-			samples++;
-		}
-	}
-
-	return samples;
-}
-
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-void AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::append(const byte *data, uint32 len) {
-	Common::StackLock lock(_mutex);
-
-	// Verify the buffer size is sane
-	if (is16Bit && stereo)
-		assert((len & 3) == 0);
-	else if (is16Bit || stereo)
-		assert((len & 1) == 0);
-
-	// Verify that the stream has not yet been finalized (by a call to finish())
-	assert(!_finalized);
-
-	if (_end + len > _bufferEnd) {
-		// Wrap-around case
-		uint32 size_to_end_of_buffer = _bufferEnd - _end;
-		len -= size_to_end_of_buffer;
-		if ((_end < _pos) || (_bufferStart + len >= _pos)) {
-			debug(2, "AppendableMemoryStream: buffer overflow (A)");
-			return;
-		}
-		memcpy(_end, data, size_to_end_of_buffer);
-		memcpy(_bufferStart, data + size_to_end_of_buffer, len);
-		_end = _bufferStart + len;
-	} else {
-		if ((_end < _pos) && (_end + len >= _pos)) {
-			debug(2, "AppendableMemoryStream: buffer overflow (B)");
-			return;
-		}
-		memcpy(_end, data, len);
-		_end += len;
-	}
-}
-
-
-#define MAKE_WRAPPED(STEREO, UNSIGNED) \
-		if (is16Bit) { \
-			if (isLE) \
-				return new AppendableMemoryStream<STEREO, true, UNSIGNED, true>(rate, len); \
-			else  \
-				return new AppendableMemoryStream<STEREO, true, UNSIGNED, false>(rate, len); \
-		} else \
-			return new AppendableMemoryStream<STEREO, false, UNSIGNED, false>(rate, len)
-
-AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len) {
-	const bool isStereo = (_flags & Audio::Mixer::FLAG_STEREO) != 0;
-	const bool is16Bit = (_flags & Audio::Mixer::FLAG_16BITS) != 0;
-	const bool isUnsigned = (_flags & Audio::Mixer::FLAG_UNSIGNED) != 0;
-	const bool isLE       = (_flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0;
-
-	if (isStereo) {
-		if (isUnsigned) {
-			MAKE_WRAPPED(true, true);
-		} else {
-			MAKE_WRAPPED(true, false);
-		}
-	} else {
-		if (isUnsigned) {
-			MAKE_WRAPPED(false, true);
-		} else {
-			MAKE_WRAPPED(false, false);
-		}
-	}
-}
-
 } // End of namespace Scumm

Modified: scummvm/trunk/engines/scumm/sound.h
===================================================================
--- scummvm/trunk/engines/scumm/sound.h	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/engines/scumm/sound.h	2006-05-18 21:46:07 UTC (rev 22526)
@@ -132,19 +132,7 @@
 	virtual void processSoundQueues();
 };
 
-/**
- * An audio stream to which additional data can be appended on-the-fly.
- * Used by SMUSH and iMuseDigital.
- */
-class AppendableAudioStream : public Audio::AudioStream {
-public:
-	virtual void append(const byte *data, uint32 len) = 0;
-	virtual void finish() = 0;
-};
 
-AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len);
-
-
 } // End of namespace Scumm
 
 #endif

Modified: scummvm/trunk/sound/audiostream.cpp
===================================================================
--- scummvm/trunk/sound/audiostream.cpp	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/sound/audiostream.cpp	2006-05-18 21:46:07 UTC (rev 22526)
@@ -214,4 +214,148 @@
 }
 
 
+#pragma mark -
+#pragma mark --- Appendable audio stream ---
+#pragma mark -
+
+
+/**
+ * Wrapped memory stream.
+ */
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+class AppendableMemoryStream : public AppendableAudioStream {
+protected:
+	Common::Mutex _mutex;
+
+	byte *_bufferStart;
+	byte *_bufferEnd;
+	byte *_pos;
+	byte *_end;
+	bool _finalized;
+	const int _rate;
+
+	inline bool eosIntern() const { return _end == _pos; };
+public:
+	AppendableMemoryStream(int rate, uint bufferSize);
+	~AppendableMemoryStream();
+	int readBuffer(int16 *buffer, const int numSamples);
+
+	bool isStereo() const		{ return stereo; }
+	bool endOfStream() const	{ return _finalized && eosIntern(); }
+	bool endOfData() const		{ return eosIntern(); }
+
+	int getRate() const			{ return _rate; }
+
+	void append(const byte *data, uint32 len);
+	void finish()				{ _finalized = true; }
+};
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::AppendableMemoryStream(int rate, uint bufferSize)
+ : _finalized(false), _rate(rate) {
+
+	// Verify the buffer size is sane
+	if (is16Bit && stereo)
+		assert((bufferSize & 3) == 0);
+	else if (is16Bit || stereo)
+		assert((bufferSize & 1) == 0);
+
+	_bufferStart = (byte *)malloc(bufferSize);
+	_pos = _end = _bufferStart;
+	_bufferEnd = _bufferStart + bufferSize;
+}
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::~AppendableMemoryStream() {
+	free(_bufferStart);
+}
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
+	Common::StackLock lock(_mutex);
+
+	int samples = 0;
+	while (samples < numSamples && !eosIntern()) {
+		// Wrap around?
+		if (_pos >= _bufferEnd)
+			_pos = _pos - (_bufferEnd - _bufferStart);
+
+		const byte *endMarker = (_pos > _end) ? _bufferEnd : _end;
+		const int len = MIN(numSamples, samples + (int)(endMarker - _pos) / (is16Bit ? 2 : 1));
+		while (samples < len) {
+			*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _pos, isLE);
+			_pos += (is16Bit ? 2 : 1);
+			samples++;
+		}
+	}
+
+	return samples;
+}
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+void AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::append(const byte *data, uint32 len) {
+	Common::StackLock lock(_mutex);
+
+	// Verify the buffer size is sane
+	if (is16Bit && stereo)
+		assert((len & 3) == 0);
+	else if (is16Bit || stereo)
+		assert((len & 1) == 0);
+
+	// Verify that the stream has not yet been finalized (by a call to finish())
+	assert(!_finalized);
+
+	if (_end + len > _bufferEnd) {
+		// Wrap-around case
+		uint32 size_to_end_of_buffer = _bufferEnd - _end;
+		len -= size_to_end_of_buffer;
+		if ((_end < _pos) || (_bufferStart + len >= _pos)) {
+			debug(2, "AppendableMemoryStream: buffer overflow (A)");
+			return;
+		}
+		memcpy(_end, data, size_to_end_of_buffer);
+		memcpy(_bufferStart, data + size_to_end_of_buffer, len);
+		_end = _bufferStart + len;
+	} else {
+		if ((_end < _pos) && (_end + len >= _pos)) {
+			debug(2, "AppendableMemoryStream: buffer overflow (B)");
+			return;
+		}
+		memcpy(_end, data, len);
+		_end += len;
+	}
+}
+
+
+#define MAKE_WRAPPED(STEREO, UNSIGNED) \
+		if (is16Bit) { \
+			if (isLE) \
+				return new AppendableMemoryStream<STEREO, true, UNSIGNED, true>(rate, len); \
+			else  \
+				return new AppendableMemoryStream<STEREO, true, UNSIGNED, false>(rate, len); \
+		} else \
+			return new AppendableMemoryStream<STEREO, false, UNSIGNED, false>(rate, len)
+
+AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len) {
+	const bool isStereo = (_flags & Audio::Mixer::FLAG_STEREO) != 0;
+	const bool is16Bit = (_flags & Audio::Mixer::FLAG_16BITS) != 0;
+	const bool isUnsigned = (_flags & Audio::Mixer::FLAG_UNSIGNED) != 0;
+	const bool isLE       = (_flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0;
+
+	if (isStereo) {
+		if (isUnsigned) {
+			MAKE_WRAPPED(true, true);
+		} else {
+			MAKE_WRAPPED(true, false);
+		}
+	} else {
+		if (isUnsigned) {
+			MAKE_WRAPPED(false, true);
+		} else {
+			MAKE_WRAPPED(false, false);
+		}
+	}
+}
+
+
 } // End of namespace Audio

Modified: scummvm/trunk/sound/audiostream.h
===================================================================
--- scummvm/trunk/sound/audiostream.h	2006-05-18 20:53:28 UTC (rev 22525)
+++ scummvm/trunk/sound/audiostream.h	2006-05-18 21:46:07 UTC (rev 22526)
@@ -112,7 +112,19 @@
 
 AudioStream *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen);
 
+/**
+ * An audio stream to which additional data can be appended on-the-fly.
+ * Used by SMUSH, iMuseDigital, and the Kyrandia 3 VQA player.
+ */
+class AppendableAudioStream : public Audio::AudioStream {
+public:
+	virtual void append(const byte *data, uint32 len) = 0;
+	virtual void finish() = 0;
+};
 
+AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len);
+
+
 // This used to be an inline template function, but
 // buggy template function handling in MSVC6 forced
 // us to go with the macro approach. So far this is


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.





More information about the Scummvm-git-logs mailing list