aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/mixer.cpp83
-rw-r--r--sound/mixer.h85
-rw-r--r--sound/mixer_intern.h154
3 files changed, 224 insertions, 98 deletions
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
index fc5b21cf32..27e031f108 100644
--- a/sound/mixer.cpp
+++ b/sound/mixer.cpp
@@ -27,7 +27,7 @@
#include "common/util.h"
#include "common/system.h"
-#include "sound/mixer.h"
+#include "sound/mixer_intern.h"
#include "sound/rate.h"
#include "sound/audiostream.h"
@@ -103,32 +103,38 @@ public:
#pragma mark -
-Mixer::Mixer() {
- _syst = g_system;
+MixerImpl::MixerImpl(OSystem *system)
+ : _syst(system), _sampleRate(0), _mixerReady(false), _handleSeed(0) {
- _handleSeed = 0;
-
- int i = 0;
+ int i;
for (i = 0; i < ARRAYSIZE(_volumeForSoundType); i++)
_volumeForSoundType[i] = kMaxMixerVolume;
for (i = 0; i != NUM_CHANNELS; i++)
_channels[i] = 0;
-
- _mixerReady = false;
}
-Mixer::~Mixer() {
+MixerImpl::~MixerImpl() {
for (int i = 0; i != NUM_CHANNELS; i++)
delete _channels[i];
}
-uint Mixer::getOutputRate() const {
- return (uint)_syst->getOutputSampleRate();
+void MixerImpl::setReady(bool ready) {
+ _mixerReady = ready;
+}
+
+uint MixerImpl::getOutputRate() const {
+ return _sampleRate;
+}
+
+void MixerImpl::setOutputRate(uint sampleRate) {
+ if (_sampleRate != 0 && _sampleRate != sampleRate)
+ error("Changing the Audio::Mixer output sample rate is not supported");
+ _sampleRate = sampleRate;
}
-void Mixer::insertChannel(SoundHandle *handle, Channel *chan) {
+void MixerImpl::insertChannel(SoundHandle *handle, Channel *chan) {
int index = -1;
for (int i = 0; i != NUM_CHANNELS; i++) {
@@ -138,7 +144,7 @@ void Mixer::insertChannel(SoundHandle *handle, Channel *chan) {
}
}
if (index == -1) {
- warning("Mixer::out of mixer slots");
+ warning("MixerImpl::out of mixer slots");
delete chan;
return;
}
@@ -151,7 +157,7 @@ void Mixer::insertChannel(SoundHandle *handle, Channel *chan) {
}
}
-void Mixer::playRaw(
+void MixerImpl::playRaw(
SoundType type,
SoundHandle *handle,
void *sound,
@@ -166,7 +172,7 @@ void Mixer::playRaw(
playInputStream(type, handle, input, id, volume, balance, true, false, ((flags & Mixer::FLAG_REVERSE_STEREO) != 0));
}
-void Mixer::playInputStream(
+void MixerImpl::playInputStream(
SoundType type,
SoundHandle *handle,
AudioStream *input,
@@ -198,8 +204,13 @@ void Mixer::playInputStream(
insertChannel(handle, chan);
}
-void Mixer::mix(int16 *buf, uint len) {
+void MixerImpl::mixCallback(byte *samples, uint len) {
+ assert(samples);
+
Common::StackLock lock(_mutex);
+
+ int16 *buf = (int16 *)samples;
+ len >>= 2;
// Since the mixer callback has been called, the mixer must be ready...
_mixerReady = true;
@@ -218,15 +229,7 @@ void Mixer::mix(int16 *buf, uint 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() {
+void MixerImpl::stopAll() {
Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++) {
if (_channels[i] != 0 && !_channels[i]->isPermanent()) {
@@ -236,7 +239,7 @@ void Mixer::stopAll() {
}
}
-void Mixer::stopID(int id) {
+void MixerImpl::stopID(int id) {
Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++) {
if (_channels[i] != 0 && _channels[i]->getId() == id) {
@@ -246,7 +249,7 @@ void Mixer::stopID(int id) {
}
}
-void Mixer::stopHandle(SoundHandle handle) {
+void MixerImpl::stopHandle(SoundHandle handle) {
Common::StackLock lock(_mutex);
// Simply ignore stop requests for handles of sounds that already terminated
@@ -258,7 +261,7 @@ void Mixer::stopHandle(SoundHandle handle) {
_channels[index] = 0;
}
-void Mixer::setChannelVolume(SoundHandle handle, byte volume) {
+void MixerImpl::setChannelVolume(SoundHandle handle, byte volume) {
Common::StackLock lock(_mutex);
const int index = handle._val % NUM_CHANNELS;
@@ -268,7 +271,7 @@ void Mixer::setChannelVolume(SoundHandle handle, byte volume) {
_channels[index]->setVolume(volume);
}
-void Mixer::setChannelBalance(SoundHandle handle, int8 balance) {
+void MixerImpl::setChannelBalance(SoundHandle handle, int8 balance) {
Common::StackLock lock(_mutex);
const int index = handle._val % NUM_CHANNELS;
@@ -278,7 +281,7 @@ void Mixer::setChannelBalance(SoundHandle handle, int8 balance) {
_channels[index]->setBalance(balance);
}
-uint32 Mixer::getSoundElapsedTime(SoundHandle handle) {
+uint32 MixerImpl::getSoundElapsedTime(SoundHandle handle) {
Common::StackLock lock(_mutex);
const int index = handle._val % NUM_CHANNELS;
@@ -288,7 +291,7 @@ uint32 Mixer::getSoundElapsedTime(SoundHandle handle) {
return _channels[index]->getElapsedTime();
}
-void Mixer::pauseAll(bool paused) {
+void MixerImpl::pauseAll(bool paused) {
Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++) {
if (_channels[i] != 0) {
@@ -297,7 +300,7 @@ void Mixer::pauseAll(bool paused) {
}
}
-void Mixer::pauseID(int id, bool paused) {
+void MixerImpl::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) {
@@ -307,7 +310,7 @@ void Mixer::pauseID(int id, bool paused) {
}
}
-void Mixer::pauseHandle(SoundHandle handle, bool paused) {
+void MixerImpl::pauseHandle(SoundHandle handle, bool paused) {
Common::StackLock lock(_mutex);
// Simply ignore (un)pause requests for sounds that already terminated
@@ -318,7 +321,7 @@ void Mixer::pauseHandle(SoundHandle handle, bool paused) {
_channels[index]->pause(paused);
}
-bool Mixer::isSoundIDActive(int id) {
+bool MixerImpl::isSoundIDActive(int id) {
Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++)
if (_channels[i] && _channels[i]->getId() == id)
@@ -326,7 +329,7 @@ bool Mixer::isSoundIDActive(int id) {
return false;
}
-int Mixer::getSoundID(SoundHandle handle) {
+int MixerImpl::getSoundID(SoundHandle handle) {
Common::StackLock lock(_mutex);
const int index = handle._val % NUM_CHANNELS;
if (_channels[index] && _channels[index]->_handle._val == handle._val)
@@ -334,13 +337,13 @@ int Mixer::getSoundID(SoundHandle handle) {
return 0;
}
-bool Mixer::isSoundHandleActive(SoundHandle handle) {
+bool MixerImpl::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) {
+bool MixerImpl::hasActiveChannelOfType(SoundType type) {
Common::StackLock lock(_mutex);
for (int i = 0; i != NUM_CHANNELS; i++)
if (_channels[i] && _channels[i]->_type == type)
@@ -348,7 +351,7 @@ bool Mixer::hasActiveChannelOfType(SoundType type) {
return false;
}
-void Mixer::setVolumeForSoundType(SoundType type, int volume) {
+void MixerImpl::setVolumeForSoundType(SoundType type, int volume) {
assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType));
// Check range
@@ -363,7 +366,7 @@ void Mixer::setVolumeForSoundType(SoundType type, int volume) {
_volumeForSoundType[type] = volume;
}
-int Mixer::getVolumeForSoundType(SoundType type) const {
+int MixerImpl::getVolumeForSoundType(SoundType type) const {
assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType));
return _volumeForSoundType[type];
@@ -443,7 +446,7 @@ uint32 Channel::getElapsedTime() {
// 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 rate = _mixer->getOutputRate();
uint32 seconds = _samplesConsumed / rate;
uint32 milliseconds = (1000 * (_samplesConsumed % rate)) / rate;
diff --git a/sound/mixer.h b/sound/mixer.h
index 26ae0898fd..28988256b3 100644
--- a/sound/mixer.h
+++ b/sound/mixer.h
@@ -38,6 +38,7 @@ namespace Audio {
class AudioStream;
class Channel;
class Mixer;
+class MixerImpl;
/**
* A SoundHandle instances corresponds to a specific sound
@@ -47,7 +48,7 @@ class Mixer;
*/
class SoundHandle {
friend class Channel;
- friend class Mixer;
+ friend class MixerImpl;
uint32 _val;
public:
inline SoundHandle() : _val(0xFFFFFFFF) {}
@@ -104,24 +105,9 @@ public:
kMaxMixerVolume = 256
};
-private:
- enum {
- NUM_CHANNELS = 16
- };
-
- OSystem *_syst;
- Common::Mutex _mutex;
-
- int _volumeForSoundType[4];
-
- uint32 _handleSeed;
- Channel *_channels[NUM_CHANNELS];
-
- bool _mixerReady;
-
public:
- Mixer();
- ~Mixer();
+ Mixer() {}
+ virtual ~Mixer() {}
@@ -132,8 +118,10 @@ public:
* sync with an audio stream. In particular, the Adlib MIDI emulation...
*
* @return whether the mixer is ready and setup
+ *
+ * @todo get rid of this?
*/
- bool isReady() const { return _mixerReady; }
+ virtual bool isReady() const = 0;
@@ -143,12 +131,12 @@ public:
* (using the makeLinearInputStream factory function), which is then
* passed on to playInputStream.
*/
- void playRaw(
+ virtual void playRaw(
SoundType type,
SoundHandle *handle,
void *sound, uint32 size, uint rate, byte flags,
int id = -1, byte volume = kMaxChannelVolume, int8 balance = 0,
- uint32 loopStart = 0, uint32 loopEnd = 0);
+ uint32 loopStart = 0, uint32 loopEnd = 0) = 0;
/**
* Start playing the given audio input stream.
@@ -170,35 +158,35 @@ public:
* not stop this particular stream
* @param reverseStereo a flag indicating whether left and right channels shall be swapped
*/
- void playInputStream(
+ virtual void playInputStream(
SoundType type,
SoundHandle *handle,
AudioStream *input,
int id = -1, byte volume = kMaxChannelVolume, int8 balance = 0,
bool autofreeStream = true,
bool permanent = false,
- bool reverseStereo = false);
+ bool reverseStereo = false) = 0;
/**
* Stop all currently playing sounds.
*/
- void stopAll();
+ virtual void stopAll() = 0;
/**
* Stop playing the sound with given ID.
*
* @param id the ID of the sound to affect
*/
- void stopID(int id);
+ virtual void stopID(int id) = 0;
/**
* Stop playing the sound corresponding to the given handle.
*
* @param handle the sound to affect
*/
- void stopHandle(SoundHandle handle);
+ virtual void stopHandle(SoundHandle handle) = 0;
@@ -208,7 +196,7 @@ public:
*
* @param paused true to pause everything, false to unpause
*/
- void pauseAll(bool paused);
+ virtual void pauseAll(bool paused) = 0;
/**
* Pause/unpause the sound with the given ID.
@@ -216,7 +204,7 @@ public:
* @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);
+ virtual void pauseID(int id, bool paused) = 0;
/**
* Pause/unpause the sound corresponding to the given handle.
@@ -224,7 +212,7 @@ public:
* @param handle the sound to affect
* @param paused true to pause the sound, false to unpause it
*/
- void pauseHandle(SoundHandle handle, bool paused);
+ virtual void pauseHandle(SoundHandle handle, bool paused) = 0;
@@ -234,7 +222,7 @@ public:
* @param id the ID of the sound to query
* @return true if the sound is active
*/
- bool isSoundIDActive(int id);
+ virtual bool isSoundIDActive(int id) = 0;
/**
* Get the sound ID of handle sound
@@ -242,7 +230,7 @@ public:
* @param handle sound to query
* @return sound ID if active
*/
- int getSoundID(SoundHandle handle);
+ virtual int getSoundID(SoundHandle handle) = 0;
/**
* Check if a sound with the given handle is active.
@@ -250,7 +238,7 @@ public:
* @param handle sound to query
* @return true if the sound is active
*/
- bool isSoundHandleActive(SoundHandle handle);
+ virtual bool isSoundHandleActive(SoundHandle handle) = 0;
@@ -260,7 +248,7 @@ public:
* @param handle the sound to affect
* @param volume the new channel volume (0 - kMaxChannelVolume)
*/
- void setChannelVolume(SoundHandle handle, byte volume);
+ virtual void setChannelVolume(SoundHandle handle, byte volume) = 0;
/**
* Set the channel balance for the given handle.
@@ -269,12 +257,12 @@ public:
* @param balance the new channel balance:
* (-127 ... 0 ... 127) corresponds to (left ... center ... right)
*/
- void setChannelBalance(SoundHandle handle, int8 balance);
+ virtual void setChannelBalance(SoundHandle handle, int8 balance) = 0;
/**
* Get approximation of for how long the channel has been playing.
*/
- uint32 getSoundElapsedTime(SoundHandle handle);
+ virtual uint32 getSoundElapsedTime(SoundHandle handle) = 0;
/**
* Check whether any channel of the given sound type is active.
@@ -284,7 +272,7 @@ public:
* @param type the sound type to look for
* @return true if any channels of the specified type are active.
*/
- bool hasActiveChannelOfType(SoundType type);
+ virtual bool hasActiveChannelOfType(SoundType type) = 0;
/**
* Set the volume for the given sound type.
@@ -292,7 +280,7 @@ public:
* @param type the sound type
* @param volume the new global volume, 0 - kMaxMixerVolume
*/
- void setVolumeForSoundType(SoundType type, int volume);
+ virtual void setVolumeForSoundType(SoundType type, int volume) = 0;
/**
* Query the global volume.
@@ -300,7 +288,7 @@ public:
* @param type the sound type
* @return the global music volume, 0 - kMaxMixerVolume
*/
- int getVolumeForSoundType(SoundType type) const;
+ virtual int getVolumeForSoundType(SoundType type) const = 0;
/**
* Query the system's audio output sample rate. This returns
@@ -308,26 +296,7 @@ public:
*
* @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; }
+ virtual uint getOutputRate() const = 0;
};
diff --git a/sound/mixer_intern.h b/sound/mixer_intern.h
new file mode 100644
index 0000000000..46ba97e66c
--- /dev/null
+++ b/sound/mixer_intern.h
@@ -0,0 +1,154 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SOUND_MIXER_INTERN_H
+#define SOUND_MIXER_INTERN_H
+
+#include "common/scummsys.h"
+#include "common/mutex.h"
+#include "sound/mixer.h"
+
+namespace Audio {
+
+/**
+ * The (default) implementation of the ScummVM audio mixing subsystem.
+ *
+ * Backends are responsible for allocating (and later releasing) an instance
+ * of this class, which engines can access via OSystem::getMixer().
+ *
+ * Initialisation of instances of this class usually happens as follows:
+ * 1) Creat a new Audio::MixerImpl instance.
+ * 2) Set the hardware output sample rate via the setSampleRate() method.
+ * 3) Hook up the mixCallback() in a suitable audio processing thread/callback.
+ * 4) Change the mixer into ready mode via setReady(true).
+ * 5) Start audio processing (e.g. by resuming the audio thread, if applicable).
+ *
+ * In the future, we might make it possible for backends to provide
+ * (partial) alternative implementations of the mixer, e.g. to make
+ * better use of native sound mixing support on low-end devices.
+ *
+ * @see OSystem::getMixer()
+ */
+class MixerImpl : public Mixer {
+private:
+ enum {
+ NUM_CHANNELS = 16
+ };
+
+ OSystem *_syst;
+ Common::Mutex _mutex;
+
+ uint _sampleRate;
+ bool _mixerReady;
+ uint32 _handleSeed;
+
+ int _volumeForSoundType[4];
+ Channel *_channels[NUM_CHANNELS];
+
+
+public:
+ MixerImpl(OSystem *system);
+ ~MixerImpl();
+
+ virtual bool isReady() const { return _mixerReady; }
+
+ virtual 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);
+
+ virtual 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);
+
+
+
+ virtual void stopAll();
+ virtual void stopID(int id);
+ virtual void stopHandle(SoundHandle handle);
+
+ virtual void pauseAll(bool paused);
+ virtual void pauseID(int id, bool paused);
+ virtual void pauseHandle(SoundHandle handle, bool paused);
+
+ virtual bool isSoundIDActive(int id);
+ virtual int getSoundID(SoundHandle handle);
+
+ virtual bool isSoundHandleActive(SoundHandle handle);
+
+ virtual void setChannelVolume(SoundHandle handle, byte volume);
+ virtual void setChannelBalance(SoundHandle handle, int8 balance);
+
+ virtual uint32 getSoundElapsedTime(SoundHandle handle);
+
+ virtual bool hasActiveChannelOfType(SoundType type);
+
+ virtual void setVolumeForSoundType(SoundType type, int volume);
+ virtual int getVolumeForSoundType(SoundType type) const;
+
+ virtual uint getOutputRate() const;
+
+protected:
+ void insertChannel(SoundHandle *handle, Channel *chan);
+
+public:
+ /**
+ * The mixer callback function, to be called at regular intervals by
+ * the backend (e.g. from an audio mixing thread). All the actual mixing
+ * work is done from here.
+ */
+ void mixCallback(byte *samples, uint len);
+
+ /**
+ * Set the internal 'is ready' flag of the mixer.
+ * Backends should invoke Mixer::setReady(true) once initialisation of
+ * their audio system has been completed (and in particular, *after*
+ * setOutputRate() has been called).
+ */
+ void setReady(bool ready);
+
+ /**
+ * Set the output sample rate.
+ *
+ * @param sampleRate the new output sample rate
+ *
+ * @note Right now, this can be done exactly ONCE. That is, the mixer
+ * currently does not support changing the output sample rate after it
+ * has been set for the first time. This may change in the future.
+ */
+ void setOutputRate(uint sampleRate);
+};
+
+
+} // End of namespace Audio
+
+#endif