[Scummvm-cvs-logs] SF.net SVN: scummvm: [31100] residual/trunk/mixer
aquadran at users.sourceforge.net
aquadran at users.sourceforge.net
Tue Mar 11 00:04:55 CET 2008
Revision: 31100
http://scummvm.svn.sourceforge.net/scummvm/?rev=31100&view=rev
Author: aquadran
Date: 2008-03-10 16:04:55 -0700 (Mon, 10 Mar 2008)
Log Message:
-----------
synced imuse digital with scummvm imuse and related stuff
Modified Paths:
--------------
residual/trunk/mixer/audiostream.cpp
residual/trunk/mixer/audiostream.h
residual/trunk/mixer/mixer.cpp
residual/trunk/mixer/mixer.h
residual/trunk/mixer/rate.cpp
residual/trunk/mixer/rate.h
Modified: residual/trunk/mixer/audiostream.cpp
===================================================================
--- residual/trunk/mixer/audiostream.cpp 2008-03-10 20:34:34 UTC (rev 31099)
+++ residual/trunk/mixer/audiostream.cpp 2008-03-10 23:04:55 UTC (rev 31100)
@@ -1,19 +1,19 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
- * Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
+ * Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
@@ -22,18 +22,39 @@
#include "common/sys.h"
#include "common/debug.h"
+#include "common/list.h"
#include "engine/backend/driver.h"
#include "mixer/mixer.h"
#include "mixer/audiostream.h"
-#define READSAMPLE(is16Bit, isUnsigned, ptr) \
- ((is16Bit ? READ_BE_UINT16(ptr) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
-
+// This used to be an inline template function, but
+// buggy template function handling in MSVC6 forced
+// us to go with the macro approach. So far this is
+// the only template function that MSVC6 seemed to
+// compile incorrectly. Knock on wood.
#define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \
((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
+
+namespace Audio {
+
+#pragma mark -
+#pragma mark --- LinearMemoryStream ---
+#pragma mark -
+
+
+/**
+ * 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:
@@ -44,7 +65,6 @@
const int _rate;
const byte *_origPtr;
- inline bool eosIntern() const { return _ptr >= _end; };
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) {
@@ -61,57 +81,127 @@
}
if (stereo) // Stereo requires even sized data
assert(len % 2 == 0);
-
+
_origPtr = autoFreeMemory ? ptr : 0;
}
- ~LinearMemoryStream() {
+ virtual ~LinearMemoryStream() {
free(const_cast<byte *>(_origPtr));
}
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return stereo; }
- bool endOfData() const { return eosIntern(); }
+ 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 && !eosIntern()) {
- const int len = MIN(numSamples, samples + (int)(_end - _ptr) / (is16Bit ? 2 : 1));
- while (samples < len) {
+ int samples = numSamples;
+ while (samples > 0 && _ptr < _end) {
+ int len = MIN(samples, (int)(_end - _ptr) / (is16Bit ? 2 : 1));
+ samples -= len;
+ do {
*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
_ptr += (is16Bit ? 2 : 1);
- samples++;
- }
+ } while (--len);
// Loop, if looping was specified
- if (_loopPtr && eosIntern()) {
+ if (_loopPtr && _ptr >= _end) {
_ptr = _loopPtr;
_end = _loopEnd;
}
}
- return samples;
+ return numSamples-samples;
}
+
+#pragma mark -
+#pragma mark --- Input stream factory ---
+#pragma mark -
+
+/* 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 & Audio::Mixer::FLAG_STEREO) != 0;
+ const bool is16Bit = (flags & Audio::Mixer::FLAG_16BITS) != 0;
+ const bool isUnsigned = (flags & Audio::Mixer::FLAG_UNSIGNED) != 0;
+ const bool isLE = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0;
+ const bool autoFree = (flags & Audio::Mixer::FLAG_AUTOFREE) != 0;
+
+ uint loopOffset = 0, loopLen = 0;
+ if (flags & Audio::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);
+ }
+ }
+}
+
+
+#pragma mark -
+#pragma mark --- Appendable audio stream ---
+#pragma mark -
+
+struct Buffer {
+ byte *start;
+ byte *end;
+};
+
/**
* Wrapped memory stream.
*/
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
class AppendableMemoryStream : public AppendableAudioStream {
protected:
- MutexRef _mutex;
- byte *_bufferStart;
- byte *_bufferEnd;
- byte *_pos;
- byte *_end;
+ // A mutex to avoid access problems (causing e.g. corruption of
+ // the linked list) in thread aware environments.
+ Common::Mutex _mutex;
+
+ // List of all queued buffers
+ Common::List<Buffer> _bufferQueue;
+
+ // Position in the front buffer, if any
bool _finalized;
const int _rate;
+ byte *_pos;
- inline bool eosIntern() const { return _end == _pos; };
+ inline bool eosIntern() const { return _bufferQueue.empty(); };
public:
- AppendableMemoryStream(int rate, uint bufferSize);
+ AppendableMemoryStream(int rate);
~AppendableMemoryStream();
int readBuffer(int16 *buffer, const int numSamples);
@@ -121,135 +211,99 @@
int getRate() const { return _rate; }
- void append(const byte *data, uint32 len);
+ void queueBuffer(byte *data, uint32 size);
void finish() { _finalized = true; }
};
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::AppendableMemoryStream(int rate, uint bufferSize)
- : _finalized(false), _rate(rate) {
+AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::AppendableMemoryStream(int rate)
+ : _finalized(false), _rate(rate), _pos(0) {
- // Verify the buffer size is sane
- if (is16Bit && stereo)
- assert((bufferSize & 3) == 0);
- else if (is16Bit || stereo)
- assert((bufferSize & 1) == 0);
-
- _bufferStart = (byte *)malloc(bufferSize);
- _pos = _end = _bufferStart;
- _bufferEnd = _bufferStart + bufferSize;
-
- _mutex = g_driver->createMutex();
}
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::~AppendableMemoryStream() {
- free(_bufferStart);
- g_driver->deleteMutex(_mutex);
+ // Clear the queue
+ Common::List<Buffer>::iterator iter;
+ for (iter = _bufferQueue.begin(); iter != _bufferQueue.end(); ++iter)
+ delete[] iter->start;
}
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
- StackLock lock(_mutex);
+ Common::StackLock lock(_mutex);
- int samples = 0;
- while (samples < numSamples && !eosIntern()) {
- // Wrap around?
- if (_pos >= _bufferEnd)
- _pos = _pos - (_bufferEnd - _bufferStart);
+ int samples = numSamples;
+ while (samples > 0 && !eosIntern()) {
+ Buffer buf = *_bufferQueue.begin();
+ if (_pos == 0)
+ _pos = buf.start;
- const byte *endMarker = (_pos > _end) ? _bufferEnd : _end;
- const int len = MIN(numSamples, samples + (int)(endMarker - _pos) / (is16Bit ? 2 : 1));
- while (samples < len) {
+ assert(buf.start <= _pos && _pos <= buf.end);
+ const int samplesLeftInCurBuffer = buf.end - _pos;
+ if (samplesLeftInCurBuffer == 0) {
+ delete [] buf.start;
+ _bufferQueue.erase(_bufferQueue.begin());
+ _pos = 0;
+ continue;
+ }
+
+ int len = MIN(samples, samplesLeftInCurBuffer / (is16Bit ? 2 : 1));
+ samples -= len;
+ do {
*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _pos, isLE);
_pos += (is16Bit ? 2 : 1);
- samples++;
- }
+ } while (--len);
}
- return samples;
+ return numSamples-samples;
}
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-void AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::append(const byte *data, uint32 len) {
- StackLock lock(_mutex);
+void AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::queueBuffer(byte *data, uint32 size) {
+ Common::StackLock lock(_mutex);
// Verify the buffer size is sane
if (is16Bit && stereo)
- assert((len & 3) == 0);
+ assert((size & 3) == 0);
else if (is16Bit || stereo)
- assert((len & 1) == 0);
-
+ assert((size & 1) == 0);
+
// Verify that the stream has not yet been finalized (by a call to finish())
assert(!_finalized);
- if (_end + len > _bufferEnd) {
- // Wrap-around case
- uint32 size_to_end_of_buffer = _bufferEnd - _end;
- len -= size_to_end_of_buffer;
- if ((_end < _pos) || (_bufferStart + len >= _pos)) {
- warning("AppendableMemoryStream: buffer overflow (A)");
- return;
- }
- memcpy(_end, data, size_to_end_of_buffer);
- memcpy(_bufferStart, data + size_to_end_of_buffer, len);
- _end = _bufferStart + len;
- } else {
- if ((_end < _pos) && (_end + len >= _pos)) {
- warning("AppendableMemoryStream: buffer overflow (B)");
- return;
- }
- memcpy(_end, data, len);
- _end += len;
- }
-}
+ // Queue the buffer
+ Buffer buf = {data, data+size};
+ _bufferQueue.push_back(buf);
-#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(int rate, byte _flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen) {
- const bool isStereo = (_flags & SoundMixer::FLAG_STEREO) != 0;
- const bool is16Bit = (_flags & SoundMixer::FLAG_16BITS) != 0;
- const bool isUnsigned = (_flags & SoundMixer::FLAG_UNSIGNED) != 0;
- const bool isLE = (_flags & SoundMixer::FLAG_LITTLE_ENDIAN) != 0;
- const bool autoFree = (_flags & SoundMixer::FLAG_AUTOFREE) != 0;
-
- 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);
- }
- }
+#if 0
+ // Output some stats
+ uint totalSize = 0;
+ Common::List<Buffer>::iterator iter;
+ for (iter = _bufferQueue.begin(); iter != _bufferQueue.end(); ++iter)
+ totalSize += iter->end - iter->start;
+ printf("AppendableMemoryStream::queueBuffer: added a %d byte buf, a total of %d bytes are queued\n",
+ size, totalSize);
+#endif
}
+
#define MAKE_WRAPPED(STEREO, UNSIGNED) \
if (is16Bit) { \
if (isLE) \
- return new AppendableMemoryStream<STEREO, true, UNSIGNED, true>(rate, len); \
+ return new AppendableMemoryStream<STEREO, true, UNSIGNED, true>(rate); \
else \
- return new AppendableMemoryStream<STEREO, true, UNSIGNED, false>(rate, len); \
+ return new AppendableMemoryStream<STEREO, true, UNSIGNED, false>(rate); \
} else \
- return new AppendableMemoryStream<STEREO, false, UNSIGNED, false>(rate, len)
+ return new AppendableMemoryStream<STEREO, false, UNSIGNED, false>(rate)
-AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len) {
- const bool isStereo = (_flags & SoundMixer::FLAG_STEREO) != 0;
- const bool is16Bit = (_flags & SoundMixer::FLAG_16BITS) != 0;
- const bool isUnsigned = (_flags & SoundMixer::FLAG_UNSIGNED) != 0;
- const bool isLE = (_flags & SoundMixer::FLAG_LITTLE_ENDIAN) != 0;
-
+AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags) {
+ const bool isStereo = (_flags & Audio::Mixer::FLAG_STEREO) != 0;
+ const bool is16Bit = (_flags & Audio::Mixer::FLAG_16BITS) != 0;
+ const bool isUnsigned = (_flags & Audio::Mixer::FLAG_UNSIGNED) != 0;
+ const bool isLE = (_flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0;
+
if (isStereo) {
if (isUnsigned) {
MAKE_WRAPPED(true, true);
@@ -264,3 +318,6 @@
}
}
}
+
+
+} // End of namespace Audio
Modified: residual/trunk/mixer/audiostream.h
===================================================================
--- residual/trunk/mixer/audiostream.h 2008-03-10 20:34:34 UTC (rev 31099)
+++ residual/trunk/mixer/audiostream.h 2008-03-10 23:04:55 UTC (rev 31100)
@@ -1,19 +1,19 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
- * Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
+ * Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
@@ -27,8 +27,11 @@
#include "common/platform.h"
+namespace Audio {
+
/**
- * Generic input stream for the resampling code.
+ * Generic audio input stream. Subclasses of this are used to feed arbitrary
+ * sampled audio data into ScummVM's audio mixer.
*/
class AudioStream {
public:
@@ -40,14 +43,19 @@
* 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.
+ * 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
@@ -56,7 +64,7 @@
* 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
@@ -71,30 +79,46 @@
virtual int getRate() const = 0;
};
-class AppendableAudioStream : public AudioStream {
+/**
+ * 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);
+
+/**
+ * An audio stream to which additional data can be appended on-the-fly.
+ * Used by SMUSH, iMuseDigital, and the Kyrandia 3 VQA player.
+ */
+class AppendableAudioStream : public Audio::AudioStream {
public:
- virtual void append(const byte *data, uint32 len) = 0;
+
+ /**
+ * Queue another audio data buffer for playback. The stream
+ * will playback all queued buffers, in the order they were
+ * queued. After all data contained in them has been played,
+ * the buffer will be delete[]'d (so make sure to allocate them
+ * with new[], not with malloc).
+ */
+ virtual void queueBuffer(byte *data, uint32 size) = 0;
+
+ /**
+ * Mark the stream as finished, that is, signal that no further data
+ * will be appended to it. Only after this has been done can the
+ * AppendableAudioStream ever 'end' (
+ */
virtual void finish() = 0;
};
-class ZeroInputStream : public AudioStream {
-private:
- int _len;
-public:
- ZeroInputStream(uint len) : _len(len) { }
- int readBuffer(int16 *buffer, const int numSamples) {
- int samples = MIN(_len, numSamples);
- memset(buffer, 0, samples * 2);
- _len -= samples;
- return samples;
- }
- bool isStereo() const { return false; }
- bool eos() const { return _len <= 0; }
-
- int getRate() const { return -1; }
-};
+/**
+ * Factory function for an AppendableAudioStream. The rate and flags
+ * parameters are analog to those used in makeLinearInputStream.
+ */
+AppendableAudioStream *makeAppendableAudioStream(int rate, byte flags);
-AudioStream *makeLinearInputStream(int rate, byte _flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen);
-AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len);
+} // End of namespace Audio
+
#endif
Modified: residual/trunk/mixer/mixer.cpp
===================================================================
--- residual/trunk/mixer/mixer.cpp 2008-03-10 20:34:34 UTC (rev 31099)
+++ residual/trunk/mixer/mixer.cpp 2008-03-10 23:04:55 UTC (rev 31100)
@@ -1,19 +1,19 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
- * Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
+ * Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
@@ -30,32 +30,38 @@
#include "mixer/rate.h"
#include "mixer/audiostream.h"
-SoundMixer *g_mixer = NULL;
+namespace Audio {
+#pragma mark -
+#pragma mark --- Channel classes ---
+#pragma mark -
+
+
/**
* Channels used by the sound mixer.
*/
class Channel {
+public:
+ const Mixer::SoundType _type;
+ SoundHandle _handle;
private:
- SoundMixer *_mixer;
- PlayingSoundHandle *_handle;
+ Mixer *_mixer;
bool _autofreeStream;
bool _permanent;
byte _volume;
int8 _balance;
- bool _paused;
+ int _pauseLevel;
int _id;
uint32 _samplesConsumed;
uint32 _samplesDecoded;
+ uint32 _mixerTimeStamp;
protected:
RateConverter *_converter;
AudioStream *_input;
public:
-
- Channel(SoundMixer *mixer, PlayingSoundHandle *handle, bool isMusic, int id = -1);
- Channel(SoundMixer *mixer, PlayingSoundHandle *handle, AudioStream *input, bool autofreeStream, bool isMusic, bool reverseStereo = false, int id = -1, bool permanent = false);
+ 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);
@@ -67,10 +73,15 @@
return _input->endOfStream();
}
void pause(bool paused) {
- _paused = paused;
+ //assert((paused && _pauseLevel >= 0) || (!paused && _pauseLevel));
+
+ if (paused)
+ _pauseLevel++;
+ else if (_pauseLevel > 0)
+ _pauseLevel--;
}
bool isPaused() {
- return _paused;
+ return _pauseLevel != 0;
}
void setVolume(const byte volume) {
_volume = volume;
@@ -85,116 +96,91 @@
};
-SoundMixer::SoundMixer() {
- _mutex = g_driver->createMutex();
- _premixChannel = NULL;
- _globalVolume = 0;
- _paused = false;
+#pragma mark -
+#pragma mark --- Mixer ---
+#pragma mark -
- for (int i = 0; i != NUM_CHANNELS; i++)
- _channels[i] = NULL;
- _mixerReady = g_driver->setSoundCallback(mixCallback, this);
- _outputRate = (uint)g_driver->getOutputSampleRate();
+Mixer::Mixer() {
+ _handleSeed = 0;
- if (_outputRate == 0)
- error("OSystem returned invalid sample rate");
-}
+ int i = 0;
-SoundMixer::~SoundMixer() {
- g_driver->clearSoundCallback();
- stopAll(true);
+ for (i = 0; i < ARRAYSIZE(_volumeForSoundType); i++)
+ _volumeForSoundType[i] = kMaxMixerVolume;
- delete _premixChannel;
- _premixChannel = NULL;
+ for (i = 0; i != NUM_CHANNELS; i++)
+ _channels[i] = 0;
- g_driver->deleteMutex(_mutex);
+ _mixerReady = false;
}
-bool SoundMixer::isPaused() {
- return _paused;
+Mixer::~Mixer() {
+ for (int i = 0; i != NUM_CHANNELS; i++)
+ delete _channels[i];
}
-void SoundMixer::setupPremix(AudioStream *stream) {
- StackLock lock(_mutex);
+uint Mixer::getOutputRate() const {
+ return (uint)g_driver->getOutputSampleRate();
+}
- delete _premixChannel;
- _premixChannel = NULL;
+void Mixer::insertChannel(SoundHandle *handle, Channel *chan) {
- if (stream == NULL)
- return;
-
- // Create the channel
- _premixChannel = new Channel(this, NULL, stream, false, true);
-}
-
-void SoundMixer::insertChannel(PlayingSoundHandle *handle, Channel *chan) {
int index = -1;
-
for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] == NULL) {
+ if (_channels[i] == 0) {
index = i;
break;
}
}
if (index == -1) {
- warning("SoundMixer::out of mixer slots");
+ warning("Mixer::out of mixer slots");
delete chan;
return;
}
_channels[index] = chan;
- if (handle)
- handle->setIndex(index);
+ chan->_handle._val = index + (_handleSeed * NUM_CHANNELS);
+ _handleSeed++;
+ if (handle) {
+ *handle = chan->_handle;
+ }
}
-void SoundMixer::playRaw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags,
- int id, byte volume, int8 balance, uint32 loopStart, uint32 loopEnd) {
- StackLock lock(_mutex);
+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) {
- // Prevent duplicate sounds
- if (id != -1) {
- for (int i = 0; i != NUM_CHANNELS; i++)
- if (_channels[i] != NULL && _channels[i]->getId() == id) {
- if ((flags & SoundMixer::FLAG_AUTOFREE) != 0)
- free(sound);
- return;
- }
- }
-
// Create the input stream
- AudioStream *input;
- if (flags & SoundMixer::FLAG_LOOP) {
- if (loopEnd == 0) {
- input = makeLinearInputStream(rate, flags, (byte *)sound, size, 0, size);
- } else {
- assert(loopStart < loopEnd && loopEnd <= size);
- input = makeLinearInputStream(rate, flags, (byte *)sound, size, loopStart, loopEnd - loopStart);
- }
- } else {
- input = makeLinearInputStream(rate, flags, (byte *)sound, size, 0, 0);
- }
+ AudioStream *input = makeLinearInputStream((byte *)sound, size, rate, flags, loopStart, loopEnd);
- // Create the channel
- Channel *chan = new Channel(this, handle, input, true, false, (flags & SoundMixer::FLAG_REVERSE_STEREO) != 0, id);
- chan->setVolume(volume);
- chan->setBalance(balance);
- insertChannel(handle, chan);
+ // Play it
+ playInputStream(type, handle, input, id, volume, balance, true, false, ((flags & Mixer::FLAG_REVERSE_STEREO) != 0));
}
-void SoundMixer::playInputStream(PlayingSoundHandle *handle, AudioStream *input, bool isMusic,
- int id, byte volume, int8 balance, bool autofreeStream, bool permanent) {
- StackLock lock(_mutex);
+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 == NULL) {
- warning("input stream is NULL");
+ if (input == 0) {
+ warning("input stream is 0");
return;
}
// Prevent duplicate sounds
if (id != -1) {
for (int i = 0; i != NUM_CHANNELS; i++)
- if (_channels[i] != NULL && _channels[i]->getId() == id) {
+ if (_channels[i] != 0 && _channels[i]->getId() == id) {
if (autofreeStream)
delete input;
return;
@@ -202,182 +188,194 @@
}
// Create the channel
- Channel *chan = new Channel(this, handle, input, autofreeStream, isMusic, false, id, permanent);
+ Channel *chan = new Channel(this, type, input, autofreeStream, reverseStereo, id, permanent);
chan->setVolume(volume);
chan->setBalance(balance);
insertChannel(handle, chan);
}
-void SoundMixer::mix(int16 *buf, uint len) {
- StackLock lock(_mutex);
+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));
- if (!_paused) {
- if (_premixChannel)
- _premixChannel->mix(buf, len);
-
- // now mix all channels
- for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i]) {
- if (_channels[i]->isFinished()) {
- delete _channels[i];
- _channels[i] = NULL;
- } else if (!_channels[i]->isPaused())
- _channels[i]->mix(buf, len);
- }
+ // 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 SoundMixer::mixCallback(void *s, byte *samples, int 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).
- ((SoundMixer *)s)->mix((int16 *)samples, len >> 2);
+ ((Mixer *)s)->mix((int16 *)samples, len >> 2);
}
-void SoundMixer::stopAll(bool force) {
- StackLock lock(_mutex);
+void Mixer::stopAll() {
+ Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] != NULL) {
- if (force || !_channels[i]->isPermanent()) {
- delete _channels[i];
- _channels[i] = NULL;
- }
+ if (_channels[i] != 0 && !_channels[i]->isPermanent()) {
+ delete _channels[i];
+ _channels[i] = 0;
}
}
}
-void SoundMixer::stopID(int id) {
- StackLock lock(_mutex);
+void Mixer::stopID(int id) {
+ Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] != NULL && _channels[i]->getId() == id) {
+ if (_channels[i] != 0 && _channels[i]->getId() == id) {
delete _channels[i];
- _channels[i] = NULL;
+ _channels[i] = 0;
}
}
}
-void SoundMixer::stopHandle(PlayingSoundHandle handle) {
- StackLock lock(_mutex);
+void Mixer::stopHandle(SoundHandle handle) {
+ Common::StackLock lock(_mutex);
// Simply ignore stop requests for handles of sounds that already terminated
- if (!handle.isActive())
+ const int index = handle._val % NUM_CHANNELS;
+ if (!_channels[index] || _channels[index]->_handle._val != handle._val)
return;
- int index = handle.getIndex();
+ delete _channels[index];
+ _channels[index] = 0;
+}
- if ((index < 0) || (index >= NUM_CHANNELS)) {
- warning("soundMixer::stopHandle has invalid index %d", index);
+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;
- }
- if (_channels[index]) {
- delete _channels[index];
- _channels[index] = NULL;
- }
+ _channels[index]->setVolume(volume);
}
-void SoundMixer::setChannelVolume(PlayingSoundHandle handle, byte volume) {
- StackLock lock(_mutex);
+void Mixer::setChannelBalance(SoundHandle handle, int8 balance) {
+ Common::StackLock lock(_mutex);
- if (!handle.isActive())
+ const int index = handle._val % NUM_CHANNELS;
+ if (!_channels[index] || _channels[index]->_handle._val != handle._val)
return;
- int index = handle.getIndex();
-
- if ((index < 0) || (index >= NUM_CHANNELS)) {
- warning("soundMixer::setChannelVolume has invalid index %d", index);
- return;
- }
-
- if (_channels[index])
- _channels[index]->setVolume(volume);
+ _channels[index]->setBalance(balance);
}
-void SoundMixer::setChannelBalance(PlayingSoundHandle handle, int8 balance) {
- StackLock lock(_mutex);
+uint32 Mixer::getSoundElapsedTime(SoundHandle handle) {
+ Common::StackLock lock(_mutex);
- if (!handle.isActive())
- return;
+ const int index = handle._val % NUM_CHANNELS;
+ if (!_channels[index] || _channels[index]->_handle._val != handle._val)
+ return 0;
- int index = handle.getIndex();
+ return _channels[index]->getElapsedTime();
+}
- if ((index < 0) || (index >= NUM_CHANNELS)) {
- warning("soundMixer::setChannelBalance has invalid index %d", index);
- return;
+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);
+ }
}
-
- if (_channels[index])
- _channels[index]->setBalance(balance);
}
-void SoundMixer::pauseAll(bool paused) {
- _paused = paused;
-}
-
-void SoundMixer::pauseID(int id, bool paused) {
- StackLock lock(_mutex);
+void Mixer::pauseID(int id, bool paused) {
+ Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] != NULL && _channels[i]->getId() == id) {
+ if (_channels[i] != 0 && _channels[i]->getId() == id) {
_channels[i]->pause(paused);
return;
}
}
}
-void SoundMixer::pauseHandle(PlayingSoundHandle handle, bool paused) {
- StackLock lock(_mutex);
+void Mixer::pauseHandle(SoundHandle handle, bool paused) {
+ Common::StackLock lock(_mutex);
- // Simply ignore pause/unpause requests for handles of sound that alreayd terminated
- if (!handle.isActive())
+ // 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;
- int index = handle.getIndex();
+ _channels[index]->pause(paused);
+}
- if ((index < 0) || (index >= NUM_CHANNELS)) {
- warning("soundMixer::pauseHandle has invalid index %d", index);
- return;
- }
+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;
+}
- if (_channels[index])
- _channels[index]->pause(paused);
+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 SoundMixer::isSoundIDActive(int id) {
- StackLock lock(_mutex);
+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]->getId() == id)
+ if (_channels[i] && _channels[i]->_type == type)
return true;
return false;
}
-void SoundMixer::setVolume(int volume) {
+void Mixer::setVolumeForSoundType(SoundType type, int volume) {
+ assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType));
+
// Check range
- if (volume > 256)
- volume = 256;
+ if (volume > kMaxMixerVolume)
+ volume = kMaxMixerVolume;
else if (volume < 0)
volume = 0;
-
- _globalVolume = volume;
+
+ // 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 < ARRAYSIZE(_volumeForSoundType));
-Channel::Channel(SoundMixer *mixer, PlayingSoundHandle *handle, bool /*isMusic*/, int id)
- : _mixer(mixer), _handle(handle), _autofreeStream(true),
- _volume(255), _balance(0), _paused(false), _id(id), _samplesConsumed(0),
- _samplesDecoded(0), _converter(0), _input(NULL) {
- assert(mixer);
+ return _volumeForSoundType[type];
}
-Channel::Channel(SoundMixer *mixer, PlayingSoundHandle *handle, AudioStream *input,
- bool autofreeStream, bool /*isMusic*/, bool reverseStereo, int id, bool permanent)
- : _mixer(mixer), _handle(handle), _autofreeStream(autofreeStream),
- _permanent(permanent), _volume(255), _balance(0), _paused(false), _id(id),
- _samplesConsumed(0), _samplesDecoded(0), _converter(0), _input(input) {
+
+#pragma mark -
+#pragma mark --- Channel implementations ---
+#pragma mark -
+
+
+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), _pauseLevel(0), _id(id), _samplesConsumed(0),
+ _samplesDecoded(0), _mixerTimeStamp(0), _converter(0), _input(input), _permanent(permanent) {
assert(mixer);
assert(input);
@@ -389,8 +387,6 @@
delete _converter;
if (_autofreeStream)
delete _input;
- if (_handle)
- _handle->resetIndex();
}
/* len indicates the number of sample *pairs*. So a value of
@@ -410,27 +406,55 @@
// 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 - 256.
+ // volume is in the range 0 - kMaxMixerVolume.
// Hence, the vol_l/vol_r values will be in that range, too
-
- int vol = _mixer->getVolume() * _volume;
+
+ int vol = _mixer->getVolumeForSoundType(_type) * _volume;
st_volume_t vol_l, vol_r;
if (_balance == 0) {
- vol_l = vol / 255;
- vol_r = vol / 255;
+ vol_l = vol / Mixer::kMaxChannelVolume;
+ vol_r = vol / Mixer::kMaxChannelVolume;
} else if (_balance < 0) {
- vol_l = vol / 255;
- vol_r = ((127 + _balance) * vol) / (255 * 127);
+ vol_l = vol / Mixer::kMaxChannelVolume;
+ vol_r = ((127 + _balance) * vol) / (Mixer::kMaxChannelVolume * 127);
} else {
- vol_l = ((127 - _balance) * vol) / (255 * 127);
- vol_r = vol / 255;
+ vol_l = ((127 - _balance) * vol) / (Mixer::kMaxChannelVolume * 127);
+ vol_r = vol / Mixer::kMaxChannelVolume;
}
_samplesConsumed = _samplesDecoded;
+ _mixerTimeStamp = g_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 = g_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;
+}
+
+
+} // End of namespace Audio
Modified: residual/trunk/mixer/mixer.h
===================================================================
--- residual/trunk/mixer/mixer.h 2008-03-10 20:34:34 UTC (rev 31099)
+++ residual/trunk/mixer/mixer.h 2008-03-10 23:04:55 UTC (rev 31100)
@@ -1,19 +1,19 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
- * Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
+ * Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
@@ -25,32 +25,51 @@
#include "common/sys.h"
#include "common/platform.h"
+#include "common/mutex.h"
+namespace Audio {
+
class AudioStream;
class Channel;
+class Mixer;
-class PlayingSoundHandle {
+/**
+ * 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 SoundMixer;
- int val;
- int getIndex() const { return val - 1; }
- void setIndex(int i) { val = i + 1; }
- void resetIndex() { val = 0; }
+ friend class Mixer;
+ uint32 _val;
public:
- PlayingSoundHandle() { resetIndex(); }
- bool isActive() const { return val > 0; }
+ inline SoundHandle() : _val(0xFFFFFFFF) {}
};
-class SoundMixer {
+/**
+ * The main audio mixer handles mixing of an arbitrary number of
+ * input audio streams (in the form of AudioStream instances).
+ */
+class Mixer {
public:
- enum {
+ /**
+ * 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,
- /** sample is little endian (default: big endian) */
+ /** samples are little endian (default: big endian) */
FLAG_LITTLE_ENDIAN = 1 << 2,
/** sound is in stereo (default: mono) */
@@ -66,75 +85,99 @@
FLAG_LOOP = 1 << 6
};
+ enum SoundType {
+ kPlainSoundType = 0,
+
+ kMusicSoundType = 1,
+ kSFXSoundType = 2,
+ kSpeechSoundType = 3
+ };
+
+ enum {
+ kMaxChannelVolume = 255,
+ kMaxMixerVolume = 256
+ };
+
private:
enum {
NUM_CHANNELS = 32
};
- MutexRef _mutex;
+ Common::Mutex _mutex;
- Channel *_premixChannel;
+ int _volumeForSoundType[4];
- uint _outputRate;
-
- int _globalVolume;
-
- bool _paused;
-
+ uint32 _handleSeed;
Channel *_channels[NUM_CHANNELS];
bool _mixerReady;
public:
- SoundMixer();
- ~SoundMixer();
+ 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 use the
- * premix callback for syncing. In particular, the Adlib MIDI emulation...
+ * 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; };
+ bool isReady() const { return _mixerReady; }
/**
- * Set the premix stream. This is mainly used for the adlib music, but
- * is not limited to it. The premix stream is invoked by the mixer whenever
- * it needs to generate any data, before any other mixing takes place.
- */
- void setupPremix(AudioStream *stream);
-
-
-
- /**
* 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(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags,
- int id = -1, byte volume = 255, int8 balance = 0,
- uint32 loopStart = 0, uint32 loopEnd = 0);
+ 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(PlayingSoundHandle *handle, AudioStream *input, bool isMusic,
- int id = -1, byte volume = 255, int8 balance = 0,
- bool autofreeStream = true, bool permanent = false);
+ 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(bool force = false);
+ void stopAll();
/**
* Stop playing the sound with given ID.
@@ -148,15 +191,15 @@
*
* @param handle the sound to affect
*/
- void stopHandle(PlayingSoundHandle handle);
+ void stopHandle(SoundHandle handle);
/**
- * Pause/unpause the mixer (this temporarily stops all audio processing,
- * including all regular channels and the premix channel).
+ * Pause/unpause all sounds, including all regular and permanent
+ * channels
*
- * @param paused true to pause the mixer, false to unpause it
+ * @param paused true to pause everything, false to unpause
*/
void pauseAll(bool paused);
@@ -174,7 +217,7 @@
* @param handle the sound to affect
* @param paused true to pause the sound, false to unpause it
*/
- void pauseHandle(PlayingSoundHandle handle, bool paused);
+ void pauseHandle(SoundHandle handle, bool paused);
@@ -187,21 +230,30 @@
bool isSoundIDActive(int id);
/**
- * Check if the mixer is paused (using pauseAll).
+ * Get the sound ID of handle sound
*
- * @return true if the mixer is paused
+ * @param handle sound to query
+ * @return sound ID if active
*/
- bool isPaused();
+ 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(PlayingSoundHandle handle, byte volume);
+ void setChannelVolume(SoundHandle handle, byte volume);
/**
* Set the channel balance for the given handle.
@@ -210,26 +262,38 @@
* @param balance the new channel balance:
* (-127 ... 0 ... 127) corresponds to (left ... center ... right)
*/
- void setChannelBalance(PlayingSoundHandle handle, int8 balance);
+ void setChannelBalance(SoundHandle handle, int8 balance);
/**
* Get approximation of for how long the channel has been playing.
*/
- uint32 getSoundElapsedTime(PlayingSoundHandle handle);
+ uint32 getSoundElapsedTime(SoundHandle handle);
/**
- * Set the global volume.
+ * 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 volume the new global volume, 0-256
+ * @param type the sound type to look for
+ * @return true if any channels of the specified type are active.
*/
- void setVolume(int volume);
+ 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.
*
- * @return the global music volume, 0-256
+ * @param type the sound type
+ * @return the global music volume, 0-kMaxMixerVolume
*/
- int getVolume() const { return _globalVolume; }
+ int getVolumeForSoundType(SoundType type) const;
/**
* Query the system's audio output sample rate. This returns
@@ -237,23 +301,29 @@
*
* @return the output sample rate in Hz
*/
- uint getOutputRate() const { return _outputRate; }
+ uint getOutputRate() const;
-private:
- void insertChannel(PlayingSoundHandle *handle, Channel *chan);
+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; }
};
-extern SoundMixer *g_mixer;
+} // End of namespace Audio
+
#endif
Modified: residual/trunk/mixer/rate.cpp
===================================================================
--- residual/trunk/mixer/rate.cpp 2008-03-10 20:34:34 UTC (rev 31099)
+++ residual/trunk/mixer/rate.cpp 2008-03-10 23:04:55 UTC (rev 31100)
@@ -1,19 +1,19 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
- * Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
+ * Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
@@ -30,16 +30,15 @@
#include "common/sys.h"
#include "common/debug.h"
+#include "common/frac.h"
+#include "mixer/audiostream.h"
#include "mixer/rate.h"
-#include "mixer/audiostream.h"
+#include "mixer/mixer.h"
-/**
- * The precision of the fractional computations used by the rate converter.
- * Normally you should never have to modify this value.
- */
-#define FRAC_BITS 16
+namespace Audio {
+
/**
* The size of the intermediate input cache. Bigger values may increase
* performance, but only until some point (depends largely on cache size,
@@ -48,7 +47,105 @@
*/
#define INTERMEDIATE_BUFFER_SIZE 512
+
/**
+ * Audio rate converter based on simple resampling. Used when no
+ * interpolation is required.
+ *
+ * Limited to sampling frequency <= 65535 Hz.
+ */
+template<bool stereo, bool reverseStereo>
+class SimpleRateConverter : public RateConverter {
+protected:
+ st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
+ const st_sample_t *inPtr;
+ int inLen;
+
+ /** position of how far output is ahead of input */
+ /** Holds what would have been opos-ipos */
+ long opos;
+
+ /** fractional position increment in the output stream */
+ long opos_inc;
+
+public:
+ SimpleRateConverter(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>
+SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
+ if ((inrate % outrate) != 0) {
+ error("Input rate must be a multiple of output rate to use rate effect");
+ }
+
+ if (inrate >= 65536 || outrate >= 65536) {
+ error("rate effect can only handle rates < 65536");
+ }
+
+ opos = 1;
+
+ /* increment */
+ opos_inc = inrate / outrate;
+
+ inLen = 0;
+}
+
+/*
+ * Processed signed long samples from ibuf to obuf.
+ * Return number of samples processed.
+ */
+template<bool stereo, bool reverseStereo>
+int SimpleRateConverter<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;
+
+ ostart = obuf;
+ oend = obuf + osamp * 2;
+
+ while (obuf < oend) {
+
+ // read enough input samples so that opos >= 0
+ do {
+ // Check if we have to refill the buffer
+ if (inLen == 0) {
+ inPtr = inBuf;
+ inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
+ if (inLen <= 0)
+ return ST_EOF;
+ }
+ inLen -= (stereo ? 2 : 1);
+ opos--;
+ if (opos >= 0) {
+ inPtr += (stereo ? 2 : 1);
+ }
+ } while (opos >= 0);
+
+ st_sample_t out0, out1;
+ out0 = *inPtr++;
+ out1 = (stereo ? *inPtr++ : out0);
+
+ // Increment output position
+ opos += opos_inc;
+
+ // output left channel
+ clampedAdd(obuf[reverseStereo ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
+
+ // output right channel
+ clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
+
+ obuf += 2;
+ }
+ return ST_SUCCESS;
+}
+
+/**
* Audio rate converter based on simple linear Interpolation.
*
* The use of fractional increment allows us to use no buffer. It
@@ -67,56 +164,46 @@
int inLen;
/** fractional position of the output stream in input stream unit */
- unsigned long opos, opos_frac;
+ frac_t opos;
/** fractional position increment in the output stream */
- unsigned long opos_inc, opos_inc_frac;
+ frac_t opos_inc;
- /** position in the input stream (integer) */
- unsigned long ipos;
-
/** last sample(s) in the input stream (left/right channel) */
- st_sample_t ilast[2];
+ st_sample_t ilast0, ilast1;
/** current sample(s) in the input stream (left/right channel) */
- st_sample_t icur[2];
+ st_sample_t icur0, icur1;
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);
+ 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;
+ opos = FRAC_ONE;
- /* increment */
- incr = (inrate << FRAC_BITS) / outrate;
+ // Compute the linear interpolation increment.
+ // This will overflow if inrate >= 2^16, and underflow if outrate >= 2^16.
+ // Also, if the quotient of the two rate becomes too small / too big, that
+ // would cause problems, but since we rarely scale from 1 to 65536 Hz or vice
+ // versa, I think we can live with that limiation ;-).
+ opos_inc = (inrate << FRAC_BITS) / outrate;
- opos_inc_frac = incr & ((1UL << FRAC_BITS) - 1);
- opos_inc = incr >> FRAC_BITS;
+ ilast0 = ilast1 = 0;
+ icur0 = icur1 = 0;
- ipos = 0;
-
- ilast[0] = ilast[1] = 0;
- icur[0] = icur[1] = 0;
-
inLen = 0;
}
@@ -127,66 +214,60 @@
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) {
+ // read enough input samples so that opos < 0
+ while ((frac_t)FRAC_ONE <= opos) {
// Check if we have to refill the buffer
if (inLen == 0) {
inPtr = inBuf;
inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
if (inLen <= 0)
- goto the_end;
+ return ST_EOF;
}
- for (i = 0; i < numChannels; i++) {
- ilast[i] = icur[i];
- icur[i] = *inPtr++;
- inLen--;
+ inLen -= (stereo ? 2 : 1);
+ ilast0 = icur0;
+ icur0 = *inPtr++;
+ if (stereo) {
+ ilast1 = icur1;
+ icur1 = *inPtr++;
}
- ipos++;
+ opos -= FRAC_ONE;
}
// Loop as long as the outpos trails behind, and as long as there is
// still space in the output buffer.
- while (ipos > opos) {
-
+ while (opos < (frac_t)FRAC_ONE && obuf < oend) {
// interpolate
- out[0] = out[1] = (st_sample_t)(ilast[0] + (((icur[0] - ilast[0]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
+ st_sample_t out0, out1;
+ out0 = (st_sample_t)(ilast0 + (((icur0 - ilast0) * opos + FRAC_HALF) >> FRAC_BITS));
+ out1 = (stereo ?
+ (st_sample_t)(ilast1 + (((icur1 - ilast1) * opos + FRAC_HALF) >> FRAC_BITS)) :
+ out0);
- if (stereo) {
- // interpolate
- out[reverseStereo ? 0 : 1] = (st_sample_t)(ilast[1] + (((icur[1] - ilast[1]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
- }
-
// output left channel
- clampedAdd(*obuf++, (out[0] * (int)vol_l) >> 8);
+ clampedAdd(obuf[reverseStereo ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
// output right channel
- clampedAdd(*obuf++, (out[1] * (int)vol_r) >> 8);
+ clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
+ obuf += 2;
+
// 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;
+ opos += opos_inc;
}
}
-
-the_end:
- return (ST_SUCCESS);
+ return ST_SUCCESS;
}
+
+#pragma mark -
+
+
/**
* Simple audio rate converter for the case that the inrate equals the outrate.
*/
@@ -202,10 +283,10 @@
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;
@@ -218,53 +299,57 @@
// 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--) {
- st_sample_t tmp0, tmp1;
- tmp0 = tmp1 = *ptr++;
- if (stereo) {
- if (reverseStereo)
- tmp0 = *ptr++;
- else
- tmp1 = *ptr++;
- len--;
- }
+ for (; len > 0; len -= (stereo ? 2 : 1)) {
+ st_sample_t out0, out1;
+ out0 = *ptr++;
+ out1 = (stereo ? *ptr++ : out0);
// output left channel
- clampedAdd(*obuf++, (tmp0 * (int)vol_l) >> 8);
-
+ clampedAdd(obuf[reverseStereo ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
+
// output right channel
- clampedAdd(*obuf++, (tmp1 * (int)vol_r) >> 8);
+ clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
+
+ obuf += 2;
}
- return (ST_SUCCESS);
+ return ST_SUCCESS;
}
- virtual int drain(st_sample_t * /*obuf*/, st_size_t /*osamp*/, st_volume_t /*vol*/) {
- return (ST_SUCCESS);
+
+ virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
+ return ST_SUCCESS;
}
};
+
+#pragma mark -
+
+template<bool stereo, bool reverseStereo>
+RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate) {
+ if (inrate != outrate) {
+ if ((inrate % outrate) == 0) {
+ return new SimpleRateConverter<stereo, reverseStereo>(inrate, outrate);
+ } else {
+ return new LinearRateConverter<stereo, reverseStereo>(inrate, outrate);
+ }
+ } else {
+ return new CopyRateConverter<stereo, reverseStereo>();
+ }
+}
+
/**
* 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>();
- }
+ if (stereo) {
+ if (reverseStereo)
+ return makeRateConverter<true, true>(inrate, outrate);
+ else
+ return makeRateConverter<true, false>(inrate, outrate);
+ } else
+ return makeRateConverter<false, false>(inrate, outrate);
}
+
+} // End of namespace Audio
Modified: residual/trunk/mixer/rate.h
===================================================================
--- residual/trunk/mixer/rate.h 2008-03-10 20:34:34 UTC (rev 31099)
+++ residual/trunk/mixer/rate.h 2008-03-10 23:04:55 UTC (rev 31100)
@@ -1,19 +1,19 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
- * Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
+ * Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
- * This library is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
@@ -27,17 +27,24 @@
class AudioStream;
+
+namespace Audio {
+
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)
+enum {
+ ST_SAMPLE_MAX = 0x7fffL,
+ ST_SAMPLE_MIN = (-ST_SAMPLE_MAX - 1L)
+};
-#define ST_EOF (-1)
-#define ST_SUCCESS (0)
+enum {
+ ST_EOF = -1,
+ ST_SUCCESS = 0
+};
static inline void clampedAdd(int16& a, int b) {
register int val;
@@ -59,12 +66,6 @@
#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() {}
@@ -75,4 +76,6 @@
RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo = false);
+} // End of namespace Audio
+
#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Scummvm-git-logs
mailing list