[Scummvm-cvs-logs] CVS: scummex/sound audiostream.cpp,NONE,1.1 audiostream.h,NONE,1.1 mixer.cpp,NONE,1.1 mixer.h,NONE,1.1 module.mk,NONE,1.1 rate.cpp,NONE,1.1 rate.h,NONE,1.1 sound.cpp,NONE,1.1 sound.h,NONE,1.1 voc.cpp,NONE,1.1 voc.h,NONE,1.1

Adrien Mercier yoshizf at users.sourceforge.net
Sun Sep 28 15:08:02 CEST 2003


Update of /cvsroot/scummvm/scummex/sound
In directory sc8-pr-cvs1:/tmp/cvs-serv8413/sound

Added Files:
	audiostream.cpp audiostream.h mixer.cpp mixer.h module.mk 
	rate.cpp rate.h sound.cpp sound.h voc.cpp voc.h 
Log Message:
We're now using the mixer from ScummVM instead of SDL_mixer

--- NEW FILE: audiostream.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/audiostream.cpp,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

#include "stdafx.h"
#include "audiostream.h"
#include "mixer.h"
#include "file.h"

// 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
// the only template function that MSVC6 seemed to
// compile incorrectly. Knock on wood.
#define READSAMPLE(is16Bit, isUnsigned, ptr) \
	((is16Bit ? READ_BE_UINT16(ptr) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))

#pragma mark -
#pragma mark --- LinearMemoryStream ---
#pragma mark -


template<bool stereo, bool is16Bit, bool isUnsigned>
class LinearMemoryStream : public AudioInputStream {
protected:
	const byte *_ptr;
	const byte *_end;
	const byte *_loopPtr;
	const byte *_loopEnd;

	inline int16 readIntern() {
		//assert(_ptr < _end);
		int16 val = READSAMPLE(is16Bit, isUnsigned, _ptr);
		_ptr += (is16Bit ? 2 : 1);
		if (_loopPtr && _ptr == _end) {
			_ptr = _loopPtr;
			_end = _loopEnd;
		}
		return val;
	}
	inline bool eosIntern() const	{ return _ptr >= _end; };
public:
	LinearMemoryStream(const byte *ptr, uint len, uint loopOffset, uint loopLen)
		: _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0) {

		// Verify the buffer sizes are sane
		if (is16Bit && stereo)
			assert((len & 3) == 0 && (loopLen & 3) == 0);
		else if (is16Bit || stereo)
			assert((len & 1) == 0 && (loopLen & 1) == 0);

		if (loopLen) {
			_loopPtr = _ptr + loopOffset;
			_loopEnd = _loopPtr + loopLen;
		}
		if (stereo)	// Stereo requires even sized data
			assert(len % 2 == 0);
	}
	int readBuffer(int16 *buffer, const int numSamples);

	int16 read()				{ return readIntern(); }
	bool eos() const			{ return eosIntern(); }
	bool isStereo() const		{ return stereo; }
};

template<bool stereo, bool is16Bit, bool isUnsigned>
int LinearMemoryStream<stereo, is16Bit, isUnsigned>::readBuffer(int16 *buffer, const int numSamples) {
	int samples = 0;
	while (samples < numSamples && !eosIntern()) {
		const int len = MIN(numSamples, samples + (int)(_end - _ptr) / (is16Bit ? 2 : 1));
		while (samples < len) {
			*buffer++ = READSAMPLE(is16Bit, isUnsigned, _ptr);
			_ptr += (is16Bit ? 2 : 1);
			samples++;
		}
		// Loop, if looping was specified
		if (_loopPtr && eosIntern()) {
			_ptr = _loopPtr;
			_end = _loopEnd;
		}
	}
	return samples;
}


#pragma mark -
#pragma mark --- WrappedMemoryStream ---
#pragma mark -


// Wrapped memory stream, to be used by the ChannelStream class (and possibly others?)
template<bool stereo, bool is16Bit, bool isUnsigned>
class WrappedMemoryStream : public WrappedAudioInputStream {
protected:
	byte *_bufferStart;
	byte *_bufferEnd;
	byte *_pos;
	byte *_end;
	
	inline int16 readIntern();
	inline bool eosIntern() const { return _end == _pos; };
public:
	WrappedMemoryStream(uint bufferSize);
	~WrappedMemoryStream()		{ free(_bufferStart); }
	int readBuffer(int16 *buffer, const int numSamples);

	int16 read()				{ return readIntern(); }
	bool eos() const			{ return eosIntern(); }
	bool isStereo() const		{ return stereo; }

	void append(const byte *data, uint32 len);
};


template<bool stereo, bool is16Bit, bool isUnsigned>
WrappedMemoryStream<stereo, is16Bit, isUnsigned>::WrappedMemoryStream(uint bufferSize) {

	// 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>
inline int16 WrappedMemoryStream<stereo, is16Bit, isUnsigned>::readIntern() {
	//assert(_pos != _end);
	int16 val = READSAMPLE(is16Bit, isUnsigned, _pos);
	_pos += (is16Bit ? 2 : 1);

	// Wrap around?
	if (_pos >= _bufferEnd)
		_pos = _pos - (_bufferEnd - _bufferStart);

	return val;
}

template<bool stereo, bool is16Bit, bool isUnsigned>
int WrappedMemoryStream<stereo, is16Bit, isUnsigned>::readBuffer(int16 *buffer, const int numSamples) {
	int samples = 0;
	while (samples < numSamples && !eosIntern()) {
		const byte *endMarker = (_pos > _end) ? _bufferEnd : _end;
		const int len = MIN(numSamples, samples + (int)(endMarker - _pos) / (is16Bit ? 2 : 1));
		while (samples < len) {
			*buffer++ = READSAMPLE(is16Bit, isUnsigned, _pos);
			_pos += (is16Bit ? 2 : 1);
			samples++;
		}
		// Wrap around?
		if (_pos >= _bufferEnd)
			_pos = _pos - (_bufferEnd - _bufferStart);
	}
	return samples;
}

template<bool stereo, bool is16Bit, bool isUnsigned>
void WrappedMemoryStream<stereo, is16Bit, isUnsigned>::append(const byte *data, uint32 len) {

	// Verify the buffer size is sane
	if (is16Bit && stereo)
		assert((len & 3) == 0);
	else if (is16Bit || stereo)
		assert((len & 1) == 0);

	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)) {
			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)) {
			return;
		}
		memcpy(_end, data, len);
		_end += len;
	}
}


#pragma mark -
#pragma mark --- Input stream factories ---
#pragma mark -

template<bool stereo>
static AudioInputStream *makeLinearInputStream(const byte *ptr, uint32 len, bool is16Bit, bool isUnsigned, uint loopOffset, uint loopLen) {
	if (isUnsigned) {
		if (is16Bit)
			return new LinearMemoryStream<stereo, true, true>(ptr, len, loopOffset, loopLen);
		else
			return new LinearMemoryStream<stereo, false, true>(ptr, len, loopOffset, loopLen);
	} else {
		if (is16Bit)
			return new LinearMemoryStream<stereo, true, false>(ptr, len, loopOffset, loopLen);
		else
			return new LinearMemoryStream<stereo, false, false>(ptr, len, loopOffset, loopLen);
	}
}

template<bool stereo>
static WrappedAudioInputStream *makeWrappedInputStream(uint32 len, bool is16Bit, bool isUnsigned) {
	if (isUnsigned) {
		if (is16Bit)
			return new WrappedMemoryStream<stereo, true, true>(len);
		else
			return new WrappedMemoryStream<stereo, false, true>(len);
	} else {
		if (is16Bit)
			return new WrappedMemoryStream<stereo, true, false>(len);
		else
			return new WrappedMemoryStream<stereo, false, false>(len);
	}
}

AudioInputStream *makeLinearInputStream(byte _flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen) {
	const bool is16Bit = (_flags & SoundMixer::FLAG_16BITS) != 0;
	const bool isUnsigned = (_flags & SoundMixer::FLAG_UNSIGNED) != 0;
	if (_flags & SoundMixer::FLAG_STEREO) {
		return makeLinearInputStream<true>(ptr, len, is16Bit, isUnsigned, loopOffset, loopLen);
	} else {
		return makeLinearInputStream<false>(ptr, len, is16Bit, isUnsigned, loopOffset, loopLen);
	}
}

WrappedAudioInputStream *makeWrappedInputStream(byte _flags, uint32 len) {
	const bool is16Bit = (_flags & SoundMixer::FLAG_16BITS) != 0;
	const bool isUnsigned = (_flags & SoundMixer::FLAG_UNSIGNED) != 0;
	if (_flags & SoundMixer::FLAG_STEREO) {
		return makeWrappedInputStream<true>(len, is16Bit, isUnsigned);
	} else {
		return makeWrappedInputStream<false>(len, is16Bit, isUnsigned);
	}
}

--- NEW FILE: audiostream.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/audiostream.h,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

#ifndef AUDIOSTREAM_H
#define AUDIOSTREAM_H

#include "stdafx.h"
#include "scummsys.h"
#include "util.h"

class File;

/**
 * Generic input stream for the resampling code.
 */
class AudioInputStream {
public:
	virtual ~AudioInputStream() {}

	/**
	 * Fill the given buffer with up to numSamples samples.
	 * Returns the actual number of samples read, or -1 if
	 * a critical error occured (note: you *must* check if
	 * this value is less than what you requested, this can
	 * happend when the stream is fully used up).
	 * For stereo stream, buffer will be filled with interleaved
	 * left and right channel samples.
	 *
	 * For maximum efficency, subclasses should always override
	 * the default implementation!
	 */
	virtual int readBuffer(int16 *buffer, const int numSamples) {
		int samples;
		for (samples = 0; samples < numSamples && !eos(); samples++) {
			*buffer++ = read();
		}
		return samples;
	}

	/** Read a singel (16 bit signed) sample from the stream. */
	virtual int16 read() = 0;
	
	/** Is this a stereo stream? */
	virtual bool isStereo() const = 0;
	
	/* End of stream reached? */
	virtual bool eos() const = 0;

	virtual int getRate() const { return -1; }
};

class WrappedAudioInputStream : public AudioInputStream {
public:
	virtual void append(const byte *data, uint32 len) = 0;
};

class ZeroInputStream : public AudioInputStream {
protected:
	int _len;
public:
	ZeroInputStream(uint len) : _len(len) { }
	int readBuffer(int16 *buffer, const int numSamples) {
		int samples = MIN(_len, numSamples);
		memset(buffer, 0, samples * 2);
		_len -= samples;
		return samples;
	}
	int16 read() { assert(_len > 0); _len--; return 0; }
	int size() const { return _len; }
	bool isStereo() const { return false; }
	bool eos() const { return _len <= 0; }
};

class MusicStream : public AudioInputStream {
public:
	virtual int getRate() const = 0;
};


AudioInputStream *makeLinearInputStream(byte _flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen);
WrappedAudioInputStream *makeWrappedInputStream(byte _flags, uint32 len);

#endif

--- NEW FILE: mixer.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 * Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/mixer.cpp,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

#include "stdafx.h"
#include "file.h"
#include "util.h"

#include "mixer.h"
#include "rate.h"
#include "audiostream.h"


#pragma mark -
#pragma mark --- Channel classes ---
#pragma mark -


/**
 * Channels used by the sound mixer.
 */
class Channel {
protected:
	SoundMixer *_mixer;
	PlayingSoundHandle *_handle;
	RateConverter *_converter;
	AudioInputStream *_input;
	byte _volume;
	int8 _pan;
	bool _paused;

public:
	int _id;

	Channel(SoundMixer *mixer, PlayingSoundHandle *handle)
		: _mixer(mixer), _handle(handle), _converter(0), _input(0), _volume(0), _pan(0), _paused(false), _id(-1) {
		assert(mixer);
	}
	virtual ~Channel();
	void destroy();
	virtual void mix(int16 *data, uint len);
	virtual void pause(bool paused) {
		_paused = paused;
	}
	virtual bool isPaused() {
		return _paused;
	}
	virtual void setChannelVolume(const byte volume) {
		_volume = volume;
	}
	virtual void setChannelPan(const int8 pan) {
		_pan = pan;
	}
	virtual int getVolume() const {
		return isMusicChannel() ? _mixer->getMusicVolume() : _mixer->getVolume();
	}
	virtual bool isMusicChannel() const	= 0;
};

class ChannelRaw : public Channel {
	byte *_ptr;
public:
	ChannelRaw(SoundMixer *mixer, PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, byte volume, int8 pan, int id, uint32 loopStart, uint32 loopEnd);
	~ChannelRaw();
	bool isMusicChannel() const		{ return false; }
};

class ChannelStream : public Channel {
	bool _finished;
public:
	ChannelStream(SoundMixer *mixer, PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, uint32 buffer_size, byte volume, int8 pan);
	void mix(int16 *data, uint len);
	void append(void *sound, uint32 size);
	bool isMusicChannel() const		{ return true; }
	void finish()					{ _finished = true; }
};

#pragma mark -
#pragma mark --- SoundMixer ---
#pragma mark -


SoundMixer::SoundMixer() {
	_premixParam = 0;
	_premixProc = 0;
	int i = 0;

	_outputRate = 22050;

	_globalVolume = 256;
	_musicVolume = 256;

	_paused = false;

	initSound();

	for (i = 0; i != NUM_CHANNELS; i++)
		_channels[i] = NULL;
}

SoundMixer::~SoundMixer() {
	SDL_CloseAudio();
	for (int i = 0; i != NUM_CHANNELS; i++) {
		delete _channels[i];
	}
}

bool SoundMixer::initSound() {
	SDL_AudioSpec desired;

	memset(&desired, 0, sizeof(desired));

	/* only one format supported at the moment */
	desired.freq = 22050;
	desired.format = AUDIO_S16SYS;
	desired.channels = 2;
	desired.samples = 2048;
	desired.callback = mixCallback;
	desired.userdata = this;
	if (SDL_OpenAudio(&desired, NULL) != 0) {
		return false;
	}
	SDL_PauseAudio(0);
	return true;
}

void SoundMixer::setupPremix(PremixProc *proc, void *param) {
	_premixParam = param;
	_premixProc = proc;
}

int SoundMixer::newStream(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, uint32 buffer_size, byte volume, int8 pan) {
	return insertChannel(handle, new ChannelStream(this, handle, sound, size, rate, flags, buffer_size, volume, pan));
}

void SoundMixer::appendStream(PlayingSoundHandle handle, void *sound, uint32 size) {
	if (handle == 0)
		return;

	int index = handle - 1;

	if ((index < 0) || (index >= NUM_CHANNELS)) {
		warning("soundMixer::appendStream has invalid index %d", index);
		return;
	}

	ChannelStream *chan;
#if !defined(_WIN32_WCE) && !defined(__PALM_OS__)
	chan = dynamic_cast<ChannelStream *>(_channels[index]);
#else
	chan = (ChannelStream*)_channels[index];
#endif
	if (!chan) {
		error("Trying to append to nonexistant streamer : %d", index);
	} else {
		chan->append(sound, size);
	}
}

void SoundMixer::endStream(PlayingSoundHandle handle) {
	// Simply ignore stop requests for handles of sounds that already terminated
	if (handle == 0)
		return;

	int index = handle - 1;

	if ((index < 0) || (index >= NUM_CHANNELS)) {
		warning("soundMixer::endStream has invalid index %d", index);
		return;
	}

	ChannelStream *chan;
#if !defined(_WIN32_WCE) && !defined(__PALM_OS__)
	chan = dynamic_cast<ChannelStream *>(_channels[index]);
#else
	chan = (ChannelStream*)_channels[index];
#endif
	if (!chan) {
		error("Trying to end a nonexistant streamer : %d", index);
	} else {
		chan->finish();
	}
}

int SoundMixer::insertChannel(PlayingSoundHandle *handle, Channel *chan) {
	int index = -1;
	for (int i = 0; i != NUM_CHANNELS; i++) {
		if (_channels[i] == NULL) {
			index = i;
			break;
		}
	}
	if(index == -1) {
		warning("SoundMixer::out of mixer slots");
		delete chan;
		return -1;
	}

	_channels[index] = chan;
	if (handle)
		*handle = index + 1;
	return index;
}

int SoundMixer::playRaw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, int id, byte volume, int8 pan, uint32 loopStart, uint32 loopEnd) {
	// Prevent duplicate sounds
	if (id != -1) {
		for (int i = 0; i != NUM_CHANNELS; i++)
			if (_channels[i] != NULL && _channels[i]->_id == id)
				return -1;
	}

	return insertChannel(handle, new ChannelRaw(this, handle, sound, size, rate, flags, volume, pan, id, loopStart, loopEnd));
}

void SoundMixer::mix(int16 *buf, uint len) {

	if (_premixProc && !_paused) {
		_premixProc(_premixParam, buf, len);
	} else {
		//  zero the buf out
		memset(buf, 0, 2 * len * sizeof(int16));
	}

	if (!_paused) {
		// now mix all channels
		for (int i = 0; i != NUM_CHANNELS; i++)
			if (_channels[i] && !_channels[i]->isPaused())
				_channels[i]->mix(buf, len);
	}
}

void SoundMixer::mixCallback(void *s, byte *samples, int len) {
	assert(s);
	assert(samples);
	// Len is the number of bytes in the buffer; we divide it by
	// four to get the number of samples (stereo 16 bit).
	((SoundMixer *)s)->mix((int16 *)samples, len >> 2);
}

void SoundMixer::stopAll() {
	for (int i = 0; i != NUM_CHANNELS; i++)
		if (_channels[i])
			_channels[i]->destroy();
}

void SoundMixer::stopChannel(int index) {
	if ((index < 0) || (index >= NUM_CHANNELS)) {
		warning("soundMixer::stop has invalid index %d", index);
		return;
	}

	if (_channels[index])
		_channels[index]->destroy();
}

void SoundMixer::stopID(int id) {
	for (int i = 0; i != NUM_CHANNELS; i++) {
		if (_channels[i] != NULL && _channels[i]->_id == id) {
			_channels[i]->destroy();
			return;
		}
	}
}

void SoundMixer::stopHandle(PlayingSoundHandle handle) {
	// Simply ignore stop requests for handles of sounds that already terminated
	if (handle == 0)
		return;

	int index = handle - 1;

	if ((index < 0) || (index >= NUM_CHANNELS)) {
		warning("soundMixer::stopHandle has invalid index %d", index);
		return;
	}

	if (_channels[index])
		_channels[index]->destroy();
}

void SoundMixer::setChannelVolume(PlayingSoundHandle handle, byte volume) {
	if (handle == 0)
		return;

	int index = handle - 1;

	if ((index < 0) || (index >= NUM_CHANNELS)) {
		warning("soundMixer::setChannelVolume has invalid index %d", index);
		return;
	}

	if (_channels[index])
		_channels[index]->setChannelVolume(volume);
}

void SoundMixer::setChannelPan(PlayingSoundHandle handle, int8 pan) {
	if (handle == 0)
		return;

	int index = handle - 1;

	if ((index < 0) || (index >= NUM_CHANNELS)) {
		warning("soundMixer::setChannelVolume has invalid index %d", index);
		return;
	}

	if (_channels[index])
		_channels[index]->setChannelPan(pan);
}

void SoundMixer::pauseAll(bool paused) {
	_paused = paused;
}

void SoundMixer::pauseChannel(int index, bool paused) {
	if ((index < 0) || (index >= NUM_CHANNELS)) {
		warning("soundMixer::pauseChannel has invalid index %d", index);
		return;
	}

	if (_channels[index])
		_channels[index]->pause(paused);
}

void SoundMixer::pauseID(int id, bool paused) {
	for (int i = 0; i != NUM_CHANNELS; i++) {
		if (_channels[i] != NULL && _channels[i]->_id == id) {
			_channels[i]->pause(paused);
			return;
		}
	}
}

void SoundMixer::pauseHandle(PlayingSoundHandle handle, bool paused) {
	// Simply ignore pause/unpause requests for handles of sound that alreayd terminated
	if (handle == 0)
		return;

	int index = handle - 1;

	if ((index < 0) || (index >= NUM_CHANNELS)) {
		warning("soundMixer::pauseHandle has invalid index %d", index);
		return;
	}

	if (_channels[index])
		_channels[index]->pause(paused);
}

bool SoundMixer::hasActiveSFXChannel() {
	// FIXME/TODO: We need to distinguish between SFX and music channels
	// (and maybe also voice) here to work properly in iMuseDigital
	// games. In the past that was achieve using the _beginSlots hack.
	// Since we don't have that anymore, it's not that simple anymore.
	for (int i = 0; i != NUM_CHANNELS; i++)
		if (_channels[i] && !_channels[i]->isMusicChannel())
			return true;
	return false;
}

void SoundMixer::setVolume(int volume) {
	// Check range
	if (volume > 256)
		volume = 256;
	else if (volume < 0)
		volume = 0;

	_globalVolume = volume;
}

void SoundMixer::setMusicVolume(int volume) {
	// Check range
	if (volume > 256)
		volume = 256;
	else if (volume < 0)
		volume = 0;

	_musicVolume = volume;
}


#pragma mark -
#pragma mark --- Channel implementations ---
#pragma mark -


Channel::~Channel() {
	delete _converter;
	delete _input;
	if (_handle)
		*_handle = 0;
}

void Channel::destroy() {
	for (int i = 0; i != SoundMixer::NUM_CHANNELS; i++)
		if (_mixer->_channels[i] == this)
			_mixer->_channels[i] = 0;
	delete this;
}

/* len indicates the number of sample *pairs*. So a value of
   10 means that the buffer contains twice 10 sample, each
   16 bits, for a total of 40 bytes.
 */
void Channel::mix(int16 *data, uint len) {
	assert(_input);
	if (_input->eos()) {
		// TODO: call drain method
		destroy();
	} else {
		assert(_converter);

		// The pan value ranges from -127 to +127. That's 255 different values.
		// From the channel pan/volume and the global volume, we compute the
		// effective volume for the left and right channel.
		// Note the slightly odd divisor: the 255 reflects the fact that
		// the maximal value for _volume is 255, while the 254 is there
		// because the maximal left/right pan value is 2*127 = 254.
		// The value getVolume() returns is in the range 0 - 256.
		// Hence, the vol_l/vol_r values will be in that range, too
		
		int vol = getVolume() * _volume;
		st_volume_t vol_l = (127 - _pan) * vol / (255 * 254);
		st_volume_t vol_r = (127 + _pan) * vol / (255 * 254);

		_converter->flow(*_input, data, len, vol_l, vol_r);
	}
}

/* RAW mixer */
ChannelRaw::ChannelRaw(SoundMixer *mixer, PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, byte volume, int8 pan, int id, uint32 loopStart, uint32 loopEnd)
	: Channel(mixer, handle) {
	_id = id;
	_ptr = (byte *)sound;
	_volume = volume;
	_pan = pan;
	
	// Create the input stream
	if (flags & SoundMixer::FLAG_LOOP) {
		if (loopEnd == 0) {
			_input = makeLinearInputStream(flags, _ptr, size, 0, size);
		} else {
			assert(loopStart < loopEnd && loopEnd <= size);
			_input = makeLinearInputStream(flags, _ptr, size, loopStart, loopEnd - loopStart);
		}
	} else {
		_input = makeLinearInputStream(flags, _ptr, size, 0, 0);
	}

	// Get a rate converter instance
	_converter = makeRateConverter(rate, mixer->getOutputRate(), _input->isStereo(), (flags & SoundMixer::FLAG_REVERSE_STEREO) != 0);

	if (!(flags & SoundMixer::FLAG_AUTOFREE))
		_ptr = 0;
}

ChannelRaw::~ChannelRaw() {
	free(_ptr);
}

ChannelStream::ChannelStream(SoundMixer *mixer, PlayingSoundHandle *handle,
                             void *sound, uint32 size, uint rate,
                             byte flags, uint32 buffer_size, byte volume, int8 pan)
	: Channel(mixer, handle) {
	_volume = volume;
	_pan = pan;
	assert(size <= buffer_size);

	// Create the input stream
	_input = makeWrappedInputStream(flags, buffer_size);
	
	// Append the initial data
	((WrappedAudioInputStream *)_input)->append((const byte *)sound, size);

	// Get a rate converter instance
	_converter = makeRateConverter(rate, mixer->getOutputRate(), _input->isStereo(), (flags & SoundMixer::FLAG_REVERSE_STEREO) != 0);

	_finished = false;
}

void ChannelStream::append(void *data, uint32 len) {
	((WrappedAudioInputStream *)_input)->append((const byte *)data, len);
}

void ChannelStream::mix(int16 *data, uint len) {
	assert(_input);
	if (_input->eos()) {
		// TODO: call drain method

		// Normally, the stream stays around even if all its data is used up.
		// This is in case more data is streamed into it. To make the stream
		// go away, one can either stop() it (which takes effect immediately,
		// ignoring any remaining sound data), or finish() it, which means
		// it will finish playing before it terminates itself.
		if (_finished) {
			destroy();
		}
	} else {
		// Invoke the parent implementation.
		Channel::mix(data, len);
	}
}


--- NEW FILE: mixer.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 * Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/mixer.h,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

#ifndef SOUND_MIXER_H
#define SOUND_MIXER_H

#include "stdafx.h"
#include "scummsys.h"
#include "SDL.h"

typedef uint32 PlayingSoundHandle;

class Channel;
class File;

class SoundMixer {
	friend class Channel;
public:
	typedef void PremixProc (void *param, int16 *data, uint len);

	enum {
		NUM_CHANNELS = 16
	};

	enum {
		FLAG_UNSIGNED = 1 << 0,         // unsigned samples (default: signed)
		FLAG_STEREO = 1 << 1,           // sound is in stereo (default: mono)
		FLAG_16BITS = 1 << 2,           // sound is 16 bits wide (default: 8bit)
		FLAG_AUTOFREE = 1 << 3,         // sound buffer is freed automagically at the end of playing
		FLAG_REVERSE_STEREO = 1 << 4,   // reverse the left and right stereo channel
		FLAG_LOOP = 1 << 5              // loop the audio
	};

private:
	void *_premixParam;
	PremixProc *_premixProc;

	uint _outputRate;

	int _globalVolume;
	int _musicVolume;

	bool _paused;

	Channel *_channels[NUM_CHANNELS];

public:
	SoundMixer();
	~SoundMixer();

	bool initSound();

	/**
	 * Set the premix procedure. This is mainly used for the adlib music, but is not limited
	 * to it. The premix proc is invoked by the mixer whenever it needs to generate any
	 * data, before any other mixing takes place. The premixer than has a chanve to fill
	 * the mix buffer with data (usually music samples). It should generate the specified
	 * number of 16bit stereo samples (i.e. len * 4 bytes).
	 */
	void setupPremix(PremixProc *proc, void *param);

	// start playing a raw sound
	int playRaw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags,
				int id = -1, byte volume = 255, int8 pan = 0, uint32 loopStart = 0, uint32 loopEnd = 0);

	/** Start a new stream. */
	int newStream(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, uint32 buffer_size, byte volume = 255, int8 pan = 0);

	/** Append to an existing stream. */
	void appendStream(PlayingSoundHandle handle, void *sound, uint32 size);

	/** Mark a stream as finished - it will play all its remaining data, then stop. */
	void endStream(PlayingSoundHandle handle);

	/** stop all currently playing sounds */
	void stopAll();

	/** stop playing the given channel */
	void stopChannel(int channel);

	/** stop playing the sound with given ID  */
	void stopID(int id);

	/** stop playing the channel for the given handle */
	void stopHandle(PlayingSoundHandle handle);

	/** pause/unpause all channels */
	void pauseAll(bool paused);

	/** pause/unpause the given channel */
	void pauseChannel(int index, bool paused);

	/** pause/unpause the sound with the given ID */
	void pauseID(int id, bool paused);

	/** pause/unpause the channel for the given handle */
	void pauseHandle(PlayingSoundHandle handle, bool paused);

	/** set the channel volume for the given handle (0 - 255) */
	void setChannelVolume(PlayingSoundHandle handle, byte volume);

	/** set the channel pan for the given handle (-127 ... 0 ... 127) (left ... center ... right)*/
	void setChannelPan(PlayingSoundHandle handle, int8 pan);

	/** Check whether any SFX channel is active.*/
	bool hasActiveSFXChannel();
	
	/** set the global volume, 0-256 */
	void setVolume(int volume);
	
	/** query the global volume, 0-256 */
	int getVolume() const { return _globalVolume; }

	/** set the music volume, 0-256 */
	void setMusicVolume(int volume);
	
	/** query the music volume, 0-256 */
	int getMusicVolume() const { return _musicVolume; }
	
	/** query the output rate in kHz */
	uint getOutputRate() const { return _outputRate; }

private:
	int insertChannel(PlayingSoundHandle *handle, Channel *chan);

	/** main mixer method */
	void mix(int16 * buf, uint len);

	static void mixCallback(void *s, byte *samples, int len);
};

#endif

--- NEW FILE: module.mk ---
MODULE := sound

MODULE_OBJS := \
	sound/sound.o \
	sound/audiostream.o \
	sound/mixer.o \
	sound/rate.o \
	sound/voc.o

MODULE_DIRS += \
	sound

# Include common rules 
include common.rules

--- NEW FILE: rate.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/rate.cpp,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

/*
 * The code in this file is based on code with Copyright 1998 Fabrice Bellard
 * Fabrice original code is part of SoX (http://sox.sourceforge.net).
 * Max Horn adapted that code to the needs of ScummVM and rewrote it partial,
 * in the process removing any use of floating point arithmetic. Various other
 * improvments over the original code were made.
 */

#include "stdafx.h"
#include "rate.h"
#include "audiostream.h"

/**
 * The precision of the fractional computations used by the rate converter.
 * Normally you should never have to modify this value.
 */
#define FRAC_BITS 16

/**
 * The size of the intermediate input cache. Bigger values may increase
 * performance, but only until some point (depends largely on cache size,
 * target processor and various other factors), at which it will decrease
 * again.
 */
#define INTERMEDIATE_BUFFER_SIZE 512


/**
 * Audio rate converter based on simple linear Interpolation.
 *
 * The use of fractional increment allows us to use no buffer. It
 * avoid the problems at the end of the buffer we had with the old
 * method which stored a possibly big buffer of size
 * lcm(in_rate,out_rate).
 *
 * Limited to sampling frequency <= 65535 Hz.
 */

template<bool stereo, bool reverseStereo>
class LinearRateConverter : public RateConverter {
protected:
	st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
	const st_sample_t *inPtr;
	int inLen;

	/** fractional position of the output stream in input stream unit */
	unsigned long opos, opos_frac;

	/** fractional position increment in the output stream */
	unsigned long opos_inc, opos_inc_frac;

	/** position in the input stream (integer) */
	unsigned long ipos;

	/** last sample(s) in the input stream (left/right channel) */
	st_sample_t ilast[2];
	/** current sample(s) in the input stream (left/right channel) */
	st_sample_t icur[2];

public:
	LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
	int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
	int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
		return (ST_SUCCESS);
	}
};


/*
 * Prepare processing.
 */
template<bool stereo, bool reverseStereo>
LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) {
	unsigned long incr;

	if (inrate == outrate) {
		error("Input and Output rates must be different to use rate effect");
	}

	if (inrate >= 65536 || outrate >= 65536) {
		error("rate effect can only handle rates < 65536");
	}

	opos_frac = 0;
	opos = 1;

	/* increment */
	incr = (inrate << FRAC_BITS) / outrate;

	opos_inc_frac = incr & ((1UL << FRAC_BITS) - 1);
	opos_inc = incr >> FRAC_BITS;

	ipos = 0;

	ilast[0] = ilast[1] = 0;
	icur[0] = icur[1] = 0;
	
	inLen = 0;
}

/*
 * Processed signed long samples from ibuf to obuf.
 * Return number of samples processed.
 */
template<bool stereo, bool reverseStereo>
int LinearRateConverter<stereo, reverseStereo>::flow(AudioInputStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r)
{
	st_sample_t *ostart, *oend;
	st_sample_t out[2];
	
	const int numChannels = stereo ? 2 : 1;
	int i;

	ostart = obuf;
	oend = obuf + osamp * 2;

	while (obuf < oend) {

		// read enough input samples so that ipos > opos
		while (ipos <= opos) {
			// Check if we have to refill the buffer
			if (inLen == 0) {
				inPtr = inBuf;
				inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
				if (inLen <= 0)
					goto the_end;
			}
			for (i = 0; i < numChannels; i++) {
				ilast[i] = icur[i];
				icur[i] = *inPtr++;
				inLen--;
			}
			ipos++;
		}

		// Loop as long as the outpos trails behind, and as long as there is
		// still space in the output buffer.
		while (ipos > opos) {

			// interpolate
			out[0] = out[1] = (st_sample_t)(ilast[0] + (((icur[0] - ilast[0]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));

			if (stereo) {
				// interpolate
				out[reverseStereo ? 0 : 1] = (st_sample_t)(ilast[1] + (((icur[1] - ilast[1]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
			}

			// output left channel
			clampedAdd(*obuf++, (out[0] * (int)vol_l) >> 8);

			// output right channel
			clampedAdd(*obuf++, (out[1] * (int)vol_r) >> 8);

			// Increment output position
			unsigned long tmp = opos_frac + opos_inc_frac;
			opos += opos_inc + (tmp >> FRAC_BITS);
			opos_frac = tmp & ((1UL << FRAC_BITS) - 1);

			// Abort if we reached the end of the output buffer
			if (obuf >= oend)
				goto the_end;
		}
	}

the_end:
	return (ST_SUCCESS);
}


#pragma mark -


/**
 * Simple audio rate converter for the case that the inrate equals the outrate.
 */
template<bool stereo, bool reverseStereo>
class CopyRateConverter : public RateConverter {
public:
	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
		int16 tmp[2];
		st_size_t len = osamp;
		assert(input.isStereo() == stereo);
		while (!input.eos() && len--) {
			tmp[0] = tmp[1] = input.read();
			if (stereo)
				tmp[reverseStereo ? 0 : 1] = input.read();

			// output left channel
			clampedAdd(*obuf++, (tmp[0] * (int)vol_l) >> 8);
	
			// output right channel
			clampedAdd(*obuf++, (tmp[1] * (int)vol_r) >> 8);
		}
		return (ST_SUCCESS);
	}
	virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
		return (ST_SUCCESS);
	}
};


#pragma mark -


/**
 * Create and return a RateConverter object for the specified input and output rates.
 */
RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
	if (inrate != outrate) {
		if (stereo) {
			if (reverseStereo)
				return new LinearRateConverter<true, true>(inrate, outrate);
			else
				return new LinearRateConverter<true, false>(inrate, outrate);
		} else
			return new LinearRateConverter<false, false>(inrate, outrate);
		//return new ResampleRateConverter(inrate, outrate, 1);
	} else {
		if (stereo) {
			if (reverseStereo)
				return new CopyRateConverter<true, true>();
			else
				return new CopyRateConverter<true, false>();
		} else
			return new CopyRateConverter<false, false>();
	}
}

--- NEW FILE: rate.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/rate.h,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

#ifndef SOUND_RATE_H
#define SOUND_RATE_H

#include "scummsys.h"
#include "util.h"

class AudioInputStream;

typedef int16 st_sample_t;
typedef uint16 st_volume_t;
typedef uint32 st_size_t;
typedef uint32 st_rate_t;

/* Minimum and maximum values a sample can hold. */
#define ST_SAMPLE_MAX 0x7fffL
#define ST_SAMPLE_MIN (-ST_SAMPLE_MAX - 1L)

#define ST_EOF (-1)
#define ST_SUCCESS (0)

static inline void clampedAdd(int16& a, int b) {
	register int val;
#ifdef OUTPUT_UNSIGNED_AUDIO
	val = (a ^ 0x8000) + b;
#else
	val = a + b;
#endif

	if (val > ST_SAMPLE_MAX)
		val = ST_SAMPLE_MAX;
	else if (val < ST_SAMPLE_MIN)
		val = ST_SAMPLE_MIN;

#ifdef OUTPUT_UNSIGNED_AUDIO
	a = ((int16)val) ^ 0x8000;
#else
	a = val;
#endif
}

// Q&D hack to get this SOX stuff to work
#define st_report warning
#define st_warn warning
#define st_fail error


class RateConverter {
public:
	RateConverter() {}
	virtual ~RateConverter() {}
	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) = 0;
	virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) = 0;
};

RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo = false);

#endif

--- NEW FILE: sound.cpp ---
/* ScummEX - Viewer for Scumm data files
 * Copyright (C) 2003 Adrien Mercier
 * Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/sound.cpp,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

#include "sound.h"
#include "sound/mixer.h"
#include "sound/voc.h"

static const int16 imcTable[] = {
    0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010,
    0x0011,
    0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025, 0x0029,
    0x002D,
    0x0032, 0x0037, 0x003C, 0x0042, 0x0049, 0x0050, 0x0058, 0x0061, 0x006B,
    0x0076,
    0x0082, 0x008F, 0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117,
    0x0133,
    0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292, 0x02D4,
    0x031C,
    0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, 0x0610, 0x06AB, 0x0756,
    0x0812,
    0x08E0, 0x09C3, 0x0ABD, 0x0BD0, 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307,
    0x14EE,
    0x1706, 0x1954, 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B,
    0x364B,
    0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
};

static const byte imxOtherTable[6][128] = {
    {
     0xFF, 0x04, 0xFF, 0x04},

    {
     0xFF, 0xFF, 0x02, 0x08, 0xFF, 0xFF, 0x02, 0x08},

    {
     0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x04, 0x06,
     0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x04, 0x06},

    {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0x01, 0x02, 0x04, 0x06, 0x08, 0x0C, 0x10, 0x20,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0x01, 0x02, 0x04, 0x06, 0x08, 0x0C, 0x10, 0x20},

    {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
     0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x20,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
     0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x20},

    {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
     0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
     0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20}
};

const byte imxShortTable[] = {
    0, 0, 1, 3, 7, 15, 31, 63
};

	byte _destImcTable[93];
	uint32 _destImcTable2[5697];
	CompTable *_compMusicTable;


Sound::Sound() {

	_mixer = new SoundMixer();
	initializeImcTables();
}

Sound::~Sound() {
	delete _mixer;
}

int Sound::playSOU(BlockTable *_blockTable, File& _input, int index, File& _output, int save)
{
	byte *data;

	if (_blockTable[index].blockTypeID == AUdt)
		_input.seek(_blockTable[index].offset+8, SEEK_SET);
	else
		_input.seek(_blockTable[index].offset+26, SEEK_SET);

	VocBlockHeader voc_block_hdr;

	_input.read(&voc_block_hdr, sizeof(voc_block_hdr));
	if (voc_block_hdr.blocktype != 1) {
		printf("startSfxSound: Expecting block_type == 1, got %d", voc_block_hdr.blocktype);
		return 0;
	}

	uint size = voc_block_hdr.size[0] + (voc_block_hdr.size[1] << 8) + (voc_block_hdr.size[2] << 16) - 2;
	int rate = getSampleRateFromVOCRate(voc_block_hdr.sr);
	int comp = voc_block_hdr.pack;

	if (comp != 0) {
		printf("playSOU: Unsupported compression type %d", comp);
		return 0;
	}

	data = (byte *)malloc(size);
	
	if (_input.read(data, size) != size) {
		printf("cannot read %d bytes", _blockTable[index].blockSize);
	}

	_mixer->playRaw(NULL, data, _blockTable[index].blockSize, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
	free(data);	
	return 0;
}

void Sound::initializeImcTables()
{
    int32 destTablePos = 0;
    int32 imcTable1Pos = 0;
    do {
	byte put = 1;
	int32 tableValue = ((imcTable[imcTable1Pos] << 2) / 7) >> 1;
	if (tableValue != 0) {
	    do {
		tableValue >>= 1;
		put++;
	    }
	    while (tableValue != 0);
	}
	if (put < 3) {
	    put = 3;
	}
	if (put > 8) {
	    put = 8;
	}
	put--;
	_destImcTable[destTablePos] = put;
	destTablePos++;
    }
    while (++imcTable1Pos <= 88);
    _destImcTable[89] = 0;

    for (int n = 0; n < 64; n++) {
	imcTable1Pos = 0;
	destTablePos = n;
	do {
	    int32 count = 32;
	    int32 put = 0;
	    int32 tableValue = imcTable[imcTable1Pos];
	    do {
		if ((count & n) != 0) {
		    put += tableValue;
		}
		count >>= 1;
		tableValue >>= 1;
	    }
	    while (count != 0);
	    _destImcTable2[destTablePos] = put;
	    destTablePos += 64;
	}
	while (++imcTable1Pos <= 88);
    }
}

#define NextBit bit = mask & 1; mask >>= 1;				\
								if (!--bitsleft) {								\
									mask = READ_LE_UINT16(srcptr);	\
									srcptr += 2;										\
									bitsleft = 16;									\
								}

int32 Sound::compDecode(byte * src, byte * dst)
{
    byte *result, *srcptr = src, *dstptr = dst;
    int data, size, bit, bitsleft = 16, mask = READ_LE_UINT16(srcptr);
    srcptr += 2;

    while (1) {
	NextBit if (bit) {
	    *dstptr++ = *srcptr++;
	} else {
	    NextBit if (!bit) {
		NextBit size = bit << 1;
		NextBit size = (size | bit) + 3;
		data = *srcptr++ | 0xffffff00;
	    } else {
		data = *srcptr++;
		size = *srcptr++;

		data |= 0xfffff000 + ((size & 0xf0) << 4);
		size = (size & 0x0f) + 3;

		if (size == 3)
		    if (((*srcptr++) + 1) == 1)
			return dstptr - dst;
	    }
	    result = dstptr + data;
	    while (size--)
		*dstptr++ = *result++;
	}
    }
}

#undef NextBit

int Sound::playiMUSE(File& _input, BlockTable *_blockTable, int index, File& _output, int save)
{
    int32 i = 0;
    int tag, num, input_size, codec;
    uint32 size = 0, rate = 0, chan = 0, bits = 0, s_size = 0;
    byte *comp_input, *comp_output, *CompFinal, *buffer = NULL;
    int32 output_size, channels;
    int32 offset1, offset2, offset3, length, k, c, s, j, r, t, z;
    byte *src, *t_table, *p, *ptr;
    byte t_tmp1, t_tmp2;
    CompFinal = (byte *) malloc(30000000);
    int32 finalSize;
    finalSize = 0;
    int voice = 0;

	_input.seek(_blockTable[index].offset, SEEK_SET);
	tag = _input.readUint32BE();
	num = _input.readUint32BE();
	_input.readUint32BE();
	_input.readUint32BE();

	if (tag != MKID_BE('COMP')) {
	    printf("Bundle: Compressed sound %d invalid (%c%c%c%c)\n",
		   index, tag >> 24, tag >> 16, tag >> 8, tag);
	    return 0;
	}

	free(_compMusicTable);
	_compMusicTable = (CompTable *) malloc(sizeof(CompTable) * num);

	for (i = 0; i < num; i++) {
	    _compMusicTable[i].offset = _input.readUint32BE();
	    _compMusicTable[i].size = _input.readUint32BE();
	    _compMusicTable[i].codec = _input.readUint32BE();
	    _input.readUint32BE();
	}

    for (i = 0; i < num; i++) {
	comp_input = (byte *) malloc(_compMusicTable[i].size + 1);
	comp_input[_compMusicTable[i].size] = 0;
	comp_output = (byte *) malloc(10000);
	memset(comp_output, 0, 10000);
	input_size = _compMusicTable[i].size;
	codec = _compMusicTable[i].codec;

	_input.seek(_blockTable[index].offset + _compMusicTable[i].offset, SEEK_SET);
	_input.read(comp_input, _compMusicTable[i].size);

	switch (_compMusicTable[i].codec) {
	case 0:
	    memcpy(comp_output, comp_input, input_size);
	    output_size = input_size;
	    break;

	case 1:
	    output_size = compDecode(comp_input, comp_output);
	    break;

	case 2:
	    output_size = compDecode(comp_input, comp_output);
	    p = comp_output;
	    for (z = 1; z < output_size; z++)
		p[z] += p[z - 1];
	    break;

	case 3:
	    output_size = compDecode(comp_input, comp_output);
	    p = comp_output;
	    for (z = 2; z < output_size; z++)
		p[z] += p[z - 1];
	    for (z = 1; z < output_size; z++)
		p[z] += p[z - 1];
	    break;

	case 4:
	    output_size = compDecode(comp_input, comp_output);
	    p = comp_output;
	    for (z = 2; z < output_size; z++)
		p[z] += p[z - 1];
	    for (z = 1; z < output_size; z++)
		p[z] += p[z - 1];

	    t_table = (byte *) malloc(output_size);
	    memset(t_table, 0, output_size);

	    src = comp_output;
	    length = (output_size * 8) / 12;
	    k = 0;
	    if (length > 0) {
		c = -12;
		s = 0;
		j = 0;
		do {
		    ptr = src + length + (k >> 1);
		    if (k & 1) {
			r = c >> 3;
			t_table[r + 2] =
			    ((src[j] & 0x0f) << 4) | (ptr[1] >> 4);
			t_table[r + 1] =
			    (src[j] & 0xf0) | (t_table[r + 1]);
		    } else {
			r = s >> 3;
			t_table[r + 0] =
			    ((src[j] & 0x0f) << 4) | (ptr[0] & 0x0f);
			t_table[r + 1] = src[j] >> 4;
		    }
		    s += 12;
		    c += 12;
		    k++;
		    j++;
		}
		while (k < length);
	    }
	    offset1 = ((length - 1) * 3) / 2;
	    t_table[offset1 + 1] =
		(t_table[offset1 + 1]) | (src[length - 1] & 0xf0);
	    memcpy(src, t_table, output_size);
	    free(t_table);
	    break;

	case 5:
	    output_size = compDecode(comp_input, comp_output);
	    p = comp_output;
	    for (z = 2; z < output_size; z++)
		p[z] += p[z - 1];
	    for (z = 1; z < output_size; z++)
		p[z] += p[z - 1];

	    t_table = (byte *) malloc(output_size);
	    memset(t_table, 0, output_size);

	    src = comp_output;
	    length = (output_size * 8) / 12;
	    k = 1;
	    c = 0;
	    s = 12;
	    t_table[0] = src[length] / 16;
	    t = length + k;
	    j = 1;
	    if (t > k) {
		do {
		    ptr = src + length + (k >> 1);
		    if (k & 1) {
			r = c >> 3;
			t_table[r + 0] = (src[j - 1] & 0xf0) | t_table[r];
			t_table[r + 1] =
			    ((src[j - 1] & 0x0f) << 4) | (ptr[0] & 0x0f);
		    } else {
			r = s >> 3;
			t_table[r + 0] = src[j - 1] >> 4;
			t_table[r - 1] =
			    ((src[j - 1] & 0x0f) << 4) | (ptr[0] >> 4);
		    }
		    s += 12;
		    c += 12;
		    k++;
		    j++;
		}
		while (k < t);
	    }
	    memcpy(src, t_table, output_size);
	    free(t_table);
	    break;

	case 6:
	    output_size = compDecode(comp_input, comp_output);
	    p = comp_output;
	    for (z = 2; z < output_size; z++)
		p[z] += p[z - 1];
	    for (z = 1; z < output_size; z++)
		p[z] += p[z - 1];

	    t_table = (byte *) malloc(output_size);
	    memset(t_table, 0, output_size);

	    src = comp_output;
	    length = (output_size * 8) / 12;
	    k = 0;
	    c = 0;
	    j = 0;
	    s = -12;
	    t_table[0] = src[output_size - 1];
	    t_table[output_size - 1] = src[length - 1];
	    t = length - 1;
	    if (t > 0) {
		do {
		    ptr = src + length + (k >> 1);
		    if (k & 1) {
			r = s >> 3;
			t_table[r + 2] =
			    (src[j] & 0xf0) | *(t_table + r + 2);
			t_table[r + 3] =
			    ((src[j] & 0x0f) << 4) | (ptr[0] >> 4);
		    } else {
			r = c >> 3;
			t_table[r + 2] = src[j] >> 4;
			t_table[r + 1] =
			    ((src[j] & 0x0f) << 4) | (ptr[0] & 0x0f);
		    }
		    s += 12;
		    c += 12;
		    k++;
		    j++;
		}
		while (k < t);
	    }
	    memcpy(src, t_table, output_size);
	    free(t_table);
	    break;

	case 10:
	    output_size = compDecode(comp_input, comp_output);
	    p = comp_output;
	    for (z = 2; z < output_size; z++)
		p[z] += p[z - 1];
	    for (z = 1; z < output_size; z++)
		p[z] += p[z - 1];

	    t_table = (byte *) malloc(output_size);
	    memcpy(t_table, p, output_size);

	    offset1 = output_size / 3;
	    offset2 = offset1 * 2;
	    offset3 = offset2;
	    src = comp_output;
	    do {
		if (offset1 == 0)
		    break;
		offset1--;
		offset2 -= 2;
		offset3--;
		t_table[offset2 + 0] = src[offset1];
		t_table[offset2 + 1] = src[offset3];
	    }
	    while (1);

	    src = comp_output;
	    length = (output_size * 8) / 12;
	    k = 0;
	    if (length > 0) {
		c = -12;
		s = 0;
		do {
		    j = length + (k >> 1);
		    if (k & 1) {
			r = c >> 3;
			t_tmp1 = t_table[k];
			t_tmp2 = t_table[j + 1];
			src[r + 2] =
			    ((t_tmp1 & 0x0f) << 4) | (t_tmp2 >> 4);
			src[r + 1] = (src[r + 1]) | (t_tmp1 & 0xf0);
		    } else {
			r = s >> 3;
			t_tmp1 = t_table[k];
			t_tmp2 = t_table[j];
			src[r + 0] =
			    ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
			src[r + 1] = t_tmp1 >> 4;
		    }
		    s += 12;
		    c += 12;
		    k++;
		}
		while (k < length);
	    }
	    offset1 = ((length - 1) * 3) / 2;
	    src[offset1 + 1] = (t_table[length] & 0xf0) | src[offset1 + 1];
	    free(t_table);
	    break;

	case 11:
	    output_size = compDecode(comp_input, comp_output);
	    p = comp_output;
	    for (z = 2; z < output_size; z++)
		p[z] += p[z - 1];
	    for (z = 1; z < output_size; z++)
		p[z] += p[z - 1];

	    t_table = (byte *) malloc(output_size);
	    memcpy(t_table, p, output_size);

	    offset1 = output_size / 3;
	    offset2 = offset1 * 2;
	    offset3 = offset2;
	    src = comp_output;
	    do {
		if (offset1 == 0)
		    break;
		offset1--;
		offset2 -= 2;
		offset3--;
		t_table[offset2 + 0] = src[offset1];
		t_table[offset2 + 1] = src[offset3];
	    }
	    while (1);

	    src = comp_output;
	    length = (output_size * 8) / 12;
	    k = 1;
	    c = 0;
	    s = 12;
	    t_tmp1 = t_table[length] / 16;
	    src[0] = t_tmp1;
	    t = length + k;
	    if (t > k) {
		do {
		    j = length + (k / 2);
		    if (k & 1) {
			r = c >> 3;
			t_tmp1 = t_table[k - 1];
			t_tmp2 = t_table[j];
			src[r + 0] = (src[r]) | (t_tmp1 & 0xf0);
			src[r + 1] =
			    ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
		    } else {
			r = s >> 3;
			t_tmp1 = t_table[k - 1];
			t_tmp2 = t_table[j];
			src[r + 0] = t_tmp1 >> 4;
			src[r - 1] =
			    ((t_tmp1 & 0x0f) << 4) | (t_tmp2 >> 4);
		    }
		    s += 12;
		    c += 12;
		    k++;
		}
		while (k < t);
	    }
	    free(t_table);
	    break;

	case 12:
	    output_size = compDecode(comp_input, comp_output);
	    p = comp_output;
	    for (z = 2; z < output_size; z++)
		p[z] += p[z - 1];
	    for (z = 1; z < output_size; z++)
		p[z] += p[z - 1];

	    t_table = (byte *) malloc(output_size);
	    memcpy(t_table, p, output_size);

	    offset1 = output_size / 3;
	    offset2 = offset1 * 2;
	    offset3 = offset2;
	    src = comp_output;
	    do {
		if (offset1 == 0)
		    break;
		offset1--;
		offset2 -= 2;
		offset3--;
		t_table[offset2 + 0] = src[offset1];
		t_table[offset2 + 1] = src[offset3];
	    }
	    while (1);

	    src = comp_output;
	    length = (output_size * 8) / 12;
	    k = 0;
	    c = 0;
	    s = -12;
	    src[0] = t_table[output_size - 1];
	    src[output_size - 1] = t_table[length - 1];
	    t = length - 1;
	    if (t > 0) {
		do {
		    j = length + (k >> 1);
		    if (k & 1) {
			r = s >> 3;
			t_tmp1 = t_table[k];
			t_tmp2 = t_table[j];
			src[r + 2] = (src[r + 2]) | (t_tmp1 & 0xf0);
			src[r + 3] =
			    ((t_tmp1 & 0x0f) << 4) | (t_tmp2 >> 4);
		    } else {
			r = c >> 3;
			t_tmp1 = t_table[k];
			t_tmp2 = t_table[j];
			src[r + 2] = t_tmp1 >> 4;
			src[r + 1] =
			    ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
		    }
		    s += 12;
		    c += 12;
		    k++;
		}
		while (k < t);
	    }
	    free(t_table);
	    break;

	case 13:
	case 15:
	    if (codec == 13) {
		channels = 1;
	    } else {
		channels = 2;
	    }

	    {
		const int MAX_CHANNELS = 2;
		int32 left,
		    startPos, origLeft, curTableEntry, destPos, esiReg;
		int16 firstWord;
		byte sByte[MAX_CHANNELS] = { 0, 0 };
		int32 sDWord1[MAX_CHANNELS] = { 0, 0 };
		int32 sDWord2[MAX_CHANNELS] = { 0, 0 };
		int32 tableEntrySum,
		    imcTableEntry, curTablePos, outputWord, adder;
		byte decompTable, otherTablePos, bitMask;
		byte *readPos, *dst;
		uint16 readWord;

		assert(0 <= channels && channels <= MAX_CHANNELS);

		src = comp_input;
		dst = comp_output;
		if (channels == 2) {
		    output_size = left = 0x2000;
		} else {
		    left = 0x1000;
		    output_size = 0x2000;
		}
		firstWord = READ_BE_UINT16(src);
		src += 2;
		if (firstWord != 0) {
		    memcpy(dst, src, firstWord);
		    dst += firstWord;
		    src += firstWord;
		    startPos = 0;
		    if (channels == 2) {
			left = 0x2000 - firstWord;
			output_size = left;
		    } else {
			left = 0x1000 - (firstWord >> 1);
			output_size = left << 1;
		    }
		} else {
		    startPos = 1;
		    for (int ch = 0; ch < channels; ch++) {
			sByte[ch] = *(src++);
			sDWord1[ch] = READ_BE_UINT32(src);
			src += 4;
			sDWord2[ch] = READ_BE_UINT32(src);
			src += 4;
		    }
		}

		origLeft = left >> (channels - 1);
		tableEntrySum = 0;
		for (int l = 0; l < channels; l++) {
		    if (startPos != 0) {
			curTablePos = sByte[l];
			imcTableEntry = sDWord1[l];
			outputWord = sDWord2[l];
		    } else {
			curTablePos = 0;
			imcTableEntry = 7;
			outputWord = 0;
		    }

		    left = origLeft;
		    destPos = l * 2;

		    if (channels == 2) {
			if (l == 0)
			    left++;
			left >>= 1;
		    }

		    while (left--) {
			curTableEntry = _destImcTable[curTablePos];
			decompTable = (byte) (curTableEntry - 2);
			bitMask = 2 << decompTable;
			readPos = src + (tableEntrySum >> 3);

			if (readPos + 1 >= comp_input + input_size) {
			    if (readPos + 1 > comp_input + input_size ||
				curTableEntry + (tableEntrySum & 7) > 8) {
				printf
				    ("decompressCodec: input buffer overflow: %d bytes over (we need %d bits of data)\n",
				     (int) ((readPos + 1) -
					    (comp_input + input_size)) + 1,
				     curTableEntry + (tableEntrySum & 7));
			    }
			}
			readWord =
			    (uint16) (READ_BE_UINT16(readPos) <<
				      (tableEntrySum & 7));
			otherTablePos =
			    (byte) (readWord >> (16 - curTableEntry));
			tableEntrySum += curTableEntry;
			esiReg =
			    ((imxShortTable[curTableEntry] & otherTablePos)
			     << (7 - curTableEntry)) + (curTablePos << 6);
			imcTableEntry >>= (curTableEntry - 1);
			adder = imcTableEntry + _destImcTable2[esiReg];
			if ((otherTablePos & bitMask) != 0) {
			    adder = -adder;
			}
			outputWord += adder;

			if (outputWord > 0x7fff)
			    outputWord = 0x7fff;
			if (outputWord < -0x8000)
			    outputWord = -0x8000;
			dst[destPos] = ((int16) outputWord) >> 8;
			dst[destPos + 1] = (byte) (outputWord);

			assert(decompTable < 6);
			curTablePos += (signed char)
			    imxOtherTable[decompTable][otherTablePos];
			if (curTablePos > 88)
			    curTablePos = 88;
			if (curTablePos < 0)
			    curTablePos = 0;
			imcTableEntry = imcTable[curTablePos];

			destPos += channels << 1;
		    }
		}
	    }
	    break;

	default:
	    printf("Bundle: Unknown codec %d!\n", (int) codec);
	    output_size = 0;
	    break;
	}

	memcpy(&CompFinal[finalSize], comp_output, output_size);
	finalSize += output_size;

	free(comp_input);
	comp_input = NULL;
	free(comp_output);
	comp_output = NULL;

    }

    ptr = CompFinal;
    tag = READ_BE_UINT32(ptr);
    ptr += 4;
    if (tag != MKID_BE('iMUS')) {
	printf("Decompression of bundle sound failed\n");
	free(CompFinal);
	return 0;
    }

    ptr += 12;			/* Skip header */
    while (tag != MKID_BE('DATA')) {
	tag = READ_BE_UINT32(ptr);
	ptr += 4;
	switch (tag) {
	case MKID_BE('FRMT'):
	    size = READ_BE_UINT32(ptr);
	    ptr += 12;
	    bits = READ_BE_UINT32(ptr);
	    ptr += 4;
	    rate = READ_BE_UINT32(ptr);
	    ptr += 4;
	    chan = READ_BE_UINT32(ptr);
	    ptr += 4;
	    break;
	case MKID_BE('TEXT'):
	case MKID_BE('REGN'):
	case MKID_BE('STOP'):
	case MKID_BE('JUMP'):
	case MKID_BE('SYNC'):
	    size = READ_BE_UINT32(ptr);
	    ptr += size + 4;
	    break;

	case MKID_BE('DATA'):
	    size = READ_BE_UINT32(ptr);
	    ptr += 4;
	    break;

	default:
	    printf("Unknown bundle header %c%c%c%c\n", tag >> 24,
		   tag >> 16, tag >> 8, tag);
	}
    }

    if (bits == 12) {
	s_size = (size * 4) / 3 + 3;
	buffer = (byte *) malloc(s_size);
	uint32 l = 0, ra = 0, tmp;
	for (; l < size; l += 3) {
	    tmp = (ptr[l + 1] & 0x0f) << 8;
	    tmp = (tmp | ptr[l + 0]) << 4;
	    tmp -= 0x8000;
	    buffer[ra++] = (uint8) (tmp & 0xff);
	    buffer[ra++] = (uint8) ((tmp >> 8) & 0xff);

	    tmp = (ptr[l + 1] & 0xf0) << 4;
	    tmp = (tmp | ptr[l + 2]) << 4;
	    tmp -= 0x8000;
	    buffer[ra++] = (uint8) (tmp & 0xff);
	    buffer[ra++] = (uint8) ((tmp >> 8) & 0xff);
	}
	bits = 16;
    } else {
	size &= ~1;
	voice = 1;
	s_size = size;
	buffer = (byte *) malloc(s_size);
    }

	byte wav[44];
	memset (wav, 0, 44);
	wav[0] = 'R';
	wav[1] = 'I';
	wav[2] = 'F';
	wav[3] = 'F';
	wav[4] = (s_size + 36) & 0xff;
	wav[5] = ((s_size + 36) >> 8) & 0xff;
	wav[6] = ((s_size + 36) >> 16) & 0xff;
	wav[7] = ((s_size + 36) >> 24) & 0xff;
	wav[8] = 'W';
	wav[9] = 'A';
	wav[10] = 'V';
	wav[11] = 'E';
	wav[12] = 'f';
	wav[13] = 'm';
	wav[14] = 't';
	wav[15] = ' ';
	wav[16] = 16;
	wav[20] = 1;
	wav[22] = chan;
	wav[24] = rate & 0xff;
	wav[25] = (rate >> 8) & 0xff;
	wav[26] = (rate >> 16) & 0xff;
	wav[27] = (rate >> 24) & 0xff;
	wav[28] = (rate * chan * (bits / 8)) & 0xff;
	wav[29] = ((rate * chan * (bits / 8))>> 8) & 0xff;
	wav[30] = ((rate * chan * (bits / 8)) >> 16) & 0xff;
	wav[31] = ((rate * chan * (bits / 8)) >> 24) & 0xff;
	wav[32] = (chan * (bits / 8)) & 0xff;
	wav[33] = ((chan * (bits / 8)) >> 8) & 0xff;
	wav[34] = bits;
	wav[36] = 'd';
	wav[37] = 'a';
	wav[38] = 't';
	wav[39] = 'a';
	wav[40] = s_size & 0xff;
	wav[41] = (s_size >> 8) & 0xff;
	wav[42] = (s_size >> 16) & 0xff;
	wav[43] = (s_size >> 24) & 0xff;

	//memcpy(buffer, wav, 44);

	if (voice)
		memcpy(buffer, ptr, s_size);
	
	free(CompFinal);
	CompFinal = NULL;

	if (save) {
		_output.write(buffer, s_size+44);
		_output.close();
	} else {
		if (bits == 8) {
			_mixer->playRaw(NULL, buffer, s_size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE, -1, 255);
		} else if (bits == 16) {
			_mixer->playRaw(NULL, buffer, s_size, rate, SoundMixer::FLAG_16BITS | SoundMixer::FLAG_AUTOFREE, -1, 255);
		}
	}

    return 0;
}

--- NEW FILE: sound.h ---
/* ScummEX - Viewer for Scumm data files
 * Copyright (C) 2003 Adrien Mercier
 * Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/sound.h,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

#ifndef sound_h
#define sound_h

#include "scummsys.h"
#include "file.h"
#include "resource.h"
#include "wxwindows.h"
#include "sound/mixer.h"

struct CompTable {
	int32 offset;
	int32 size;
	int32 codec;
};

class Sound {
private:
	SoundMixer *_mixer;
	Resource *_resource;

	static int32 compDecode(byte * src, byte * dst);
	void initializeImcTables();

public:
	Sound();
	~Sound();
	int playiMUSE(File& _input, BlockTable *_blockTable, int index, File& _output, int save = 0);
	int playSOU(BlockTable *_blockTable, File& _input, int index, File& _output, int save = 0);

};

#endif

--- NEW FILE: voc.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 * Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/voc.cpp,v 1.1 2003/09/28 21:49:25 yoshizf Exp $
 *
 */

#include "stdafx.h"
#include "util.h"
#include "voc.h"


int getSampleRateFromVOCRate(int vocSR) {
	if (vocSR == 0xa5 || vocSR == 0xa6) {
		return 11025;
	} else if (vocSR == 0xd2 || vocSR == 0xd3) {
		return 22050;
	} else {
		int sr = 1000000L / (256L - vocSR);
		return sr;
	}
}

--- NEW FILE: voc.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 * Copyright (C) 2001-2003 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummex/sound/voc.h,v 1.1 2003/09/28 21:49:26 yoshizf Exp $
 *
 */

#ifndef SOUND_VOC_H
#define SOUND_VOC_H

#include "stdafx.h"
#include "scummsys.h"

#if !defined(__GNUC__)
#pragma START_PACK_STRUCTS
#endif

struct VocHeader {
	uint8 desc[20];
	uint16 datablock_offset;
	uint16 version;
	uint16 id;
} GCC_PACK;

struct VocBlockHeader {
	uint8 blocktype;
	uint8 size[3];
	uint8 sr;
	uint8 pack;
} GCC_PACK;

#if !defined(__GNUC__)
#pragma END_PACK_STRUCTS
#endif

/**
 * Take a sample rate parameter as it occurs in a VOC sound header, and
 * return the corresponding sample frequency.
 */
extern int getSampleRateFromVOCRate(int vocSR);

#endif





More information about the Scummvm-git-logs mailing list