Index: source.list
===================================================================
--- source.list	(revision 11812)
+++ source.list	(working copy)
@@ -34,7 +34,6 @@
 md5.cpp
 minilzo.cpp
 misc.cpp
-mixer.cpp
 music.cpp
 namegen.cpp
 network/network.cpp
@@ -394,6 +393,23 @@
 misc/str.hpp
 misc/strapi.hpp
 
+# Mixer
+mixer/array.hpp
+mixer/audiostream.cpp
+mixer/audiostream.hpp
+mixer/file.cpp
+mixer/file.hpp
+mixer/mixer.cpp
+mixer/mixer.hpp
+mixer/rate.cpp
+mixer/rate.hpp
+mixer/str.cpp
+mixer/str.hpp
+mixer/stream.cpp
+mixer/stream.hpp
+mixer/wave.cpp
+mixer/wave.hpp
+
 # Network Core
 network/core/config.h
 network/core/core.cpp
Index: src/mixer.cpp
===================================================================
--- src/mixer.cpp	(revision 11812)
+++ src/mixer.cpp	(working copy)
@@ -1,142 +0,0 @@
-/* $Id$ */
-
-/** @file mixer.cpp*/
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "mixer.h"
-
-struct MixerChannel {
-	bool active;
-
-	/* pointer to allocated buffer memory */
-	int8 *memory;
-
-	/* current position in memory */
-	uint32 pos;
-	uint32 frac_pos;
-	uint32 frac_speed;
-	uint32 samples_left;
-
-	/* Mixing volume */
-	uint volume_left;
-	uint volume_right;
-
-	uint flags;
-};
-
-static MixerChannel _channels[8];
-static uint32 _play_rate;
-
-
-static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
-{
-	int8 *b;
-	uint32 frac_pos;
-	uint32 frac_speed;
-	uint volume_left;
-	uint volume_right;
-
-	if (samples > sc->samples_left) samples = sc->samples_left;
-	sc->samples_left -= samples;
-	assert(samples > 0);
-
-	b = sc->memory + sc->pos;
-	frac_pos = sc->frac_pos;
-	frac_speed = sc->frac_speed;
-	volume_left = sc->volume_left;
-	volume_right = sc->volume_right;
-
-	if (frac_speed == 0x10000) {
-		/* Special case when frac_speed is 0x10000 */
-		do {
-			buffer[0] += *b * volume_left >> 8;
-			buffer[1] += *b * volume_right >> 8;
-			b++;
-			buffer += 2;
-		} while (--samples > 0);
-	} else {
-		do {
-			buffer[0] += *b * volume_left >> 8;
-			buffer[1] += *b * volume_right >> 8;
-			buffer += 2;
-			frac_pos += frac_speed;
-			b += frac_pos >> 16;
-			frac_pos &= 0xffff;
-		} while (--samples > 0);
-	}
-
-	sc->frac_pos = frac_pos;
-	sc->pos = b - sc->memory;
-}
-
-static void MxCloseChannel(MixerChannel *mc)
-{
-	if (mc->flags & MX_AUTOFREE) free(mc->memory);
-	mc->active = false;
-	mc->memory = NULL;
-}
-
-void MxMixSamples(void *buffer, uint samples)
-{
-	MixerChannel *mc;
-
-	/* Clear the buffer */
-	memset(buffer, 0, sizeof(int16) * 2 * samples);
-
-	/* Mix each channel */
-	for (mc = _channels; mc != endof(_channels); mc++) {
-		if (mc->active) {
-			mix_int8_to_int16(mc, (int16*)buffer, samples);
-			if (mc->samples_left == 0) MxCloseChannel(mc);
-		}
-	}
-}
-
-MixerChannel *MxAllocateChannel()
-{
-	MixerChannel *mc;
-	for (mc = _channels; mc != endof(_channels); mc++)
-		if (mc->memory == NULL) {
-			mc->active = false;
-			return mc;
-		}
-	return NULL;
-}
-
-void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags)
-{
-	mc->memory = mem;
-	mc->flags = flags;
-	mc->frac_pos = 0;
-	mc->pos = 0;
-
-	mc->frac_speed = (rate << 16) / _play_rate;
-
-	/* adjust the magnitude to prevent overflow */
-	while (size & 0xFFFF0000) {
-		size >>= 1;
-		rate = (rate >> 1) + 1;
-	}
-
-	mc->samples_left = size * _play_rate / rate;
-}
-
-void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
-{
-	mc->volume_left = left;
-	mc->volume_right = right;
-}
-
-
-void MxActivateChannel(MixerChannel* mc)
-{
-	mc->active = true;
-}
-
-
-bool MxInitialize(uint rate)
-{
-	_play_rate = rate;
-	return true;
-}
Index: src/mixer.h
===================================================================
--- src/mixer.h	(revision 11812)
+++ src/mixer.h	(working copy)
@@ -1,25 +0,0 @@
-/* $Id$ */
-
-/** @file mixer.h */
-
-#ifndef MIXER_H
-#define MIXER_H
-
-struct MixerChannel;
-
-enum {
-	MX_AUTOFREE = 1,
-//	MX_8BIT = 2,
-//	MX_STEREO = 4,
-//	MX_UNSIGNED = 8,
-};
-
-bool MxInitialize(uint rate);
-void MxMixSamples(void *buffer, uint samples);
-
-MixerChannel *MxAllocateChannel();
-void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags);
-void MxSetChannelVolume(MixerChannel *mc, uint left, uint right);
-void MxActivateChannel(MixerChannel*);
-
-#endif /* MIXER_H */
Index: src/mixer/audiostream.cpp
===================================================================
--- src/mixer/audiostream.cpp	(revision 0)
+++ src/mixer/audiostream.cpp	(revision 0)
@@ -0,0 +1,305 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+ 
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../driver.h"
+#include "../sound/sound_driver.hpp"
+#include "../misc/blob.hpp"
+#include "../core/math_func.hpp"
+#include "../core/endian_func.hpp"
+
+#include "str.hpp"
+#include "stream.hpp"
+#include "wave.hpp"
+#include "file.hpp"
+#include "mixer.hpp"
+#include "rate.hpp"
+#include "audiostream.hpp"
+
+// 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.
+
+#if defined(TTD_BIG_ENDIAN)
+	FORCEINLINE uint16 READ_LE_UINT16(const void *ptr) {
+		const byte *b = (const byte *)ptr;
+		return (b[1] << 8) + b[0];
+	}
+	FORCEINLINE uint32 READ_LE_UINT32(const void *ptr) {
+		const byte *b = (const byte *)ptr;
+		return (b[3] << 24) + (b[2] << 16) + (b[1] << 8) + (b[0]);
+	}
+	FORCEINLINE void WRITE_LE_UINT16(void *ptr, uint16 value) {
+		byte *b = (byte *)ptr;
+		b[0] = (byte)(value >> 0);
+		b[1] = (byte)(value >> 8);
+	}
+	FORCEINLINE void WRITE_LE_UINT32(void *ptr, uint32 value) {
+		byte *b = (byte *)ptr;
+		b[0] = (byte)(value >>  0);
+		b[1] = (byte)(value >>  8);
+		b[2] = (byte)(value >> 16);
+		b[3] = (byte)(value >> 24);
+	}
+
+	FORCEINLINE uint16 READ_BE_UINT16(const void *ptr) {
+		return *(const uint16 *)(ptr);
+	}
+	FORCEINLINE uint32 READ_BE_UINT32(const void *ptr) {
+		return *(const uint32 *)(ptr);
+	}
+	FORCEINLINE void WRITE_BE_UINT16(void *ptr, uint16 value) {
+		*(uint16 *)(ptr) = value;
+	}
+	FORCEINLINE void WRITE_BE_UINT32(void *ptr, uint32 value) {
+		*(uint32 *)(ptr) = value;
+	}
+#else
+	FORCEINLINE uint16 READ_LE_UINT16(const void *ptr) {
+		return *(const uint16 *)(ptr);
+	}
+	FORCEINLINE uint32 READ_LE_UINT32(const void *ptr) {
+		return *(const uint32 *)(ptr);
+	}
+	FORCEINLINE void WRITE_LE_UINT16(void *ptr, uint16 value) {
+		*(uint16 *)(ptr) = value;
+	}
+	FORCEINLINE void WRITE_LE_UINT32(void *ptr, uint32 value) {
+		*(uint32 *)(ptr) = value;
+	}
+
+	FORCEINLINE uint16 READ_BE_UINT16(const void *ptr) {
+		const byte *b = (const byte *)ptr;
+		return (b[0] << 8) + b[1];
+	}
+	FORCEINLINE uint32 READ_BE_UINT32(const void *ptr) {
+		const byte *b = (const byte*)ptr;
+		return (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + (b[3]);
+	}
+	FORCEINLINE void WRITE_BE_UINT16(void *ptr, uint16 value) {
+		byte *b = (byte *)ptr;
+		b[0] = (byte)(value >> 8);
+		b[1] = (byte)(value >> 0);
+	}
+	FORCEINLINE void WRITE_BE_UINT32(void *ptr, uint32 value) {
+		byte *b = (byte *)ptr;
+		b[0] = (byte)(value >> 24);
+		b[1] = (byte)(value >> 16);
+		b[2] = (byte)(value >>  8);
+		b[3] = (byte)(value >>  0);
+	}
+#endif
+
+#define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \
+	((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
+
+
+struct StreamFileFormat {
+	/** Decodername */
+	const char* decoderName;
+	const char* fileExtension;
+	/**
+	 * Pointer to a function which tries to open a file of type StreamFormat.
+	 * Return NULL in case of an error (invalid/nonexisting file).
+	 */
+	AudioStream* (*openStreamFile)(SeekableReadStream *stream, bool disposeAfterUse,
+					uint32 startTime, uint32 duration, uint numLoops);
+};
+
+static const StreamFileFormat STREAM_FILEFORMATS[] = {
+	/* decoderName,		fileExt, openStreamFuntion */
+	{ "PCM Wave",		"wav", makeWAVStream },
+#ifdef USE_FLAC
+	{ "FLAC",			"flac", makeFlacStream },
+	{ "FLAC",			"fla",  makeFlacStream },
+#endif
+#ifdef USE_VORBIS
+	{ "Ogg Vorbis",		"ogg",  makeVorbisStream },
+#endif
+#ifdef USE_MAD
+	{ "MPEG Layer 3",	"mp3",  makeMP3Stream },
+	{ "MPEG Layer 3",	"mpga",  makeMP3Stream },
+#endif
+
+	{ NULL, NULL, NULL } // Terminator
+};
+
+static int Music_GetFormat(const char *filename)
+{
+	char *aext;
+	int i;
+
+	aext = (char *) strrchr(filename, '.');
+
+	if (aext == NULL)
+		return(-1);
+	else
+		aext++; // point to extension without the dot
+
+	for (i = 0; i < lengthof(STREAM_FILEFORMATS)-1; i++)
+	{
+		if (strcasecmp(STREAM_FILEFORMATS[i].fileExtension, aext) == 0)
+			return(i);
+	}
+
+	return(-1);
+}
+
+AudioStream* AudioStream::openStreamFile(const String &basename, uint32 startTime, uint32 duration, uint numLoops) {
+	AudioStream* stream = NULL;
+	File *fileHandle = new File();
+
+	int format = Music_GetFormat(basename.c_str());
+
+	if (format == -1)
+	{
+		DEBUG(misc, 1, "AudioStream: Could not find decoder for file '%s'", basename.c_str());
+		return NULL;
+	}
+
+	fileHandle->open(basename);
+
+	if (fileHandle->isOpen())
+	{
+		// Create the stream object
+		stream = STREAM_FILEFORMATS[format].openStreamFile(fileHandle, true, startTime, duration, numLoops);
+
+		if (stream == NULL) {
+			DEBUG(misc, 1, "AudioStream: Could not open compressed AudioFile %s", basename.c_str());
+		}
+	}
+
+	delete fileHandle;
+	return stream;
+}
+
+
+/**
+ * A simple raw audio stream, purely memory based. It operates on a single
+ * block of data, which is passed to it upon creation.
+ * Optionally supports looping the sound.
+ *
+ * Design note: This code tries to be as efficient as possible (without
+ * resorting to assembly, that is). To this end, it is written as a template
+ * class. This way the compiler can create optimized code for each special
+ * case. This results in a total of 12 versions of the code being generated.
+ */
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+class LinearMemoryStream : public AudioStream {
+protected:
+	const byte *_ptr;
+	const byte *_end;
+	const byte *_loopPtr;
+	const byte *_loopEnd;
+	const int _rate;
+	const byte *_origPtr;
+
+public:
+	LinearMemoryStream(int rate, const byte *ptr, uint len, uint loopOffset, uint loopLen, bool autoFreeMemory)
+		: _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0), _rate(rate) {
+
+		// 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);
+
+		_origPtr = autoFreeMemory ? ptr : 0;
+	}
+	~LinearMemoryStream() {
+		free(const_cast<byte *>(_origPtr));
+	}
+	int readBuffer(int16 *buffer, const int numSamples);
+
+	bool isStereo() const		{ return stereo; }
+	bool endOfData() const		{ return _ptr >= _end; }
+
+	int getRate() const			{ return _rate; }
+};
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+int LinearMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
+	int samples = 0;
+	while (samples < numSamples && _ptr < _end) {
+		const int len = min(numSamples, samples + (int)(_end - _ptr) / (is16Bit ? 2 : 1));
+		while (samples < len) {
+			*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
+			_ptr += (is16Bit ? 2 : 1);
+			samples++;
+		}
+		// Loop, if looping was specified
+		if (_loopPtr && _ptr >= _end) {
+			_ptr = _loopPtr;
+			_end = _loopEnd;
+		}
+	}
+	return samples;
+}
+
+
+/* In the following, we use preprocessor / macro tricks to simplify the code
+ * which instantiates the input streams. We used to use template functions for
+ * this, but MSVC6 / EVC 3-4 (used for WinCE builds) are extremely buggy when it
+ * comes to this feature of C++... so as a compromise we use macros to cut down
+ * on the (source) code duplication a bit.
+ * So while normally macro tricks are said to make maintenance harder, in this
+ * particular case it should actually help it :-)
+ */
+
+#define MAKE_LINEAR(STEREO, UNSIGNED) \
+		if (is16Bit) { \
+			if (isLE) \
+				return new LinearMemoryStream<STEREO, true, UNSIGNED, true>(rate, ptr, len, loopOffset, loopLen, autoFree); \
+			else  \
+				return new LinearMemoryStream<STEREO, true, UNSIGNED, false>(rate, ptr, len, loopOffset, loopLen, autoFree); \
+		} else \
+			return new LinearMemoryStream<STEREO, false, UNSIGNED, false>(rate, ptr, len, loopOffset, loopLen, autoFree)
+
+AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte flags, uint loopStart, uint loopEnd) {
+	const bool isStereo   = (flags & Mixer::FLAG_STEREO) != 0;
+	const bool is16Bit    = (flags & Mixer::FLAG_16BITS) != 0;
+	const bool isUnsigned = (flags & Mixer::FLAG_UNSIGNED) != 0;
+	const bool isLE       = (flags & Mixer::FLAG_LITTLE_ENDIAN) != 0;
+	const bool autoFree   = (flags & Mixer::FLAG_AUTOFREE) != 0;
+
+	uint loopOffset = 0, loopLen = 0;
+	if (flags & Mixer::FLAG_LOOP) {
+		if (loopEnd == 0)
+			loopEnd = len;
+		assert(loopStart <= loopEnd);
+		assert(loopEnd <= len);
+			
+		loopOffset = loopStart;
+		loopLen = loopEnd - loopStart;
+	}
+
+	if (isStereo) {
+		if (isUnsigned) {
+			MAKE_LINEAR(true, true);
+		} else {
+			MAKE_LINEAR(true, false);
+		}
+	} else {
+		if (isUnsigned) {
+			MAKE_LINEAR(false, true);
+		} else {
+			MAKE_LINEAR(false, false);
+		}
+	}
+}

Property changes on: src\mixer\audiostream.cpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/audiostream.hpp
===================================================================
--- src/mixer/audiostream.hpp	(revision 0)
+++ src/mixer/audiostream.hpp	(revision 0)
@@ -0,0 +1,88 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+#ifndef SOUND_AUDIOSTREAM_H
+#define SOUND_AUDIOSTREAM_H
+
+#include "str.hpp"
+
+/**
+ * Generic audio input stream. Subclasses of this are used to feed arbitrary
+ * sampled audio data into ScummVM's audio mixer.
+ */
+class AudioStream {
+public:
+	virtual ~AudioStream() {}
+
+	/**
+	 * 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
+	 * happen when the stream is fully used up).
+	 *
+	 * Data has to be in native endianess, 16 bit per sample, signed.
+	 * For stereo stream, buffer will be filled with interleaved
+	 * left and right channel samples, starting with a left sample.
+	 * Furthermore, the samples in the left and right are summed up.
+	 * So if you request 4 samples from a stereo stream, you will get
+	 * a total of two left channel and two right channel samples.
+	 */
+	virtual int readBuffer(int16 *buffer, const int numSamples) = 0;
+
+	/** Is this a stereo stream? */
+	virtual bool isStereo() const = 0;
+
+	/**
+	 * End of data reached? If this returns true, it means that at this
+	 * time there is no data available in the stream. However there may be
+	 * more data in the future.
+	 * This is used by e.g. a rate converter to decide whether to keep on
+	 * converting data or stop.
+	 */
+	virtual bool endOfData() const = 0;
+
+	/**
+	 * End of stream reached? If this returns true, it means that all data
+	 * in this stream is used up and no additional data will appear in it
+	 * in the future.
+	 * This is used by the mixer to decide whether a given stream shall be
+	 * removed from the list of active streams (and thus be destroyed).
+	 * By default this maps to endOfData()
+	 */
+	virtual bool endOfStream() const { return endOfData(); }
+
+	/** Sample rate of the stream. */
+	virtual int getRate() const = 0;
+
+	/**
+	 * Tries to load a file by trying all available formats.
+	 * In case of an error, the file handle will be closed, but deleting
+	 * it is still the responsibilty of the caller.
+	 * @param basename	a filename without an extension
+	 * @param startTime	the (optional) time offset in milliseconds from which to start playback 
+	 * @param duration	the (optional) time in milliseconds specifying how long to play
+	 * @param numLoops	how often the data shall be looped (0 = infinite)
+	 * @return	an Audiostream ready to use in case of success;
+	 *			NULL in case of an error (e.g. invalid/nonexisting file)
+	 */
+	static AudioStream* openStreamFile(const String &basename, uint32 startTime = 0, uint32 duration = 0, uint numLoops = 1);
+};
+
+/**
+ * Factory function for a raw linear AudioStream, which will simply treat all data
+ * in the buffer described by ptr and len as raw sample data in the specified
+ * format. It will then simply pass this data directly to the mixer, after converting
+ * it to the sample format used by the mixer (i.e. 16 bit signed native endian).
+ * Optionally supports (infinite) looping of a portion of the data.
+ */
+AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte flags, uint loopStart, uint loopEnd);
+
+
+#endif

Property changes on: src\mixer\audiostream.hpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/file.cpp
===================================================================
--- src/mixer/file.cpp	(revision 0)
+++ src/mixer/file.cpp	(revision 0)
@@ -0,0 +1,270 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+#include <ctype.h>
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../driver.h"
+#include "stream.hpp"
+#include "str.hpp"
+#include "file.hpp"
+
+#if defined(WIN32) && defined(UNICODE)
+	#include <windows.h>
+#endif
+
+#ifdef MACOSX
+#include "CoreFoundation/CoreFoundation.h"
+#endif
+
+static FILE *fopenNoCase(const String &filename, const String &directory, const char *mode) {
+	FILE *file;
+	String buf(directory);
+	uint i;
+
+#if !defined(__GP32__) && !defined(PALMOS_MODE)
+	// Add a trailing slash, if necessary.
+	if (!buf.empty()) {
+		const char c = buf.lastChar();
+		if (c != ':' && c != '/' && c != '\\')
+			buf += '/';
+	}
+#endif
+
+	// Append the filename to the path string
+	const int offsetToFileName = buf.size();
+	buf += filename;
+
+#if defined(WIN32) && defined(UNICODE)
+	/* fopen is implemented as a define with ellipses for
+	 * Unicode support (prepend an L). As we are not sending
+	 * a string, but a variable, it 'renames' the variable,
+	 * so make that variable to makes it compile happily */
+	wchar_t Lmode[5];
+	MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, lengthof(Lmode));
+#endif
+
+	//
+	// Try to open the file normally
+	//
+	file = fopen(buf.c_str(), mode);
+
+	//
+	// Try again, with file name converted to upper case
+	//
+	if (!file) {
+		for (i = offsetToFileName; i < buf.size(); ++i) {
+			buf[i] = toupper(buf[i]);
+		}
+		file = fopen(buf.c_str(), mode);
+	}
+
+	//
+	// Try again, with file name converted to lower case
+	//
+	if (!file) {
+		for (i = offsetToFileName; i < buf.size(); ++i) {
+			buf[i] = tolower(buf[i]);
+		}
+		file = fopen(buf.c_str(), mode);
+	}
+
+	//
+	// Try again, with file name capitalized
+	//
+	if (!file) {
+		i = offsetToFileName;
+		buf[i] = toupper(buf[i]);
+		file = fopen(buf.c_str(), mode);
+	}
+
+#ifdef __amigaos4__
+	//
+	// Work around for possibility that someone uses AmigaOS "newlib" build with SmartFileSystem (blocksize 512 bytes), leading
+	// to buffer size being only 512 bytes. "Clib2" sets the buffer size to 8KB, resulting smooth movie playback. This forces the buffer
+	// to be enough also when using "newlib" compile on SFS.
+	//
+	if (file) {
+		setvbuf(file, NULL, _IOFBF, 8192);
+	}
+#endif
+
+	return file;
+}
+
+File::File()
+	: _handle(0), _ioFailed(false) {
+}
+
+File::~File() {
+#ifdef DEBUG_FILE_REFCOUNT
+	warning("File::~File on file '%s'", _name.c_str());
+#endif
+	close();
+}
+
+
+bool File::open(const String &filename, AccessMode mode) {
+	assert(mode == kFileReadMode || mode == kFileWriteMode);
+
+	if (filename.empty()) {
+		error("File::open: No filename was specified");
+	}
+
+	if (_handle) {
+		error("File::open: This file object already is opened (%s), won't open '%s'", _name.c_str(), filename.c_str());
+	}
+
+	_name.clear();
+	clearIOFailed();
+
+	String fname(filename);
+	fname.toLowercase();
+
+	const char *modeStr = (mode == kFileReadMode) ? "rb" : "wb";
+	_handle = fopenNoCase(filename, "", modeStr); // TODO: Integrate OpenTTD file checking thingy somehow?
+
+	if (_handle == NULL) {
+		if (mode == kFileReadMode)
+			DEBUG(misc, 1, "File %s not found", filename.c_str());
+		else
+			DEBUG(misc, 1, "File %s not opened", filename.c_str());
+		return false;
+	}
+
+
+	_name = filename;
+
+#ifdef DEBUG_FILE_REFCOUNT
+	warning("File::open on file '%s'", _name.c_str());
+#endif
+
+	return true;
+}
+
+bool File::exists(const String &filename) {
+	// Next, try to locate the file by *opening* it in read mode. This has
+	// multiple effects:
+	// 1) It takes _filesMap and _defaultDirectories into consideration -> good
+	// 2) It returns true if and only if File::open is possible on the file -> good
+	// 3) If this method is misused, it could lead to an fopen call on a directory
+	//    -> bad!
+	// 4) It also checks whether we can read the file. This is not 100%
+	//    desirable; after all, even when we can't read it, the file is present.
+	//    Since this method is often used to check whether a file should be
+	//    re-created, that's not nice.
+	//
+	// TODO/FIXME: We should clarify the semantics of this method, and then
+	// maybe should introduce several new methods:
+	//   fileExistsAndReadable
+	//   fileExists
+	//   fileExistsAtPath
+	//   dirExists
+	//   dirExistsAtPath
+	// or maybe only 1-2 methods which take some params :-).
+	
+	File tmp;
+	return tmp.open(filename, kFileReadMode);
+}
+
+void File::close() {
+	if (_handle)
+		fclose((FILE *)_handle);
+	_handle = NULL;
+}
+
+bool File::isOpen() const {
+	return _handle != NULL;
+}
+
+bool File::ioFailed() const {
+	return _ioFailed != 0;
+}
+
+void File::clearIOFailed() {
+	_ioFailed = false;
+}
+
+bool File::eof() const {
+	if (_handle == NULL) {
+		error("File::eof: File is not open!");
+		return false;
+	}
+
+	return feof((FILE *)_handle) != 0;
+}
+
+uint32 File::pos() const {
+	if (_handle == NULL) {
+		error("File::pos: File is not open!");
+		return 0;
+	}
+
+	return ftell((FILE *)_handle);
+}
+
+uint32 File::size() const {
+	if (_handle == NULL) {
+		error("File::size: File is not open!");
+		return 0;
+	}
+
+	uint32 oldPos = ftell((FILE *)_handle);
+	fseek((FILE *)_handle, 0, SEEK_END);
+	uint32 length = ftell((FILE *)_handle);
+	fseek((FILE *)_handle, oldPos, SEEK_SET);
+
+	return length;
+}
+
+void File::seek(int32 offs, int whence) {
+	if (_handle == NULL) {
+		error("File::seek: File is not open!");
+		return;
+	}
+
+	if (fseek((FILE *)_handle, offs, whence) != 0)
+		clearerr((FILE *)_handle);
+}
+
+uint32 File::read(void *ptr, uint32 len) {
+	byte *ptr2 = (byte *)ptr;
+	uint32 real_len;
+
+	if (_handle == NULL) {
+		error("File::read: File is not open!");
+		return 0;
+	}
+
+	if (len == 0)
+		return 0;
+
+	real_len = fread(ptr2, 1, len, (FILE *)_handle);
+	if (real_len < len) {
+		_ioFailed = true;
+	}
+
+	return real_len;
+}
+
+uint32 File::write(const void *ptr, uint32 len) {
+	if (_handle == NULL) {
+		error("File::write: File is not open!");
+		return 0;
+	}
+
+	if (len == 0)
+		return 0;
+
+	if ((uint32)fwrite(ptr, 1, len, (FILE *)_handle) != len) {
+		_ioFailed = true;
+	}
+
+	return len;
+}

Property changes on: src\mixer\file.cpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/file.hpp
===================================================================
--- src/mixer/file.hpp	(revision 0)
+++ src/mixer/file.hpp	(revision 0)
@@ -0,0 +1,88 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+
+#ifndef COMMON_FILE_H
+#define COMMON_FILE_H
+
+class File : public SeekableReadStream, public WriteStream {
+protected:
+	/** File handle to the actual file; 0 if no file is open. */
+	void *_handle;
+
+	/** Status flag which tells about recent I/O failures. */
+	bool _ioFailed;
+
+	/** The name of this file, for debugging. */
+	String _name;
+
+private:
+	// Disallow copying File objects. There is not strict reason for this,
+	// except that so far we never had real need for such a feature, and
+	// code that accidentally copied File objects tended to break in strange
+	// ways.
+	File(const File &f);
+	File &operator  =(const File &f);
+
+public:
+	enum AccessMode {
+		kFileReadMode = 1,
+		kFileWriteMode = 2
+	};
+
+	File();
+	virtual ~File();
+
+	/**
+	 * Checks if a given file exists in any of the current default paths
+	 * (those were/are added by addDefaultDirectory and/or
+	 * addDefaultDirectoryRecursive).
+	 *
+	 * @param filename: the file to check for
+	 * @return: true if the file exists, else false
+	 */
+	static bool exists(const String &filename);
+
+	virtual bool open(const String &filename, AccessMode mode = kFileReadMode);
+
+	virtual void close();
+
+	/**
+	 * Checks if the object opened a file successfully.
+	 *
+	 * @return: true if any file is opened, false otherwise.
+	 */
+	bool isOpen() const;
+
+	/**
+	 * Returns the filename of the opened file.
+	 *
+	 * @return: the filename
+	 */
+	const char *name() const { return _name.c_str(); }
+
+	bool ioFailed() const;
+	void clearIOFailed();
+	bool eos() const { return eof(); }
+
+	/**
+	 * Checks for end of file.
+	 *
+	 * @return: true if the end of file is reached, false otherwise.
+	 */
+	bool eof() const;
+
+	uint32 pos() const;
+	uint32 size() const;
+	void seek(int32 offs, int whence = SEEK_SET);
+	uint32 read(void *dataPtr, uint32 dataSize);
+	uint32 write(const void *dataPtr, uint32 dataSize);
+};
+
+#endif

Property changes on: src\mixer\file.hpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/mixer.cpp
===================================================================
--- src/mixer/mixer.cpp	(revision 0)
+++ src/mixer/mixer.cpp	(revision 0)
@@ -0,0 +1,420 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../driver.h"
+#include "../sound/sound_driver.hpp"
+#include "mixer.hpp"
+#include "rate.hpp"
+#include "audiostream.hpp"
+
+/**
+ * Channels used by the sound mixer.
+ */
+class Channel {
+public:
+	const Mixer::SoundType	_type;
+	SoundHandle _handle;
+private:
+	Mixer *_mixer;
+	bool _autofreeStream;
+	bool _permanent;
+	byte _volume;
+	int8 _balance;
+	bool _paused;
+	int _id;
+	uint32 _samplesConsumed;
+	uint32 _samplesDecoded;
+	uint32 _mixerTimeStamp;
+
+protected:
+	RateConverter *_converter;
+	AudioStream *_input;
+
+public:
+	Channel(Mixer *mixer, Mixer::SoundType type, AudioStream *input, bool autofreeStream, bool reverseStereo = false, int id = -1, bool permanent = false);
+	virtual ~Channel();
+
+	void mix(int16 *data, uint len);
+
+	bool isPermanent() const {
+		return _permanent;
+	}
+	bool isFinished() const {
+		return _input->endOfStream();
+	}
+	void pause(bool paused) {
+		_paused = paused;
+	}
+	bool isPaused() {
+		return _paused;
+	}
+	void setVolume(const byte volume) {
+		_volume = volume;
+	}
+	void setBalance(const int8 balance) {
+		_balance = balance;
+	}
+	int getId() const {
+		return _id;
+	}
+	uint32 getElapsedTime();
+};
+
+
+Mixer::Mixer() {
+	_handleSeed = 0;
+
+	int i = 0;
+
+	for (i = 0; i < _MIXER_NUM_SOUND_TYPES; i++)
+		_volumeForSoundType[i] = kMaxMixerVolume;
+
+	for (i = 0; i != NUM_CHANNELS; i++)
+		_channels[i] = 0;
+
+	_mixerReady = false;
+}
+
+Mixer::~Mixer() {
+	for (int i = 0; i != NUM_CHANNELS; i++)
+		delete _channels[i];
+}
+
+uint Mixer::getOutputRate() const {
+	return _sound_driver->GetSampleRate();
+}
+
+void Mixer::insertChannel(SoundHandle *handle, Channel *chan) {
+
+	int index = -1;
+	for (int i = 0; i != NUM_CHANNELS; i++) {
+		if (_channels[i] == 0) {
+			index = i;
+			break;
+		}
+	}
+	if (index == -1) {
+		DEBUG(misc, 1, "Mixer::out of mixer slots");
+		delete chan;
+		return;
+	}
+
+	_channels[index] = chan;
+	 chan->_handle._val = index + (_handleSeed * NUM_CHANNELS);
+	_handleSeed++;
+	if (handle) {
+		*handle = chan->_handle;
+	}
+}
+
+void Mixer::playRaw(
+			SoundType type,
+			SoundHandle *handle,
+			void *sound,
+			uint32 size, uint rate, byte flags,
+			int id, byte volume, int8 balance,
+			uint32 loopStart, uint32 loopEnd) {
+
+	// Create the input stream
+	AudioStream *input = makeLinearInputStream((byte *)sound, size, rate, flags, loopStart, loopEnd);
+	
+	// Play it
+	playInputStream(type, handle, input, id, volume, balance, true, false, ((flags & Mixer::FLAG_REVERSE_STEREO) != 0));
+}
+
+void Mixer::playInputStream(
+			SoundType type,
+			SoundHandle *handle,
+			AudioStream *input,
+			int id, byte volume, int8 balance,
+			bool autofreeStream,
+			bool permanent,
+			bool reverseStereo) {
+	//Common::StackLock lock(_mutex);
+
+	if (input == 0) {
+		DEBUG(misc, 1, "mixer: input stream is 0");
+		return;
+	}
+
+	// Prevent duplicate sounds
+	if (id != -1) {
+		for (int i = 0; i != NUM_CHANNELS; i++)
+			if (_channels[i] != 0 && _channels[i]->getId() == id) {
+				if (autofreeStream)
+					delete input;
+				return;
+			}
+	}
+
+	// Create the channel
+	Channel *chan = new Channel(this, type, input, autofreeStream, reverseStereo, id, permanent);
+	chan->setVolume(volume);
+	chan->setBalance(balance);
+	insertChannel(handle, chan);
+}
+
+void Mixer::mix(int16 *buf, uint len) {
+	//Common::StackLock lock(_mutex);
+	
+	// Since the mixer callback has been called, the mixer must be ready...
+	_mixerReady = true;
+
+	//  zero the buf
+	memset(buf, 0, 2 * len * sizeof(int16));
+
+	// mix all channels
+	for (int i = 0; i != NUM_CHANNELS; i++)
+		if (_channels[i]) {
+			if (_channels[i]->isFinished()) {
+				delete _channels[i];
+				_channels[i] = 0;
+			} else if (!_channels[i]->isPaused())
+				_channels[i]->mix(buf, len);
+		}
+}
+
+void Mixer::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).
+	((Mixer *)s)->mix((int16 *)samples, len >> 2);
+}
+
+void Mixer::stopAll() {
+	//Common::StackLock lock(_mutex);
+	for (int i = 0; i != NUM_CHANNELS; i++) {
+		if (_channels[i] != 0 && !_channels[i]->isPermanent()) {
+			delete _channels[i];
+			_channels[i] = 0;
+		}
+	}
+}
+
+void Mixer::stopID(int id) {
+	//Common::StackLock lock(_mutex);
+	for (int i = 0; i != NUM_CHANNELS; i++) {
+		if (_channels[i] != 0 && _channels[i]->getId() == id) {
+			delete _channels[i];
+			_channels[i] = 0;
+		}
+	}
+}
+
+void Mixer::stopHandle(SoundHandle handle) {
+//	Common::StackLock lock(_mutex);
+
+	// Simply ignore stop requests for handles of sounds that already terminated
+	const int index = handle._val % NUM_CHANNELS;
+	if (!_channels[index] || _channels[index]->_handle._val != handle._val)
+		return;
+
+	delete _channels[index];
+	_channels[index] = 0;
+}
+
+void Mixer::setChannelVolume(SoundHandle handle, byte volume) {
+//	Common::StackLock lock(_mutex);
+
+	const int index = handle._val % NUM_CHANNELS;
+	if (!_channels[index] || _channels[index]->_handle._val != handle._val)
+		return;
+
+	_channels[index]->setVolume(volume);
+}
+
+void Mixer::setChannelBalance(SoundHandle handle, int8 balance) {
+//	Common::StackLock lock(_mutex);
+
+	const int index = handle._val % NUM_CHANNELS;
+	if (!_channels[index] || _channels[index]->_handle._val != handle._val)
+		return;
+
+	_channels[index]->setBalance(balance);
+}
+
+uint32 Mixer::getSoundElapsedTime(SoundHandle handle) {
+//	Common::StackLock lock(_mutex);
+
+	const int index = handle._val % NUM_CHANNELS;
+	if (!_channels[index] || _channels[index]->_handle._val != handle._val)
+		return 0;
+
+	return _channels[index]->getElapsedTime();
+}
+
+void Mixer::pauseAll(bool paused) {
+//	Common::StackLock lock(_mutex);
+	for (int i = 0; i != NUM_CHANNELS; i++) {
+		if (_channels[i] != 0) {
+			_channels[i]->pause(paused);
+		}
+	}
+}
+
+void Mixer::pauseID(int id, bool paused) {
+//	Common::StackLock lock(_mutex);
+	for (int i = 0; i != NUM_CHANNELS; i++) {
+		if (_channels[i] != 0 && _channels[i]->getId() == id) {
+			_channels[i]->pause(paused);
+			return;
+		}
+	}
+}
+
+void Mixer::pauseHandle(SoundHandle handle, bool paused) {
+//	Common::StackLock lock(_mutex);
+
+	// Simply ignore (un)pause requests for sounds that already terminated
+	const int index = handle._val % NUM_CHANNELS;
+	if (!_channels[index] || _channels[index]->_handle._val != handle._val)
+		return;
+
+	_channels[index]->pause(paused);
+}
+
+bool Mixer::isSoundIDActive(int id) {
+//	Common::StackLock lock(_mutex);
+	for (int i = 0; i != NUM_CHANNELS; i++)
+		if (_channels[i] && _channels[i]->getId() == id)
+			return true;
+	return false;
+}
+
+int Mixer::getSoundID(SoundHandle handle) {
+//	Common::StackLock lock(_mutex);
+	const int index = handle._val % NUM_CHANNELS;
+	if (_channels[index] && _channels[index]->_handle._val == handle._val)
+		return _channels[index]->getId();
+	return 0;
+}
+
+bool Mixer::isSoundHandleActive(SoundHandle handle) {
+//	Common::StackLock lock(_mutex);
+	const int index = handle._val % NUM_CHANNELS;
+	return _channels[index] && _channels[index]->_handle._val == handle._val;
+}
+
+bool Mixer::hasActiveChannelOfType(SoundType type) {
+//	Common::StackLock lock(_mutex);
+	for (int i = 0; i != NUM_CHANNELS; i++)
+		if (_channels[i] && _channels[i]->_type == type)
+			return true;
+	return false;
+}
+
+void Mixer::setVolumeForSoundType(SoundType type, int volume) {
+	assert(0 <= type && type < ARRAY_SIZE(_volumeForSoundType));
+
+	// Check range
+	if (volume > kMaxMixerVolume)
+		volume = kMaxMixerVolume;
+	else if (volume < 0)
+		volume = 0;
+
+	// TODO: Maybe we should do logarithmic (not linear) volume
+	// scaling? See also Player_V2::setMasterVolume
+
+	_volumeForSoundType[type] = volume;
+}
+
+int Mixer::getVolumeForSoundType(SoundType type) const {
+	assert(0 <= type && type < ARRAY_SIZE(_volumeForSoundType));
+
+	return _volumeForSoundType[type];
+}
+
+
+Channel::Channel(Mixer *mixer, Mixer::SoundType type, AudioStream *input,
+				bool autofreeStream, bool reverseStereo, int id, bool permanent)
+	: _type(type), _mixer(mixer), _autofreeStream(autofreeStream),
+	  _volume(Mixer::kMaxChannelVolume), _balance(0), _paused(false), _id(id), _samplesConsumed(0),
+	  _samplesDecoded(0), _mixerTimeStamp(0), _converter(0), _input(input), _permanent(permanent) {
+	assert(mixer);
+	assert(input);
+
+	// Get a rate converter instance
+	_converter = makeRateConverter(_input->getRate(), mixer->getOutputRate(), _input->isStereo(), reverseStereo);
+}
+
+Channel::~Channel() {
+	delete _converter;
+	if (_autofreeStream)
+		delete _input;
+}
+
+/* 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->endOfData()) {
+		// TODO: call drain method
+	} else {
+		assert(_converter);
+
+		// From the channel balance/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 127 is there because the
+		// balance value ranges from -127 to 127.  The mixer (music/sound)
+		// volume is in the range 0 - kMaxMixerVolume.
+		// Hence, the vol_l/vol_r values will be in that range, too
+
+		int vol = _mixer->getVolumeForSoundType(_type) * _volume;
+		st_volume_t vol_l, vol_r;
+
+		if (_balance == 0) {
+			vol_l = vol / Mixer::kMaxChannelVolume;
+			vol_r = vol / Mixer::kMaxChannelVolume;
+		} else if (_balance < 0) {
+			vol_l = vol / Mixer::kMaxChannelVolume;
+			vol_r = ((127 + _balance) * vol) / (Mixer::kMaxChannelVolume * 127);
+		} else {
+			vol_l = ((127 - _balance) * vol) / (Mixer::kMaxChannelVolume * 127);
+			vol_r = vol / Mixer::kMaxChannelVolume;
+		}
+
+		_samplesConsumed = _samplesDecoded;
+		_mixerTimeStamp = _sound_driver->GetMillis();
+
+		_converter->flow(*_input, data, len, vol_l, vol_r);
+
+		_samplesDecoded += len;
+	}
+}
+
+uint32 Channel::getElapsedTime() {
+	if (_mixerTimeStamp == 0)
+		return 0;
+
+	// Convert the number of samples into a time duration. To avoid
+	// overflow, this has to be done in a somewhat non-obvious way.
+
+	uint rate = _mixer->getOutputRate();
+
+	uint32 seconds = _samplesConsumed / rate;
+	uint32 milliseconds = (1000 * (_samplesConsumed % rate)) / rate;
+
+	uint32 delta = _sound_driver->GetMillis() - _mixerTimeStamp;
+
+	// In theory it would seem like a good idea to limit the approximation
+	// so that it never exceeds the theoretical upper bound set by
+	// _samplesDecoded. Meanwhile, back in the real world, doing so makes
+	// the Broken Sword cutscenes noticeably jerkier. I guess the mixer
+	// isn't invoked at the regular intervals that I first imagined.
+
+	// FIXME: This won't work very well if the sound is paused.
+	return 1000 * seconds + milliseconds + delta;
+}

Property changes on: src\mixer\mixer.cpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/mixer.hpp
===================================================================
--- src/mixer/mixer.hpp	(revision 0)
+++ src/mixer/mixer.hpp	(revision 0)
@@ -0,0 +1,312 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+#ifndef SOUND_MIXER_H
+#define SOUND_MIXER_H
+
+#define ARRAY_SIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
+
+class AudioStream;
+class Channel;
+class Mixer;
+
+/**
+ * A SoundHandle instances corresponds to a specific sound
+ * being played via the mixer. It can be used to control that
+ * sound (pause it, stop it, etc.).
+ * @see The Mixer class
+ */
+class SoundHandle {
+	friend class Channel;
+	friend class Mixer;
+	uint32 _val;
+public:
+	inline SoundHandle() : _val(0xFFFFFFFF) {}
+};
+
+#define _MIXER_NUM_SOUND_TYPES		3
+
+/**
+ * The main audio mixer handles mixing of an arbitrary number of
+ * input audio streams (in the form of AudioStream instances).
+ */
+class Mixer {
+public:
+	/**
+	 * Various flags which can be bit-ORed and then passed to
+	 * Mixer::playRaw resp. makeLinearInputStream to control their
+	 * behavior.
+	 *
+	 * Engine authors are advised not to rely on a certain value or
+	 * order of these flags (in particular, do not store them verbatim
+	 * in savestates).
+	 */
+	enum RawFlags {
+		/** unsigned samples (default: signed) */
+		FLAG_UNSIGNED = 1 << 0,
+
+		/** sound is 16 bits wide (default: 8bit) */
+		FLAG_16BITS = 1 << 1,
+
+		/** samples are little endian (default: big endian) */
+		FLAG_LITTLE_ENDIAN = 1 << 2,
+
+		/** sound is in stereo (default: mono) */
+		FLAG_STEREO = 1 << 3,
+
+		/** reverse the left and right stereo channel */
+		FLAG_REVERSE_STEREO = 1 << 4,
+
+		/** sound buffer is freed automagically at the end of playing */
+		FLAG_AUTOFREE = 1 << 5,
+
+		/** loop the audio */
+		FLAG_LOOP = 1 << 6
+	};
+
+	enum SoundType {
+		kPlainSoundType = 0,
+
+		kMusicSoundType = 1,
+		kSFXSoundType = 2
+	};
+
+	enum {
+		kMaxChannelVolume = 255,
+		kMaxMixerVolume = 256
+	};
+
+private:
+	enum {
+		NUM_CHANNELS = 16
+	};
+
+	//OSystem *_syst;
+	//Common::Mutex _mutex;
+
+	int _volumeForSoundType[_MIXER_NUM_SOUND_TYPES];
+
+	uint32 _handleSeed;
+	Channel *_channels[NUM_CHANNELS];
+
+	bool _mixerReady;
+
+public:
+	Mixer();
+	~Mixer();
+
+
+
+	/**
+	 * Is the mixer ready and setup? This may not be the case on systems which
+	 * don't support digital sound output. In that case, the mixer proc may
+	 * never be called. That in turn can cause breakage in games which try to
+	 * sync with an audio stream. In particular, the Adlib MIDI emulation...
+	 *
+	 * @return whether the mixer is ready and setup
+	 */
+	bool isReady() const { return _mixerReady; }
+
+
+
+	/**
+	 * Start playing the given raw sound data.
+	 * Internally, this simply creates an audio input stream wrapping the data
+	 * (using the makeLinearInputStream factory function), which is then
+	 * passed on to playInputStream.
+	 */
+	void playRaw(
+		SoundType type,
+		SoundHandle *handle,
+		void *sound, uint32 size, uint rate, byte flags,
+		int id = -1, byte volume = 255, int8 balance = 0,
+		uint32 loopStart = 0, uint32 loopEnd = 0);
+
+	/**
+	 * Start playing the given audio input stream.
+	 *
+	 * Note that the sound id assigned below is unique. At most one stream
+	 * with a given idea can play at any given time. Trying to play a sound
+	 * with an id that is already in use causes the new sound to be not played.
+	 *
+	 * @param type	the type (voice/sfx/music) of the stream
+	 * @param handle	a SoundHandle which can be used to reference and control
+	 *                  the stream via suitable mixer methods
+	 * @param input	the actual AudioStream to be played
+	 * @param id	a unique id assigned to this stream
+	 * @param volume	the volume with which to play the sound, ranging from 0 to 255
+	 * @param balance	the balance with which to play the sound, ranging from -128 to 127
+	 * @param autofreeStream	a flag indicating whether the stream should be
+	 *                          freed after playback finished
+	 * @param permanent	a flag indicating whether a plain stopAll call should
+	 *                  not stop this particular stream
+	 * @param reverseStereo	a flag indicating whether left and right channels shall be swapped
+	 */
+	void playInputStream(
+		SoundType type,
+		SoundHandle *handle,
+		AudioStream *input,
+		int id = -1, byte volume = 255, int8 balance = 0,
+		bool autofreeStream = true,
+		bool permanent = false,
+		bool reverseStereo = false);
+
+
+
+	/**
+	 * Stop all currently playing sounds.
+	 */
+	void stopAll();
+
+	/**
+	 * Stop playing the sound with given ID.
+	 *
+	 * @param id the ID of the sound to affect
+	 */
+	void stopID(int id);
+
+	/**
+	 * Stop playing the sound corresponding to the given handle.
+	 *
+	 * @param handle the sound to affect
+	 */
+	void stopHandle(SoundHandle handle);
+
+
+
+	/**
+	 * Pause/unpause all sounds, including all regular and permanent 
+	 * channels
+	 *
+	 * @param paused true to pause everything, false to unpause
+	 */
+	void pauseAll(bool paused);
+
+	/**
+	 * Pause/unpause the sound with the given ID.
+	 *
+	 * @param id the ID of the sound to affect
+	 * @param paused true to pause the sound, false to unpause it
+	 */
+	void pauseID(int id, bool paused);
+
+	/**
+	 * Pause/unpause the sound corresponding to the given handle.
+	 *
+	 * @param handle the sound to affect
+	 * @param paused true to pause the sound, false to unpause it
+	 */
+	void pauseHandle(SoundHandle handle, bool paused);
+
+
+
+	/**
+	 * Check if a sound with the given ID is active.
+	 *
+	 * @param id the ID of the sound to query
+	 * @return true if the sound is active
+	 */
+	bool isSoundIDActive(int id);
+
+	/**
+	 * Get the sound ID of handle sound
+	 *
+	 * @param handle sound to query
+	 * @return sound ID if active
+	 */
+	int getSoundID(SoundHandle handle);
+
+	/**
+	 * Check if a sound with the given handle is active.
+	 *
+	 * @param handle sound to query
+	 * @return true if the sound is active
+	 */
+	bool isSoundHandleActive(SoundHandle handle);
+
+
+
+	/**
+	 * Set the channel volume for the given handle.
+	 *
+	 * @param handle the sound to affect
+	 * @param volume the new channel volume (0 - 255)
+	 */
+	void setChannelVolume(SoundHandle handle, byte volume);
+
+	/**
+	 * Set the channel balance for the given handle.
+	 *
+	 * @param handle the sound to affect
+	 * @param balance the new channel balance:
+	 *        (-127 ... 0 ... 127) corresponds to (left ... center ... right)
+	 */
+	void setChannelBalance(SoundHandle handle, int8 balance);
+
+	/**
+	 * Get approximation of for how long the channel has been playing.
+	 */
+	uint32 getSoundElapsedTime(SoundHandle handle);
+
+	/**
+	 * Check whether any channel of the given sound type is active.
+	 * For example, this can be used to check whether any SFX sound
+	 * is currently playing, by checking for type kSFXSoundType.
+	 *
+	 * @param  type the sound type to look for
+	 * @return true if any channels of the specified type are active.
+	 */
+	bool hasActiveChannelOfType(SoundType type);
+
+	/**
+	 * Set the volume for the given sound type.
+	 *
+	 * @param type the sound type
+	 * @param volume the new global volume, 0-kMaxMixerVolume
+	 */
+	void setVolumeForSoundType(SoundType type, int volume);
+
+	/**
+	 * Query the global volume.
+	 *
+	 * @param type the sound type
+	 * @return the global music volume, 0-kMaxMixerVolume
+	 */
+	int getVolumeForSoundType(SoundType type) const;
+
+	/**
+	 * Query the system's audio output sample rate. This returns
+	 * the same value as OSystem::getOutputSampleRate().
+	 *
+	 * @return the output sample rate in Hz
+	 */
+	uint getOutputRate() const;
+
+protected:
+	void insertChannel(SoundHandle *handle, Channel *chan);
+
+	/**
+	 * Internal main method -- all the actual mixing work is done from here.
+	 */
+	void mix(int16 * buf, uint len);
+
+	// FIXME: temporary "public" to allow access to mixCallback
+	// from within OSystem::makeMixer()
+public:
+	/**
+	 * The mixer callback function, passed on to OSystem::setSoundCallback().
+	 * This simply calls the mix() method.
+	 */
+	static void mixCallback(void *s, byte *samples, int len);
+	
+	void setReady(bool ready) { _mixerReady = ready; }
+};
+
+
+#endif

Property changes on: src\mixer\mixer.hpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/rate.cpp
===================================================================
--- src/mixer/rate.cpp	(revision 0)
+++ src/mixer/rate.cpp	(revision 0)
@@ -0,0 +1,263 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+
+/*
+ * 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 "../openttd.h"
+#include "../driver.h"
+#include "mixer.hpp"
+#include "audiostream.hpp"
+#include "rate.hpp"
+
+/**
+ * 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(AudioStream &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(AudioStream &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, ARRAY_SIZE(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) / Mixer::kMaxMixerVolume);
+
+			// output right channel
+			clampedAdd(*obuf++, (out[1] * (int)vol_r) / Mixer::kMaxMixerVolume);
+
+			// 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);
+}
+
+
+/**
+ * Simple audio rate converter for the case that the inrate equals the outrate.
+ */
+template<bool stereo, bool reverseStereo>
+class CopyRateConverter : public RateConverter {
+	st_sample_t *_buffer;
+	st_size_t _bufferSize;
+public:
+	CopyRateConverter() : _buffer(0), _bufferSize(0) {}
+	~CopyRateConverter() {
+		free(_buffer);
+	}
+
+	virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
+		assert(input.isStereo() == stereo);
+
+		st_sample_t *ptr;
+		st_size_t len;
+
+		if (stereo)
+			osamp *= 2;
+
+		// Reallocate temp buffer, if necessary
+		if (osamp > _bufferSize) {
+			free(_buffer);
+			_buffer = (st_sample_t *)malloc(osamp * 2);
+			_bufferSize = osamp;
+		}
+
+		// Read up to 'osamp' samples into our temporary buffer
+		len = input.readBuffer(_buffer, osamp);
+
+		// Mix the data into the output buffer
+		ptr = _buffer;
+		while (len-- > 0) {
+			st_sample_t tmp0, tmp1;
+			tmp0 = tmp1 = *ptr++;
+			if (stereo) {
+				if (reverseStereo)
+					tmp0 = *ptr++;
+				else
+					tmp1 = *ptr++;
+				len--;
+			}
+
+			// output left channel
+			clampedAdd(*obuf++, (tmp0 * (int)vol_l) / Mixer::kMaxMixerVolume);
+
+			// output right channel
+			clampedAdd(*obuf++, (tmp1 * (int)vol_r) / Mixer::kMaxMixerVolume);
+		}
+		return (ST_SUCCESS);
+	}
+	virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
+		return (ST_SUCCESS);
+	}
+};
+
+
+/**
+ * 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>();
+	}
+}

Property changes on: src\mixer\rate.cpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/rate.hpp
===================================================================
--- src/mixer/rate.hpp	(revision 0)
+++ src/mixer/rate.hpp	(revision 0)
@@ -0,0 +1,64 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+#ifndef SOUND_RATE_H
+#define SOUND_RATE_H
+
+class AudioStream;
+
+
+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(AudioStream &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

Property changes on: src\mixer\rate.hpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/str.cpp
===================================================================
--- src/mixer/str.cpp	(revision 0)
+++ src/mixer/str.cpp	(revision 0)
@@ -0,0 +1,454 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+
+#include "str.hpp"
+
+#include <ctype.h>
+
+#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__))
+const String String::emptyString;
+#else
+const char *String::emptyString = "";
+#endif
+
+static int computeCapacity(int len) {
+	// By default, for the capacity we use the nearest multiple of 32
+	// that leaves at least 16 chars of extra space (in case the string
+	// grows a bit).
+	// Finally, we subtract 1 to compensate for the trailing zero byte.
+	len += 16;
+	return ((len + 32 - 1) & ~0x1F) - 1;
+}
+
+String::String(const char *str, uint32 len)
+: _len(0), _str(_storage) {
+
+	// Init _storage member explicitly (ie. without calling its constructor)
+	// for GCC 2.95.x compatibility (see also tracker item #1602879).
+	_storage[0] = 0;
+
+	if (str && *str) {
+		const uint32 tmp = strlen(str);
+		assert(len <= tmp);
+		if (len <= 0)
+			len = tmp;
+		_len = len;
+		
+		if (len >= _builtinCapacity) {
+			// Not enough internal storage, so allocate more
+			_extern._capacity = computeCapacity(len);
+			_extern._refCount = 0;
+			_str = (char *)malloc(_extern._capacity+1);
+			assert(_str != 0);
+		}
+		
+		// Copy the string into the storage area
+		memcpy(_str, str, len);
+		_str[len] = 0;
+	}
+}
+
+String::String(const String &str)
+ : _len(str._len), _str(str.isStorageIntern() ? _storage : str._str) {
+	if (str.isStorageIntern()) {
+		// String in internal storage: just copy it
+		memcpy(_storage, str._storage, _builtinCapacity);
+	} else {
+		// String in external storage: use refcount mechanism
+		str.incRefCount();
+		_extern._refCount = str._extern._refCount;
+		_extern._capacity = str._extern._capacity;
+	}
+	assert(_str != 0);
+}
+
+String::String(char c)
+: _len(0), _str(_storage) {
+	
+	_storage[0] = c;
+	_storage[1] = 0;
+	
+	_len = (c == 0) ? 0 : 1;
+}
+
+String::~String() {
+	decRefCount(_extern._refCount);
+}
+
+void String::incRefCount() const {
+	assert(!isStorageIntern());
+	if (_extern._refCount == 0) {
+		_extern._refCount = new int(2);
+	} else {
+		++(*_extern._refCount);
+	}
+}
+
+void String::decRefCount(int *oldRefCount) {
+	if (isStorageIntern())
+		return;
+
+	if (oldRefCount) {
+		--(*oldRefCount);
+	}
+	if (!oldRefCount || *oldRefCount <= 0) {
+		// The ref count reached zero, so we free the string storage
+		// and the ref count storage.
+		delete oldRefCount;
+		free(_str);
+
+		// Even though _str points to a freed memory block now,
+		// we do not change its value, because any code that calls
+		// decRefCount will have to do this afterwards anyway.
+	}
+}
+
+String& String::operator  =(const char *str) {
+	uint32 len = strlen(str);
+	ensureCapacity(len, false);
+	_len = len;
+	memcpy(_str, str, len + 1);
+	return *this;
+}
+
+String &String::operator  =(const String &str) {
+	if (str.isStorageIntern()) {
+		decRefCount(_extern._refCount);
+		_len = str._len;
+		_str = _storage;
+		memcpy(_str, str._str, _len + 1);
+	} else {
+		str.incRefCount();
+		decRefCount(_extern._refCount);
+	
+		_extern._refCount = str._extern._refCount;
+		_extern._capacity = str._extern._capacity;
+		_len = str._len;
+		_str = str._str;
+	}
+
+	return *this;
+}
+
+String& String::operator  =(char c) {
+	ensureCapacity(1, false);
+	_len = 1;
+	_str[0] = c;
+	_str[1] = 0;
+	return *this;
+}
+
+String &String::operator +=(const char *str) {
+	int len = strlen(str);
+	if (len > 0) {
+		ensureCapacity(_len + len, true);
+
+		memcpy(_str + _len, str, len + 1);
+		_len += len;
+	}
+	return *this;
+}
+
+String &String::operator +=(const String &str) {
+	int len = str._len;
+	if (len > 0) {
+		ensureCapacity(_len + len, true);
+
+		memcpy(_str + _len, str._str, len + 1);
+		_len += len;
+	}
+	return *this;
+}
+
+String &String::operator +=(char c) {
+	ensureCapacity(_len + 1, true);
+
+	_str[_len++] = c;
+	_str[_len] = 0;
+
+	return *this;
+}
+
+bool String::hasPrefix(const char *x) const {
+	assert(x != 0);
+	// Compare x with the start of _str.
+	const char *y = c_str();
+	while (*x && *x == *y) {
+		++x;
+		++y;
+	}
+	// It's a prefix, if and only if all letters in x are 'used up' before
+	// _str ends.
+	return *x == 0;
+}
+
+bool String::hasSuffix(const char *x) const {
+	assert(x != 0);
+	// Compare x with the end of _str.
+	const uint32 x_len = strlen(x);
+	if (x_len > _len)
+		return false;
+	const char *y = c_str() + _len - x_len;
+	while (*x && *x == *y) {
+		++x;
+		++y;
+	}
+	// It's a suffix, if and only if all letters in x are 'used up' before
+	// _str ends.
+	return *x == 0;
+}
+
+bool String::contains(const char *x) const {
+	assert(x != 0);
+	return strstr(c_str(), x) != NULL;
+}
+
+void String::deleteLastChar() {
+	deleteChar(_len - 1);
+}
+
+void String::deleteChar(uint32 p) {
+	assert(p < _len);
+
+	// Call ensureCapacity to make sure we actually *own* the storage
+	// to which _str points to -- we wouldn't want to modify a storage
+	// which other string objects are sharing, after all.
+	ensureCapacity(_len, true);
+	while (p++ < _len)
+		_str[p-1] = _str[p];
+	_len--;
+}
+
+void String::clear() {
+	decRefCount(_extern._refCount);
+
+	_len = 0;
+	_str = _storage;
+	_storage[0] = 0;
+}
+
+void String::insertChar(char c, uint32 p) {
+	assert(p <= _len);
+
+	ensureCapacity(_len + 1, true);
+	_len++;
+	for (uint32 i = _len; i > p; --i)
+		_str[i] = _str[i-1];
+	_str[p] = c;
+}
+
+void String::toLowercase() {
+	ensureCapacity(_len, true);
+	for (uint32 i = 0; i < _len; ++i)
+		_str[i] = tolower(_str[i]);
+}
+
+void String::toUppercase() {
+	ensureCapacity(_len, true);
+	for (uint32 i = 0; i < _len; ++i)
+		_str[i] = toupper(_str[i]);
+}
+
+/**
+ * Ensure that enough storage is available to store at least new_len
+ * characters plus a null byte. In addition, if we currently share
+ * the storage with another string, unshare it, so that we can safely
+ * write to the storage.
+ */
+void String::ensureCapacity(uint32 new_len, bool keep_old) {
+	bool isShared;
+	uint32 curCapacity, newCapacity;
+	char *newStorage;
+	int *oldRefCount = _extern._refCount;
+	
+	if (isStorageIntern()) {
+		isShared = false;
+		curCapacity = _builtinCapacity - 1;
+	} else {
+		isShared = (oldRefCount && *oldRefCount > 1);
+		curCapacity = _extern._capacity;
+	}
+	
+	// Special case: If there is enough space, and we do not share
+	// the storage, then there is nothing to do.
+	if (!isShared && new_len <= curCapacity)
+		return;
+
+	if (isShared && new_len <= _builtinCapacity - 1) {
+		// We share the storage, but there is enough internal storage: Use that.
+		newStorage = _storage;
+		newCapacity = _builtinCapacity - 1;
+	} else {
+		// We need to allocate storage on the heap!
+
+		// Compute a suitable new capacity limit
+		newCapacity = computeCapacity(new_len);
+
+		// Allocate new storage
+		newStorage = (char *)malloc(newCapacity+1);
+		assert(newStorage);
+	}
+
+	// Copy old data if needed, elsewise reset the new storage.
+	if (keep_old) {
+		assert(_len <= newCapacity);
+		memcpy(newStorage, _str, _len + 1);
+	} else {
+		_len = 0;
+		newStorage[0] = 0;
+	}
+
+	// Release hold on the old storage ...
+	decRefCount(oldRefCount);
+
+	// ... in favor of the new storage
+	_str = newStorage;
+
+	if (!isStorageIntern()) {
+		// Set the ref count & capacity if we use an external storage.
+		// It is important to do this *after* copying any old content,
+		// else we would override data that has not yet been copied!
+		_extern._refCount = 0;
+		_extern._capacity = newCapacity;
+	}
+}
+
+/*uint String::hash() const {
+	return hashit(c_str());
+}*/
+	
+bool String::operator ==(const String &x) const {
+	return equals(x);
+}
+
+bool String::operator ==(const char *x) const {
+	assert(x != 0);
+	return equals(x);
+}
+
+bool String::operator !=(const String &x) const {
+	return !equals(x);
+}
+
+bool String::operator !=(const char *x) const {
+	assert(x != 0);
+	return !equals(x);
+}
+
+bool String::operator < (const String &x) const {
+	return compareTo(x) < 0;
+}
+
+bool String::operator <= (const String &x) const {
+	return compareTo(x) <= 0;
+}
+
+bool String::operator > (const String &x) const {
+	return compareTo(x) > 0;
+}
+
+bool String::operator >= (const String &x) const {
+	return compareTo(x) >= 0;
+}
+
+bool operator == (const char* y, const String &x) {
+	return (x == y);
+}
+
+bool operator != (const char* y, const String &x) {
+	return x != y;
+}
+
+//#pragma mark -
+
+bool String::equals(const String &x) const {
+	return (0 == compareTo(x));
+}
+
+bool String::equals(const char *x) const {
+	assert(x != 0);
+	return (0 == compareTo(x));
+}
+
+bool String::equalsIgnoreCase(const String &x) const {
+	return (0 == compareToIgnoreCase(x));
+}
+
+bool String::equalsIgnoreCase(const char *x) const {
+	assert(x != 0);
+	return (0 == compareToIgnoreCase(x));
+}
+
+int String::compareTo(const String &x) const {
+	return compareTo(x.c_str());
+}
+
+int String::compareTo(const char *x) const {
+	assert(x != 0);
+	return strcmp(c_str(), x);
+}
+
+int String::compareToIgnoreCase(const String &x) const {
+	return compareToIgnoreCase(x.c_str());
+}
+
+int String::compareToIgnoreCase(const char *x) const {
+	assert(x != 0);
+	return strcasecmp(c_str(), x);
+}
+
+String operator +(const String &x, const String &y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+String operator +(const char *x, const String &y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+String operator +(const String &x, const char *y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+String operator +(char x, const String &y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+String operator +(const String &x, char y) {
+	String temp(x);
+	temp += y;
+	return temp;
+}
+
+char *ltrim(char *t) {
+	while (isspace(*t))
+		t++;
+	return t;
+}
+
+char *rtrim(char *t) {
+	int l = strlen(t) - 1;
+	while (l >= 0 && isspace(t[l]))
+		t[l--] = 0;
+	return t;
+}
+
+char *trim(char *t) {
+	return rtrim(ltrim(t));
+}

Property changes on: src\mixer\str.cpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/str.hpp
===================================================================
--- src/mixer/str.hpp	(revision 0)
+++ src/mixer/str.hpp	(revision 0)
@@ -0,0 +1,187 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+#ifndef COMMON_STRING_H
+#define COMMON_STRING_H
+
+/**
+ * Simple string class for ScummVM. Provides automatic storage managment,
+ * and overloads several operators in a 'natural' fashion, mimicking
+ * the std::string class. Even provides simple iterators.
+ * 
+ * This class tries to avoid allocating lots of small blocks on the heap,
+ * since that is inefficient on several platforms supported by ScummVM.
+ * Instead, small strings are stored 'inside' the string object (i.e. on
+ * the stack, for stack allocated objects), and only for strings exceeding
+ * a certain length do we allocate a buffer on the heap.
+ */
+class String {
+protected:
+	/**
+	 * The size of the internal storage. Increasing this means less heap
+	 * allocations are needed, at the cost of more stack memory usage,
+	 * and of course lots of wasted memory. Empirically, 90% or more of
+	 * all String instances are less than 32 chars long. If a platform
+	 * is very short on stack space, it would be possible to lower this.
+	 * A value of 24 still seems acceptable, though considerably worse,
+	 * while 16 seems to be the lowest you want to go... Anything lower
+	 * than 8 makes no sense, since that's the size of member _extern
+	 * (on 32 bit machines; 12 bytes on systems with 64bit pointers).
+	 */
+	static const uint32 _builtinCapacity = 32;
+
+	/**
+	 * Length of the string. Stored to avoid having to call strlen
+	 * a lot. Yes, we limit ourselves to strings shorter than 4GB --
+	 * on purpose :-).
+	 */
+	uint32 		_len;
+	
+	/**
+	 * Pointer to the actual string storage. Either points to _storage,
+	 * or to a block allocated on the heap via malloc.
+	 */
+	char		*_str;
+	
+	
+	union {
+		/**
+		 * Internal string storage.
+		 */
+		char _storage[_builtinCapacity];
+		/**
+		 * External string storage data -- the refcounter, and the
+		 * capacity of the string _str points to.
+		 */
+		struct {
+			mutable int *_refCount;
+			uint32 		_capacity;
+		} _extern;
+	};
+	
+	inline bool isStorageIntern() const {
+		return _str == _storage;
+	}
+	
+public:
+#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__))
+	static const String emptyString;
+#else
+	static const char *emptyString;
+#endif
+
+	String() : _len(0), _str(_storage) { _storage[0] = 0; }
+	String(const char *str, uint32 len = 0);
+	String(const String &str);
+	String(char c);
+	virtual ~String();
+
+	String &operator  =(const char *str);
+	String &operator  =(const String &str);
+	String &operator  =(char c);
+	String &operator +=(const char *str);
+	String &operator +=(const String &str);
+	String &operator +=(char c);
+
+	bool operator ==(const String &x) const;
+	bool operator ==(const char *x) const;
+	bool operator !=(const String &x) const;
+	bool operator !=(const char *x) const;
+
+	bool operator <(const String &x) const;
+	bool operator <=(const String &x) const;
+	bool operator >(const String &x) const;
+	bool operator >=(const String &x) const;
+
+	bool equals(const String &x) const;
+	bool equalsIgnoreCase(const String &x) const;
+	int compareTo(const String &x) const;	// strcmp clone
+	int compareToIgnoreCase(const String &x) const;	// stricmp clone
+
+	bool equals(const char *x) const;
+	bool equalsIgnoreCase(const char *x) const;
+	int compareTo(const char *x) const;	// strcmp clone
+	int compareToIgnoreCase(const char *x) const;	// stricmp clone
+
+	bool hasSuffix(const char *x) const;
+	bool hasPrefix(const char *x) const;
+	
+	bool contains(const char *x) const;
+
+	inline const char *c_str() const		{ return _str; }
+	inline uint size() const				{ return _len; }
+
+	inline bool empty() const	{ return (_len == 0); }
+	char lastChar() const	{ return (_len > 0) ? _str[_len-1] : 0; }
+
+	char operator [](int idx) const {
+		assert(_str && idx >= 0 && idx < (int)_len);
+		return _str[idx];
+	}
+
+	char &operator [](int idx) {
+		assert(_str && idx >= 0 && idx < (int)_len);
+		return _str[idx];
+	}
+
+	void deleteLastChar();
+	void deleteChar(uint32 p);
+	void clear();
+	void insertChar(char c, uint32 p);
+
+	void toLowercase();
+	void toUppercase();
+
+//	uint hash() const;
+
+public:
+	typedef char *        iterator;
+	typedef const char *  const_iterator;
+
+	iterator		begin() {
+		return _str;
+	}
+
+	iterator		end() {
+		return begin() + size();
+	}
+
+	const_iterator	begin() const {
+		return _str;
+	}
+
+	const_iterator	end() const {
+		return begin() + size();
+	}
+
+protected:
+	void ensureCapacity(uint32 new_len, bool keep_old);
+	void incRefCount() const;
+	void decRefCount(int *oldRefCount);
+};
+
+// Append two strings to form a new (temp) string
+String operator +(const String &x, const String &y);
+
+String operator +(const char *x, const String &y);
+String operator +(const String &x, const char *y);
+
+String operator +(const String &x, char y);
+String operator +(char x, const String &y);
+
+// Some useful additional comparision operators for Strings
+bool operator == (const char *x, const String &y);
+bool operator != (const char *x, const String &y);
+
+// Utility functions to remove leading and trailing whitespaces
+extern char *ltrim(char *t);
+extern char *rtrim(char *t);
+extern char *trim(char *t);
+
+#endif

Property changes on: src\mixer\str.hpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/stream.cpp
===================================================================
--- src/mixer/stream.cpp	(revision 0)
+++ src/mixer/stream.cpp	(revision 0)
@@ -0,0 +1,173 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../core/math_func.hpp"
+#include "stream.hpp"
+
+
+void WriteStream::writeString(const char *str) {
+	write(str, strlen(str));
+}
+
+MemoryReadStream *ReadStream::readStream(uint32 dataSize) {
+	void *buf = malloc(dataSize);
+	dataSize = read(buf, dataSize);
+	assert(dataSize > 0);
+	return new MemoryReadStream((byte *)buf, dataSize, true);
+}
+
+
+uint32 MemoryReadStream::read(void *dataPtr, uint32 dataSize) {
+	// Read at most as many bytes as are still available...
+	if (dataSize > _size - _pos)
+		dataSize = _size - _pos;
+	memcpy(dataPtr, _ptr, dataSize);
+
+	if (_encbyte) {
+		byte *p = (byte *)dataPtr;
+		byte *end = p + dataSize;
+		while (p < end)
+			*p++ ^= _encbyte;
+	}
+
+	_ptr += dataSize;
+	_pos += dataSize;
+
+	return dataSize;
+}
+
+void MemoryReadStream::seek(int32 offs, int whence) {
+	// Pre-Condition
+	assert(_pos <= _size);
+	switch (whence) {
+	case SEEK_END:
+		// SEEK_END works just like SEEK_SET, only 'reversed',
+		// i.e. from the end.
+		offs = _size - offs;
+		// Fall through
+	case SEEK_SET:
+		_ptr = _ptrOrig + offs;
+		_pos = offs;
+		break;
+
+	case SEEK_CUR:
+		_ptr += offs;
+		_pos += offs;
+		break;
+	}
+	// Post-Condition
+	assert(_pos <= _size);
+}
+
+#define LF 0x0A
+#define CR 0x0D
+
+char *SeekableReadStream::readLine(char *buf, size_t bufSize) {
+	assert(buf && bufSize > 0);
+	char *p = buf;
+	size_t len = 0;
+	char c;
+
+	if (buf == 0 || bufSize == 0 || eos()) {
+		return 0;
+	}
+
+	// We don't include the newline character(s) in the buffer, and we
+	// always terminate it - we never read more than len-1 characters.
+
+	// EOF is treated as a line break, unless it was the first character
+	// that was read.
+
+	// 0 is treated as a line break, even though it should never occur in
+	// a text file.
+
+	// DOS and Windows use CRLF line breaks
+	// Unix and OS X use LF line breaks
+	// Macintosh before OS X uses CR line breaks
+
+
+	c = readByte();
+	if (eos() || ioFailed()) {
+		return 0;
+	}
+
+	while (!eos() && len + 1 < bufSize) {
+
+		if (ioFailed())
+			return 0;
+
+		if (c == 0 || c == LF)
+			break;
+
+		if (c == CR) {
+			c = readByte();
+			if (c != LF && !eos())
+				seek(-1, SEEK_CUR);
+			break;
+		}
+
+		*p++ = c;
+		len++;
+
+		c = readByte();
+	}
+
+	// This should fix a bug while using readLine with Common::File
+	// it seems that it sets the eos flag after an invalid read
+	// and at the same time the ioFailed flag
+	// the config file parser fails out of that reason for the new themes
+	if (eos()) {
+		clearIOFailed();
+	}
+
+	*p = 0;
+	return buf;
+}
+
+uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) {
+	dataSize = min(dataSize, _end - _pos);
+
+	dataSize = _parentStream->read(dataPtr, dataSize);
+	_pos += dataSize;
+
+	return dataSize;
+}
+
+SeekableSubReadStream::SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, bool disposeParentStream)
+	: SubReadStream(parentStream, end, disposeParentStream),
+	_parentStream(parentStream),
+	_begin(begin) {
+	assert(_begin <= _end);
+	_pos = _begin;
+	_parentStream->seek(_pos);
+}
+
+void SeekableSubReadStream::seek(int32 offset, int whence) {
+	assert(_pos >= _begin);
+	assert(_pos <= _end);
+
+	switch(whence) {
+	case SEEK_END:
+		offset = size() - offset;
+		// fallthrough
+	case SEEK_SET:
+		_pos = _begin + offset;
+		break;
+	case SEEK_CUR:
+		_pos += offset;
+	}
+
+	assert(_pos >= _begin);
+	assert(_pos <= _end);
+
+	_parentStream->seek(_pos);
+}

Property changes on: src\mixer\stream.cpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/stream.hpp
===================================================================
--- src/mixer/stream.hpp	(revision 0)
+++ src/mixer/stream.hpp	(revision 0)
@@ -0,0 +1,413 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+
+#ifndef COMMON_STREAM_H
+#define COMMON_STREAM_H
+
+class String;
+class MemoryReadStream;
+
+/**
+ * Virtual base class for both ReadStream and WriteStream.
+ */
+class Stream {
+public:
+	virtual ~Stream() {}
+
+	/**
+	 * Returns true if any I/O failure occurred.
+	 * This flag is never cleared automatically. In order to clear it,
+	 * client code has to call clearIOFailed() explicitly.
+	 *
+	 * @todo Instead of returning a plain bool, maybe we should define
+	 *       a list of error codes which can be returned here.
+	 */
+	virtual bool ioFailed() const { return false; }
+
+	/**
+	 * Reset the I/O error status.
+	 */
+	virtual void clearIOFailed() {}
+};
+
+/**
+ * Generic interface for a writable data stream.
+ */
+class WriteStream : virtual public Stream {
+public:
+	/**
+	 * Write data into the stream. Subclasses must implement this
+	 * method; all other write methods are implemented using it.
+	 *
+	 * @param dataPtr	pointer to the data to be written
+	 * @param dataSize	number of bytes to be written
+	 * @return the number of bytes which were actually written.
+	 */
+	virtual uint32 write(const void *dataPtr, uint32 dataSize) = 0;
+
+	/**
+	 * Commit any buffered data to the underlying channel or
+	 * storage medium; unbuffered streams can use the default
+	 * implementation.
+	 */
+	virtual void flush() {}
+
+	// The remaining methods all have default implementations; subclasses
+	// need not (and should not) overload them.
+
+	void writeByte(byte value) {
+		write(&value, 1);
+	}
+
+	void writeSByte(int8 value) {
+		write(&value, 1);
+	}
+
+	void writeUint16LE(uint16 value) {
+		writeByte((byte)(value & 0xff));
+		writeByte((byte)(value >> 8));
+	}
+
+	void writeUint32LE(uint32 value) {
+		writeUint16LE((uint16)(value & 0xffff));
+		writeUint16LE((uint16)(value >> 16));
+	}
+
+	void writeUint16BE(uint16 value) {
+		writeByte((byte)(value >> 8));
+		writeByte((byte)(value & 0xff));
+	}
+
+	void writeUint32BE(uint32 value) {
+		writeUint16BE((uint16)(value >> 16));
+		writeUint16BE((uint16)(value & 0xffff));
+	}
+
+	void writeSint16LE(int16 value) {
+		writeUint16LE((uint16)value);
+	}
+
+	void writeSint32LE(int32 value) {
+		writeUint32LE((uint32)value);
+	}
+
+	void writeSint16BE(int16 value) {
+		writeUint16BE((uint16)value);
+	}
+
+	void writeSint32BE(int32 value) {
+		writeUint32BE((uint32)value);
+	}
+
+	void writeString(const char *str);
+};
+
+
+/**
+ * Generic interface for a readable data stream.
+ */
+class ReadStream : virtual public Stream {
+public:
+	/**
+	 * Returns true if the end of the stream has been reached.
+	 */
+	virtual bool eos() const = 0;
+
+	/**
+	 * Read data from the stream. Subclasses must implement this
+	 * method; all other read methods are implemented using it.
+	 *
+	 * @param dataPtr	pointer to a buffer into which the data is read
+	 * @param dataSize	number of bytes to be read
+	 * @return the number of bytes which were actually read.
+	 */
+	virtual uint32 read(void *dataPtr, uint32 dataSize) = 0;
+
+
+	// The remaining methods all have default implementations; subclasses
+	// need not (and should not) overload them.
+
+	/**
+	 * Read am unsigned byte from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	byte readByte() {
+		byte b = 0;
+		read(&b, 1);
+		return b;
+	}
+
+	/**
+	 * Read a signed byte from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	int8 readSByte() {
+		int8 b = 0;
+		read(&b, 1);
+		return b;
+	}
+
+	/**
+	 * Read an unsigned 16-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	uint16 readUint16LE() {
+		uint16 a = readByte();
+		uint16 b = readByte();
+		return a | (b << 8);
+	}
+
+	/**
+	 * Read an unsigned 32-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	uint32 readUint32LE() {
+		uint32 a = readUint16LE();
+		uint32 b = readUint16LE();
+		return (b << 16) | a;
+	}
+
+	/**
+	 * Read an unsigned 16-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	uint16 readUint16BE() {
+		uint16 b = readByte();
+		uint16 a = readByte();
+		return a | (b << 8);
+	}
+
+	/**
+	 * Read an unsigned 32-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	uint32 readUint32BE() {
+		uint32 b = readUint16BE();
+		uint32 a = readUint16BE();
+		return (b << 16) | a;
+	}
+
+	/**
+	 * Read a signed 16-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	int16 readSint16LE() {
+		return (int16)readUint16LE();
+	}
+
+	/**
+	 * Read a signed 32-bit word stored in little endian (LSB first) order
+	 * from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	int32 readSint32LE() {
+		return (int32)readUint32LE();
+	}
+
+	/**
+	 * Read a signed 16-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	int16 readSint16BE() {
+		return (int16)readUint16BE();
+	}
+
+	/**
+	 * Read a signed 32-bit word stored in big endian (MSB first) order
+	 * from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling ioFailed()).
+	 */
+	int32 readSint32BE() {
+		return (int32)readUint32BE();
+	}
+	
+	/**
+	 * Read the specified amount of data into a malloc'ed buffer
+	 * which then is wrapped into a MemoryReadStream.
+	 * The returned stream might contain less data than requested,
+	 * if reading more failed.
+	 */
+	MemoryReadStream *readStream(uint32 dataSize);
+
+};
+
+
+/**
+ * Interface for a seekable & readable data stream.
+ *
+ * @todo We really need better error handling here!
+ *       Like seek should somehow indicate whether it failed.
+ */
+class SeekableReadStream : virtual public ReadStream {
+public:
+
+	virtual uint32 pos() const = 0;
+	virtual uint32 size() const = 0;
+
+	virtual void seek(int32 offset, int whence = SEEK_SET) = 0;
+
+	void skip(uint32 offset) { seek(offset, SEEK_CUR); }
+
+	/**
+	 * Read one line of text from a CR or CR/LF terminated plain text file.
+	 * This method is a rough analog of the (f)gets function.
+	 *
+	 * @param buf	the buffer to store into
+	 * @param bufSize	the size of the buffer
+	 * @return a pointer to the read string, or NULL if an error occurred
+	 * @note The line terminator (CR or CR/LF) is stripped and not inserted
+	 *       into the buffer.
+	 */
+	virtual char *readLine(char *buf, size_t bufSize);
+};
+
+/**
+ * SubReadStream provides access to a ReadStream restricted to the range
+ * [currentPosition, currentPosition+end).
+ * Manipulating the parent stream directly /will/ mess up a substream.
+ * Likewise, manipulating two substreams of a parent stream will cause them to
+ * step on each others toes.
+ */
+class SubReadStream : virtual public ReadStream {
+protected:
+	ReadStream *_parentStream;
+	uint32 _pos;
+	uint32 _end;
+	bool _disposeParentStream;
+public:
+	SubReadStream(ReadStream *parentStream, uint32 end, bool disposeParentStream = false)
+		: _parentStream(parentStream),
+		  _pos(0),
+		  _end(end),
+		  _disposeParentStream(disposeParentStream) {}
+	~SubReadStream() {
+		if (_disposeParentStream) delete _parentStream;
+	}
+
+	virtual bool eos() const { return _pos == _end; }
+	virtual uint32 read(void *dataPtr, uint32 dataSize);
+};
+
+/*
+ * SeekableSubReadStream provides access to a SeekableReadStream restricted to
+ * the range [begin, end).
+ * The same caveats apply to SeekableSubReadStream as do to SeekableReadStream.
+ */
+class SeekableSubReadStream : public SubReadStream, public SeekableReadStream {
+protected:
+	SeekableReadStream *_parentStream;
+	uint32 _begin;
+public:
+	SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, bool disposeParentStream = false);
+
+	virtual uint32 pos() const { return _pos - _begin; }
+	virtual uint32 size() const { return _end - _begin; }
+
+	virtual void seek(int32 offset, int whence = SEEK_SET);
+};
+
+/**
+ * Simple memory based 'stream', which implements the ReadStream interface for
+ * a plain memory block.
+ */
+class MemoryReadStream : public SeekableReadStream {
+private:
+	const byte * const _ptrOrig;
+	const byte *_ptr;
+	const uint32 _size;
+	uint32 _pos;
+	byte _encbyte;
+	bool _disposeMemory;
+
+public:
+
+	/**
+	 * This constructor takes a pointer to a memory buffer and a length, and
+	 * wraps it. If disposeMemory is true, the MemoryReadStream takes ownership
+	 * of the buffer and hence free's it when destructed.
+	 */
+	MemoryReadStream(const byte *dataPtr, uint32 dataSize, bool disposeMemory = false) :
+		_ptrOrig(dataPtr),
+		_ptr(dataPtr),
+		_size(dataSize),
+		_pos(0),
+		_encbyte(0),
+		_disposeMemory(disposeMemory) {}
+
+	~MemoryReadStream() {
+		if (_disposeMemory)
+			free(const_cast<byte *>(_ptrOrig));
+	}
+
+	void setEnc(byte value) { _encbyte = value; }
+
+	uint32 read(void *dataPtr, uint32 dataSize);
+
+	bool eos() const { return _pos == _size; }
+	uint32 pos() const { return _pos; }
+	uint32 size() const { return _size; }
+
+	void seek(int32 offs, int whence = SEEK_SET);
+};
+
+/**
+ * Simple memory based 'stream', which implements the WriteStream interface for
+ * a plain memory block.
+ */
+class MemoryWriteStream : public WriteStream {
+private:
+	byte *_ptr;
+	const uint32 _bufSize;
+	uint32 _pos;
+public:
+	MemoryWriteStream(byte *buf, uint32 len) : _ptr(buf), _bufSize(len), _pos(0) {}
+
+	uint32 write(const void *dataPtr, uint32 dataSize) {
+		// Write at most as many bytes as are still available...
+		if (dataSize > _bufSize - _pos)
+			dataSize = _bufSize - _pos;
+		memcpy(_ptr, dataPtr, dataSize);
+		_ptr += dataSize;
+		_pos += dataSize;
+		return dataSize;
+	}
+
+	bool eos() const { return _pos == _bufSize; }
+	uint32 pos() const { return _pos; }
+	uint32 size() const { return _bufSize; }
+};
+
+#endif

Property changes on: src\mixer\stream.hpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/wave.cpp
===================================================================
--- src/mixer/wave.cpp	(revision 0)
+++ src/mixer/wave.cpp	(revision 0)
@@ -0,0 +1,170 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../driver.h"
+#include "../sound/sound_driver.hpp"
+#include "../misc/blob.hpp"
+#include "../misc/str.hpp"
+#include "../core/math_func.hpp"
+#include "../core/endian_func.hpp"
+
+#include "stream.hpp"
+#include "mixer.hpp"
+#include "audiostream.hpp"
+#include "wave.hpp"
+
+bool loadWAVFromStream(SeekableReadStream *stream, int &size, int &rate, byte &flags, uint16 *wavType, int *blockAlign_) {
+	const uint32 initialPos = stream->pos();
+	byte buf[4+1];
+
+	buf[4] = 0;
+
+	stream->read(buf, 4);
+	if (memcmp(buf, "RIFF", 4) != 0) {
+		DEBUG(misc, 1, "getWavInfo: No 'RIFF' header");
+		return false;
+	}
+
+	uint32 wavLength = stream->readUint32LE();
+
+	stream->read(buf, 4);
+	if (memcmp(buf, "WAVE", 4) != 0) {
+		DEBUG(misc, 1, "getWavInfo: No 'WAVE' header");
+		return false;
+	}
+
+	stream->read(buf, 4);
+	if (memcmp(buf, "fmt ", 4) != 0) {
+		DEBUG(misc, 1, "getWavInfo: No 'fmt' header");
+		return false;
+	}
+
+	uint32 fmtLength = stream->readUint32LE();
+	if (fmtLength < 16) {
+		// A valid fmt chunk always contains at least 16 bytes
+		DEBUG(misc, 1, "getWavInfo: 'fmt' header is too short");
+		return false;
+	}
+
+	// Next comes the "type" field of the fmt header. Some typical
+	// values for it:
+	// 1  -> uncompressed PCM
+	// 17 -> IMA ADPCM compressed WAVE
+	// See <http://www.saettler.com/RIFFNEW/RIFFNEW.htm> for a more complete
+	// list of common WAVE compression formats...
+	uint16 type = stream->readUint16LE();	// == 1 for PCM data
+	uint16 numChannels = stream->readUint16LE();	// 1 for mono, 2 for stereo
+	uint32 samplesPerSec = stream->readUint32LE();	// in Hz
+	uint32 avgBytesPerSec = stream->readUint32LE();	// == SampleRate * NumChannels * BitsPerSample/8
+
+	uint16 blockAlign = stream->readUint16LE();	// == NumChannels * BitsPerSample/8
+	uint16 bitsPerSample = stream->readUint16LE();	// 8, 16 ...
+	// 8 bit data is unsigned, 16 bit data signed
+
+
+	if (wavType != 0)
+		*wavType = type;
+
+	if (blockAlign_ != 0)
+		*blockAlign_ = blockAlign;
+#if 0
+	printf("WAVE information:\n");
+	printf("  total size: %d\n", wavLength);
+	printf("  fmt size: %d\n", fmtLength);
+	printf("  type: %d\n", type);
+	printf("  numChannels: %d\n", numChannels);
+	printf("  samplesPerSec: %d\n", samplesPerSec);
+	printf("  avgBytesPerSec: %d\n", avgBytesPerSec);
+	printf("  blockAlign: %d\n", blockAlign);
+	printf("  bitsPerSample: %d\n", bitsPerSample);
+#endif
+
+	if (type != 1) {
+		DEBUG(misc, 1, "getWavInfo: only PCM is supported (type %d)", type);
+		return false;
+	}
+
+	if (blockAlign != numChannels * bitsPerSample / 8 && type != 2) {
+		DEBUG(misc, 4, "getWavInfo: blockAlign is invalid");
+	}
+
+	if (avgBytesPerSec != samplesPerSec * blockAlign && type != 2) {
+		DEBUG(misc, 4, "getWavInfo: avgBytesPerSec is invalid");
+	}
+
+	// Prepare the return values.
+	rate = samplesPerSec;
+
+	flags = 0;
+	if (bitsPerSample == 8)		// 8 bit data is unsigned
+		flags |= Mixer::FLAG_UNSIGNED;
+	else if (bitsPerSample == 16)	// 16 bit data is signed little endian
+		flags |= (Mixer::FLAG_16BITS | Mixer::FLAG_LITTLE_ENDIAN);
+	else if (bitsPerSample == 4 && type == 17)	// MS IMA ADPCM compressed. We decompress it
+		flags |= (Mixer::FLAG_16BITS | Mixer::FLAG_LITTLE_ENDIAN);
+	else if (bitsPerSample == 4 && type == 2)	// MS ADPCM compressed. We decompress it
+		flags |= (Mixer::FLAG_16BITS | Mixer::FLAG_LITTLE_ENDIAN);
+	else {
+		DEBUG(misc, 1, "getWavInfo: unsupported bitsPerSample %d", bitsPerSample);
+		return false;
+	}
+
+	if (numChannels == 2)
+		flags |= Mixer::FLAG_STEREO;
+	else if (numChannels != 1) {
+		DEBUG(misc, 1, "getWavInfo: unsupported number of channels %d", numChannels);
+		return false;
+	}
+
+	// It's almost certainly a WAV file, but we still need to find its
+	// 'data' chunk.
+
+	// Skip over the rest of the fmt chunk.
+	int offset = fmtLength - 16;
+
+	do {
+		stream->seek(offset, SEEK_CUR);
+		if (stream->pos() >= initialPos + wavLength + 8) {
+			DEBUG(misc, 1, "getWavInfo: Can't find 'data' chunk");
+			return false;
+		}
+		stream->read(buf, 4);
+		offset = stream->readUint32LE();
+
+#if 0
+		printf("  found a '%s' tag of size %d\n", buf, offset);
+#endif
+	} while (memcmp(buf, "data", 4) != 0);
+
+	// Stream now points at 'offset' bytes of sample data...
+	size = offset;
+
+	return true;
+}
+
+AudioStream *makeWAVStream(SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) {
+	int size, rate;
+	byte *data, flags;
+	uint16 type;
+	int blockAlign;
+
+	if (!loadWAVFromStream(stream, size, rate, flags, &type, &blockAlign))
+		return 0;
+
+	data = (byte *)malloc(size);
+	assert(data);
+	stream->read(data, size);
+
+	// Since we allocated our own buffer for the data, we must set the autofree flag.
+	flags |= Mixer::FLAG_AUTOFREE;
+
+	return makeLinearInputStream(data, size, rate, flags, 0, 0);
+}

Property changes on: src\mixer\wave.cpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/mixer/wave.hpp
===================================================================
--- src/mixer/wave.hpp	(revision 0)
+++ src/mixer/wave.hpp	(revision 0)
@@ -0,0 +1,34 @@
+/* $Id$ */
+
+/*
+ * This file is based upon code taken from the ScummVM project.
+ * ScummVM is licenced under the GNU General Public Licence 2.0.
+ * Please visit http://www.scummvm.org/ for more information.
+ *
+ */
+
+
+#ifndef SOUND_WAVE_H
+#define SOUND_WAVE_H
+
+class AudioStream;
+
+/**
+ * Try to load a WAVE from the given seekable stream. Returns true if
+ * successful. In that case, the stream's seek position will be set to the
+ * start of the audio data, and size, rate and flags contain information
+ * necessary for playback. Currently this function only supports uncompressed
+ * raw PCM data as well as IMA ADPCM.
+ */
+extern bool loadWAVFromStream(SeekableReadStream *stream, int &size, int &rate, byte &flags, uint16 *wavType = 0, int *blockAlign = 0);
+
+/**
+ * Try to load a WAVE from the given seekable stream and create an AudioStream
+ * from that data. Currently this function only supports uncompressed raw PCM
+ * data as well as IMA ADPCM.
+ *
+ * This function uses loadWAVFromStream() internally.
+ */
+AudioStream *makeWAVStream(SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops);
+
+#endif

Property changes on: src\mixer\wave.hpp
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/music_gui.cpp
===================================================================
--- src/music_gui.cpp	(revision 11812)
+++ src/music_gui.cpp	(working copy)
@@ -438,6 +438,7 @@
 				*vol = new_vol;
 				if (vol == &msf.music_vol)
 					MusicVolumeChanged(new_vol);
+
 				SetWindowDirty(w);
 			}
 
Index: src/openttd.cpp
===================================================================
--- src/openttd.cpp	(revision 11812)
+++ src/openttd.cpp	(working copy)
@@ -11,7 +11,7 @@
 #include "openttd.h"
 #include "table/strings.h"
 #include "bridge_map.h"
-#include "mixer.h"
+#include "mixer/mixer.hpp"
 #include "spritecache.h"
 #include "gfxinit.h"
 #include "gui.h"
@@ -89,6 +89,8 @@
 extern void ShowOSErrorBox(const char *buf);
 extern void SetDefaultRailGui();
 
+Mixer *_mixer = NULL;
+
 /* TODO: usrerror() for errors which are not of an internal nature but
  * caused by the user, i.e. missing files or fatal configuration errors.
  * Post-0.4.0 since Celestar doesn't want this in SVN before. --pasky */
@@ -474,9 +476,16 @@
 	/* start the AI */
 	AI_Initialize();
 
+	/* initialise mixer */
+	if (_mixer == NULL)
+	{
+		_mixer = new Mixer();
+		_mixer->setReady(true);
+	}
+
 	/* Sample catalogue */
 	DEBUG(misc, 1, "Loading sound effects...");
-	MxInitialize(11025);
+
 	SoundInitialize("sample.cat");
 
 	/* Initialize FreeType */
Index: src/sound.cpp
===================================================================
--- src/sound.cpp	(revision 11812)
+++ src/sound.cpp	(working copy)
@@ -5,7 +5,6 @@
 #include "stdafx.h"
 #include "openttd.h"
 #include "landscape.h"
-#include "mixer.h"
 #include "sound_func.h"
 #include "fileio.h"
 #include "newgrf_sound.h"
@@ -15,14 +14,22 @@
 #include "map_func.h"
 #include "vehicle_base.h"
 
+#include "mixer/mixer.hpp"
+#include "mixer/audiostream.hpp"
+
+extern Mixer *_mixer;
+
 static uint _file_count;
 static FileEntry *_files;
 MusicFileSettings msf;
 
 // Number of levels of panning per side
-#define PANNING_LEVELS 16
+#define PANNING_LEVELS  127
 
+// Base for mixer SFX IDs
+#define MIXER_SFX_BASE  10
 
+
 static void OpenBankFile(const char *filename)
 {
 	uint count;
@@ -104,57 +111,47 @@
 	return _file_count;
 }
 
-static bool SetBankSource(MixerChannel *mc, uint bank)
+bool SoundInitialize(const char *filename)
 {
+	OpenBankFile(filename);
+	return true;
+}
+
+/* Low level sound player */
+
+static void StartSound(uint sound, int panning, uint volume)
+{
 	const FileEntry *fe;
-	uint i;
 
-	if (bank >= GetNumSounds()) return false;
-	fe = GetSound(bank);
+	if (volume == 0)
+		return;
+	
+	if (sound >= GetNumSounds())
+		return;
 
-	if (fe->file_size == 0) return false;
+	fe = GetSound(sound);
 
+	if (fe->file_size == 0)
+		return;
+
 	int8 *mem = MallocT<int8>(fe->file_size);
-	if (mem == NULL) return false;
+	
+	if (mem == NULL)
+		return;
 
 	FioSeekToFile(fe->file_slot, fe->file_offset);
 	FioReadBlock(mem, fe->file_size);
 
-	for (i = 0; i != fe->file_size; i++)
-		mem[i] += -128; // Convert unsigned sound data to signed
-
 	assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0);
 
-	MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE);
+	panning = Clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
 
-	return true;
+	// play the sound
+	SoundHandle handle;
+	_mixer->playRaw(Mixer::kSFXSoundType, &handle, mem, fe->file_size, fe->rate, Mixer::FLAG_AUTOFREE | Mixer::FLAG_UNSIGNED, MIXER_SFX_BASE + sound, volume, panning, 0, 0); // todo: sort panning, etc
 }
 
-bool SoundInitialize(const char *filename)
-{
-	OpenBankFile(filename);
-	return true;
-}
 
-/* Low level sound player */
-static void StartSound(uint sound, int panning, uint volume)
-{
-	MixerChannel *mc;
-	uint left_vol, right_vol;
-
-	if (volume == 0) return;
-	mc = MxAllocateChannel();
-	if (mc == NULL) return;
-	if (!SetBankSource(mc, sound)) return;
-
-	panning = Clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
-	left_vol = (volume * PANNING_LEVELS) - (volume * panning);
-	right_vol = (volume * PANNING_LEVELS) + (volume * panning);
-	MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS);
-	MxActivateChannel(mc);
-}
-
-
 static const byte _vol_factor_by_zoom[] = {255, 190, 134, 87};
 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_END - ZOOM_LVL_BEGIN);
 
@@ -202,7 +199,8 @@
 {
 	Window* const *wz;
 
-	if (msf.effect_vol == 0) return;
+	if (msf.effect_vol == 0)
+		return;
 
 	FOR_ALL_WINDOWS(wz) {
 		const ViewPort *vp = (*wz)->viewport;
Index: src/sound/cocoa_s.cpp
===================================================================
--- src/sound/cocoa_s.cpp	(revision 11812)
+++ src/sound/cocoa_s.cpp	(working copy)
@@ -13,6 +13,8 @@
 
 #include <AudioUnit/AudioUnit.h>
 
+#include <mach/mach_time.h>
+
 /* Name conflict */
 #define Rect        OTTDRect
 #define Point       OTTDPoint
@@ -21,7 +23,7 @@
 #include "../stdafx.h"
 #include "../debug.h"
 #include "../driver.h"
-#include "../mixer.h"
+#include "../mixer/mixer.hpp"
 #include "../core/endian_func.hpp"
 
 #include "cocoa_s.h"
@@ -34,10 +36,13 @@
 
 static AudioUnit _outputAudioUnit;
 
+extern Mixer *_mixer;
+
 /* The CoreAudio callback */
 static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData)
 {
-	MxMixSamples(ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / 4);
+	if (_mixer != NULL)
+		_mixer->mixCallback(_mixer, (byte *) ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize);
 
 	return noErr;
 }
@@ -54,7 +59,7 @@
 	requestedDesc.mFormatID = kAudioFormatLinearPCM;
 	requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
 	requestedDesc.mChannelsPerFrame = 2;
-	requestedDesc.mSampleRate = GetDriverParamInt(parm, "hz", 11025);
+	requestedDesc.mSampleRate = _sample_rate = GetDriverParamInt(parm, "hz", 44100);
 
 	requestedDesc.mBitsPerChannel = 16;
 	requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
@@ -135,4 +140,22 @@
 	}
 }
 
+uint16 SoundDriver_Cocoa::GetSampleRate()
+{
+	return(_sample_rate);
+}
+
+// returns time in milliseconds since system started - actual time doesn't matter, we just want a reference
+uint32 SoundDriver_Cocoa::GetMillis()
+{
+	uint64 time = mach_absolute_time();
+
+	// get timebase info
+	mach_timebase_info_data_t info;
+	mach_timebase_info(&info);
+
+	// convert to milliseconds and return
+	return(((double) ((1e-6 * ( (double) info.numer) / ((double) info.denom) * time)));
+}
+
 #endif /* WITH_COCOA */
Index: src/sound/cocoa_s.h
===================================================================
--- src/sound/cocoa_s.h	(revision 11812)
+++ src/sound/cocoa_s.h	(working copy)
@@ -10,6 +10,12 @@
 	/* virtual */ const char *Start(const char * const *param);
 
 	/* virtual */ void Stop();
+
+	/* virtual */ uint16 GetSampleRate();
+	/* virtual */ uint32 GetMillis();
+
+private:
+	uint16 _sample_rate;
 };
 
 class FSoundDriver_Cocoa: public SoundDriverFactory<FSoundDriver_Cocoa> {
Index: src/sound/null_s.h
===================================================================
--- src/sound/null_s.h	(revision 11812)
+++ src/sound/null_s.h	(working copy)
@@ -10,6 +10,9 @@
 	/* virtual */ const char *Start(const char * const *param) { return NULL; }
 
 	/* virtual */ void Stop() { }
+
+	/* virtual */ uint16 GetSampleRate() { return(0); }
+	/* virtual */ uint32 GetMillis() { return(0); }
 };
 
 class FSoundDriver_Null: public SoundDriverFactory<FSoundDriver_Null> {
Index: src/sound/sdl_s.cpp
===================================================================
--- src/sound/sdl_s.cpp	(revision 11812)
+++ src/sound/sdl_s.cpp	(working copy)
@@ -5,16 +5,19 @@
 #include "../stdafx.h"
 
 #include "../driver.h"
-#include "../mixer.h"
+#include "../mixer/mixer.hpp"
 #include "../sdl.h"
 #include "sdl_s.h"
 #include <SDL.h>
 
+extern Mixer *_mixer;
+
 static FSoundDriver_SDL iFSoundDriver_SDL;
 
 static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len)
 {
-	MxMixSamples(stream, len / 4);
+	if (_mixer != NULL)
+		_mixer->mixCallback(_mixer, (byte *) stream, len);
 }
 
 const char *SoundDriver_SDL::Start(const char * const *parm)
@@ -24,7 +27,7 @@
 	const char *s = SdlOpen(SDL_INIT_AUDIO);
 	if (s != NULL) return s;
 
-	spec.freq = GetDriverParamInt(parm, "hz", 11025);
+	spec.freq = _sample_rate = GetDriverParamInt(parm, "hz", 44100);
 	spec.format = AUDIO_S16SYS;
 	spec.channels = 2;
 	spec.samples = 512;
@@ -40,4 +43,15 @@
 	SdlClose(SDL_INIT_AUDIO);
 }
 
+uint16 SoundDriver_SDL::GetSampleRate()
+{
+	return(_sample_rate);
+}
+
+// returns time in milliseconds since system started - actual time doesn't matter, we just want a reference
+uint32 SoundDriver_SDL::GetMillis()
+{
+	return(SDL_GetTicks());
+}
+
 #endif /* WITH_SDL */
Index: src/sound/sdl_s.h
===================================================================
--- src/sound/sdl_s.h	(revision 11812)
+++ src/sound/sdl_s.h	(working copy)
@@ -10,6 +10,12 @@
 	/* virtual */ const char *Start(const char * const *param);
 
 	/* virtual */ void Stop();
+
+	/* virtual */ uint16 GetSampleRate();
+	/* virtual */ uint32 GetMillis();
+
+private:
+	uint16 _sample_rate;
 };
 
 class FSoundDriver_SDL: public SoundDriverFactory<FSoundDriver_SDL> {
Index: src/sound/sound_driver.hpp
===================================================================
--- src/sound/sound_driver.hpp	(revision 11812)
+++ src/sound/sound_driver.hpp	(working copy)
@@ -6,6 +6,9 @@
 #include "../driver.h"
 
 class SoundDriver: public Driver {
+public:
+	virtual uint16 GetSampleRate() = 0;
+	virtual uint32 GetMillis() = 0;
 };
 
 class SoundDriverFactoryBase: public DriverFactoryBase {
Index: src/sound/win32_s.cpp
===================================================================
--- src/sound/win32_s.cpp	(revision 11812)
+++ src/sound/win32_s.cpp	(working copy)
@@ -3,8 +3,8 @@
 #include "../stdafx.h"
 #include "../openttd.h"
 #include "../driver.h"
-#include "../mixer.h"
 #include "../core/alloc_func.hpp"
+#include "../mixer/mixer.hpp"
 #include "win32_s.h"
 #include <windows.h>
 #include <mmsystem.h>
@@ -15,6 +15,9 @@
 static WAVEHDR _wave_hdr[2];
 static int _bufsize;
 
+extern Mixer *_mixer;
+
+
 static void PrepareHeader(WAVEHDR *hdr)
 {
 	hdr->dwBufferLength = _bufsize * 4;
@@ -31,7 +34,9 @@
 
 	for (hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
 		if (!(hdr->dwFlags & WHDR_INQUEUE)) {
-			MxMixSamples(hdr->lpData, hdr->dwBufferLength / 4);
+			if (_mixer != NULL)
+				_mixer->mixCallback(_mixer, (byte *) hdr->lpData, hdr->dwBufferLength);
+
 			if (waveOutWrite(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
 				error("waveOutWrite failed");
 		}
@@ -55,11 +60,11 @@
 	wfex.wFormatTag = WAVE_FORMAT_PCM;
 	wfex.nChannels = 2;
 	wfex.wBitsPerSample = 16;
-	wfex.nSamplesPerSec = GetDriverParamInt(parm, "hz", 11025);
+	wfex.nSamplesPerSec = _sample_rate = GetDriverParamInt(parm, "hz", 44100); // was 11025
 	wfex.nBlockAlign = (wfex.nChannels * wfex.wBitsPerSample) / 8;
 	wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
 
-	_bufsize = GetDriverParamInt(parm, "bufsize", 1024);
+	_bufsize = GetDriverParamInt(parm, "bufsize", 4096); // was 1024
 
 	if (waveOutOpen(&_waveout, WAVE_MAPPER, &wfex, (DWORD_PTR)&waveOutProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
 		return "waveOutOpen failed";
@@ -80,3 +85,15 @@
 	waveOutUnprepareHeader(waveout, &_wave_hdr[1], sizeof(WAVEHDR));
 	waveOutClose(waveout);
 }
+
+uint16 SoundDriver_Win32::GetSampleRate()
+{
+	return(_sample_rate);
+}
+
+// returns time in milliseconds since system started - actual time doesn't matter, we just want a reference
+uint32 SoundDriver_Win32::GetMillis()
+{
+	return(GetTickCount());
+}
+
Index: src/sound/win32_s.h
===================================================================
--- src/sound/win32_s.h	(revision 11812)
+++ src/sound/win32_s.h	(working copy)
@@ -10,6 +10,12 @@
 	/* virtual */ const char *Start(const char * const *param);
 
 	/* virtual */ void Stop();
+
+	/* virtual */ uint16 GetSampleRate();
+	/* virtual */ uint32 GetMillis();
+
+private:
+	uint16 _sample_rate;
 };
 
 class FSoundDriver_Win32: public SoundDriverFactory<FSoundDriver_Win32> {
