From c45d632f3b8c2d8c8aa46b05db758898de863e97 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 28 Jun 2008 15:28:29 +0000 Subject: Patch ##1956946 (Audio::Mixer internal API revision) with some tweaks svn-id: r32828 --- backends/platform/gp2x/gp2x-common.h | 4 +- backends/platform/gp2x/gp2x.cpp | 7 +- backends/platform/psp/osys_psp.cpp | 4 +- backends/platform/sdl/sdl.cpp | 51 +++++---- backends/platform/sdl/sdl.h | 10 +- backends/platform/symbian/src/SymbianOS.cpp | 69 +++++++------ backends/platform/symbian/src/SymbianOS.h | 9 +- backends/platform/wince/wince-sdl.cpp | 45 +++++--- backends/platform/wince/wince-sdl.h | 5 +- common/system.h | 9 -- sound/mixer.cpp | 83 +++++++-------- sound/mixer.h | 85 +++++---------- sound/mixer_intern.h | 154 ++++++++++++++++++++++++++++ 13 files changed, 336 insertions(+), 199 deletions(-) create mode 100644 sound/mixer_intern.h diff --git a/backends/platform/gp2x/gp2x-common.h b/backends/platform/gp2x/gp2x-common.h index 78d1296bc7..7e0ea88e0b 100644 --- a/backends/platform/gp2x/gp2x-common.h +++ b/backends/platform/gp2x/gp2x-common.h @@ -37,7 +37,7 @@ #include namespace Audio { - class Mixer; + class MixerImpl; } namespace Common { @@ -367,7 +367,7 @@ protected: Common::SaveFileManager *_savefile; FilesystemFactory *getFilesystemFactory(); - Audio::Mixer *_mixer; + Audio::MixerImpl *_mixer; SDL_TimerID _timerID; Common::TimerManager *_timer; diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp index 8735ea757e..1f330cf2d4 100644 --- a/backends/platform/gp2x/gp2x.cpp +++ b/backends/platform/gp2x/gp2x.cpp @@ -40,7 +40,7 @@ #include "backends/timer/default/default-timer.h" #include "backends/plugins/posix/posix-provider.h" #include "backends/fs/posix/posix-fs-factory.h" // for getFilesystemFactory() -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include #include @@ -225,8 +225,7 @@ void OSystem_GP2X::initBackend() { // Create and hook up the mixer, if none exists yet (we check for this to // allow subclasses to provide their own). if (_mixer == 0) { - _mixer = new Audio::Mixer(); - setSoundCallback(Audio::Mixer::mixCallback, _mixer); + setupMixer(); } // Create and hook up the timer manager, if none exists yet (we check for @@ -445,7 +444,7 @@ void OSystem_GP2X::deleteMutex(MutexRef mutex) { #pragma mark --- Audio --- #pragma mark - -bool OSystem_GP2X::setSoundCallback(SoundProc proc, void *param) { +void OSystem_GP2X::setupMixer() { SDL_AudioSpec desired; SDL_AudioSpec obtained; diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index aff5373510..2d18b4bfd6 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -34,7 +34,7 @@ #include "backends/timer/default/default-timer.h" #include "graphics/surface.h" #include "graphics/scaler.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include @@ -99,7 +99,7 @@ OSystem_PSP::~OSystem_PSP() { void OSystem_PSP::initBackend() { _savefile = new DefaultSaveFileManager(); - _mixer = new Audio::Mixer(); + _mixer = new Audio::MixerImpl(this); _timer = new DefaultTimerManager(); setSoundCallback(Audio::Mixer::mixCallback, _mixer); setTimerCallback(&timer_handler, 10); diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 60f8d3c95c..290fe63663 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -30,7 +30,7 @@ #include "backends/saves/default/default-saves.h" #include "backends/timer/default/default-timer.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "icons/scummvm.xpm" @@ -131,9 +131,7 @@ void OSystem_SDL::initBackend() { // Create and hook up the mixer, if none exists yet (we check for this to // allow subclasses to provide their own). if (_mixer == 0) { - _mixer = new Audio::Mixer(); - bool result = setSoundCallback(Audio::Mixer::mixCallback, _mixer); - _mixer->setReady(result); + setupMixer(); } // Create and hook up the timer manager, if none exists yet (we check for @@ -391,7 +389,15 @@ void OSystem_SDL::deleteMutex(MutexRef mutex) { #pragma mark --- Audio --- #pragma mark - -bool OSystem_SDL::setSoundCallback(SoundProc proc, void *param) { +void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) { + OSystem_SDL *this_ = (OSystem_SDL *)sys; + assert(this_); + + if (this_->_mixer) + this_->_mixer->mixCallback(samples, len); +} + +void OSystem_SDL::setupMixer() { SDL_AudioSpec desired; SDL_AudioSpec obtained; @@ -415,23 +421,30 @@ bool OSystem_SDL::setSoundCallback(SoundProc proc, void *param) { desired.format = AUDIO_S16SYS; desired.channels = 2; desired.samples = (uint16)samples; - desired.callback = proc; - desired.userdata = param; + desired.callback = mixCallback; + desired.userdata = this; + + // Create the mixer instance + assert(!_mixer); + _mixer = new Audio::MixerImpl(this); + assert(_mixer); + if (SDL_OpenAudio(&desired, &obtained) != 0) { warning("Could not open audio device: %s", SDL_GetError()); - return false; + _samplesPerSec = 0; + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + _samplesPerSec = obtained.freq; + debug(1, "Output sample rate: %d Hz", _samplesPerSec); + + // Tell the mixer that we are ready and start the sound processing + _mixer->setOutputRate(_samplesPerSec); + _mixer->setReady(true); + SDL_PauseAudio(0); } - // Note: This should be the obtained output rate, but it seems that at - // least on some platforms SDL will lie and claim it did get the rate - // even if it didn't. Probably only happens for "weird" rates, though. - _samplesPerSec = obtained.freq; - debug(1, "Output sample rate: %d Hz", _samplesPerSec); - SDL_PauseAudio(0); - return true; -} - -int OSystem_SDL::getOutputSampleRate() const { - return _samplesPerSec; } Audio::Mixer *OSystem_SDL::getMixer() { diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 2cbadae2f4..8a94a17b00 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -38,7 +38,7 @@ namespace Audio { - class Mixer; + class MixerImpl; } namespace Common { @@ -134,8 +134,9 @@ public: virtual bool pollEvent(Common::Event &event); // overloaded by CE backend // Set function that generates samples - typedef void (*SoundProc)(void *param, byte *buf, int len); - virtual bool setSoundCallback(SoundProc proc, void *param); // overloaded by CE backend + virtual void setupMixer(); + static void mixCallback(void *s, byte *samples, int len); + virtual Audio::Mixer *getMixer(); // Poll CD status @@ -186,7 +187,6 @@ public: virtual void setWindowCaption(const char *caption); virtual bool openCD(int drive); - virtual int getOutputSampleRate() const; virtual bool hasFeature(Feature f); virtual void setFeatureState(Feature f, bool enable); @@ -371,7 +371,7 @@ protected: Common::SaveFileManager *_savefile; - Audio::Mixer *_mixer; + Audio::MixerImpl *_mixer; SDL_TimerID _timerID; Common::TimerManager *_timer; diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp index d3e92731db..dfeb24d825 100644 --- a/backends/platform/symbian/src/SymbianOS.cpp +++ b/backends/platform/symbian/src/SymbianOS.cpp @@ -173,11 +173,8 @@ void OSystem_SDL_Symbian::quit() { OSystem_SDL::quit(); } -bool OSystem_SDL_Symbian::setSoundCallback(SoundProc proc, void *param) { +void OSystem_SDL_Symbian::setupMixer() { - // First save the proc and param - _sound_proc_param = param; - _sound_proc = proc; SDL_AudioSpec desired; SDL_AudioSpec obtained; @@ -207,48 +204,53 @@ bool OSystem_SDL_Symbian::setSoundCallback(SoundProc proc, void *param) { desired.format = AUDIO_S16SYS; desired.channels = 2; desired.samples = (uint16)samples; -#ifdef S60 desired.callback = symbianMixCallback; desired.userdata = this; -#else - desired.callback = proc; - desired.userdata = param; -#endif + + // Create the mixer instance + assert(!_mixer); + _mixer = new Audio::MixerImpl(this); + assert(_mixer); + if (SDL_OpenAudio(&desired, &obtained) != 0) { warning("Could not open audio device: %s", SDL_GetError()); - return false; - } - // Note: This should be the obtained output rate, but it seems that at - // least on some platforms SDL will lie and claim it did get the rate - // even if it didn't. Probably only happens for "weird" rates, though. - _samplesPerSec = obtained.freq; - _channels = obtained.channels; - - // Need to create mixbuffer for stereo mix to downmix - if (_channels != 2) { - _stereo_mix_buffer = new byte [obtained.size*2];//*2 for stereo values + _samplesPerSec = 0; + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + _samplesPerSec = obtained.freq; + _channels = obtained.channels; + + // Need to create mixbuffer for stereo mix to downmix + if (_channels != 2) { + _stereo_mix_buffer = new byte [obtained.size*2];//*2 for stereo values + } + + // Tell the mixer that we are ready and start the sound processing + _mixer->setOutputRate(_samplesPerSec); + _mixer->setReady(true); + SDL_PauseAudio(0); } - - SDL_PauseAudio(0); - return true; } /** * The mixer callback function, passed on to OSystem::setSoundCallback(). * This simply calls the mix() method. */ -void OSystem_SDL_Symbian::symbianMixCallback(void *s, byte *samples, int len) { - static_cast (s)->symbianMix(samples,len); -} +void OSystem_SDL_Symbian::symbianMixCallback(void *sys, byte *samples, int len) { + OSystem_SDL_Symbian *this_ = (OSystem_SDL_Symbian *)sys; + assert(this_); + if (!this_->_mixer) + return; -/** - * Actual mixing implementation - */ -void OSystem_SDL_Symbian::symbianMix(byte *samples, int len) { +#ifdef S60 // If not stereo then we need to downmix if (_channels != 2) { - _sound_proc(_sound_proc_param, _stereo_mix_buffer, len * 2); + this_->_mixer->mixCallback(_stereo_mix_buffer, len * 2); + int16 *bitmixDst = (int16 *)samples; int16 *bitmixSrc = (int16 *)_stereo_mix_buffer; @@ -258,9 +260,12 @@ void OSystem_SDL_Symbian::symbianMix(byte *samples, int len) { bitmixSrc += 2; } } else - _sound_proc(_sound_proc_param, samples, len); +#else + this_->_mixer->mixCallback(samples, len); +#endif } + /** * This is an implementation by the remapKey function * @param SDL_Event to remap diff --git a/backends/platform/symbian/src/SymbianOS.h b/backends/platform/symbian/src/SymbianOS.h index 77e42cd476..71d24f6286 100644 --- a/backends/platform/symbian/src/SymbianOS.h +++ b/backends/platform/symbian/src/SymbianOS.h @@ -58,7 +58,7 @@ public: // This function is overridden by the symbian port in order to provide MONO audio // downmix is done by supplying our own audiocallback // - virtual bool setSoundCallback(SoundProc proc, void *param); // overloaded by CE backend + virtual void setupMixer(); // overloaded by CE backend // Overloaded from SDL_Commmon void quit(); @@ -70,11 +70,6 @@ protected: // static void symbianMixCallback(void *s, byte *samples, int len); - // - // Actual mixing implementation - // - void symbianMix(byte *samples, int len); - virtual FilesystemFactory *getFilesystemFactory(); public: // vibration support @@ -121,8 +116,6 @@ protected: // Audio int _channels; - SoundProc _sound_proc; - void *_sound_proc_param; byte *_stereo_mix_buffer; // Used to handle joystick navi zones diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index 8cf5fac279..470c4ef435 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -35,7 +35,7 @@ #include "base/main.h" #include "base/plugins.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "sound/fmopl.h" #include "backends/timer/default/default-timer.h" @@ -404,7 +404,7 @@ void OSystem_WINCE3::initBackend() // Instantiate our own sound mixer // mixer init is postponed until a game engine is selected. if (_mixer == 0) { - _mixer = new Audio::Mixer(); + _mixer = new Audio::Mixer(this); } // Create the timer. CE SDL does not support multiple timers (SDL_AddTimer). @@ -770,7 +770,7 @@ void OSystem_WINCE3::create_toolbar() { _toolbarHandler.setVisible(false); } -bool OSystem_WINCE3::setSoundCallback(SoundProc proc, void *param) { +void OSystem_WINCE3::setupMixer(SoundProc proc, void *param) { SDL_AudioSpec desired; int thread_priority; @@ -785,12 +785,16 @@ bool OSystem_WINCE3::setSoundCallback(SoundProc proc, void *param) { desired.channels = 2; desired.samples = 128; desired.callback = private_sound_proc; - desired.userdata = param; + desired.userdata = this; + + // Create the mixer instance + assert(!_mixer); + _mixer = new Audio::MixerImpl(this); + assert(_mixer); // Add sound thread priority - if (!ConfMan.hasKey("sound_thread_priority")) { + if (!ConfMan.hasKey("sound_thread_priority")) thread_priority = THREAD_PRIORITY_NORMAL; - } else thread_priority = ConfMan.getInt("sound_thread_priority"); @@ -799,16 +803,24 @@ bool OSystem_WINCE3::setSoundCallback(SoundProc proc, void *param) { SDL_CloseAudio(); if (SDL_OpenAudio(&desired, NULL) != 0) { warning("Could not open audio device: %s", SDL_GetError()); - return false; - } - else + _mixer->setReady(false); + + } else { debug(1, "Sound opened OK, mixing at %d Hz", _sampleRate); - SDL_PauseAudio(0); - return true; + + // Tell the mixer that we are ready and start the sound processing + _mixer->setOutputRate(_sampleRate); + _mixer->setReady(true); + SDL_PauseAudio(0); + } } void OSystem_WINCE3::private_sound_proc(void *param, byte *buf, int len) { - (*_originalSoundProc)(param, buf, len); + OSystem_WINCE3 *this_ = (OSystem_WINCE3 *)param; + assert(this_); + + if (this_->_mixer) + this_->_mixer->mixCallback(buf, len); if (!_soundMaster) memset(buf, 0, len); } @@ -838,7 +850,7 @@ bool OSystem_WINCE3::checkOggHighSampleRate() { } #endif -void OSystem_WINCE3::get_sample_rate() { +void OSystem_WINCE3::compute_sample_rate() { // Force at least medium quality FM synthesis for FOTAQ Common::String gameid(ConfMan.get("gameid")); if (gameid == "queen") { @@ -875,9 +887,8 @@ void OSystem_WINCE3::setWindowCaption(const char *caption) { //update_game_settings(); // finalize mixer init - get_sample_rate(); - bool result = setSoundCallback(Audio::Mixer::mixCallback, _mixer); - _mixer->setReady(result); + compute_sample_rate(); + setupMixer(); // handle the actual event OSystem_SDL::setWindowCaption(caption); @@ -1050,7 +1061,7 @@ void OSystem_WINCE3::update_game_settings() { } } - get_sample_rate(); + compute_sample_rate(); } void OSystem_WINCE3::initSize(uint w, uint h) { diff --git a/backends/platform/wince/wince-sdl.h b/backends/platform/wince/wince-sdl.h index daa7e832f6..8853c156d8 100644 --- a/backends/platform/wince/wince-sdl.h +++ b/backends/platform/wince/wince-sdl.h @@ -82,7 +82,7 @@ public: // Overloaded from SDL_Commmon void quit(); // Overloaded from SDL_Commmon (master volume and sample rate subtleties) - bool setSoundCallback(SoundProc proc, void *param); + void setupMixer(); // Overloaded from OSystem //void engineInit(); void getTimeAndDate(struct tm &t) const; @@ -160,13 +160,12 @@ private: #endif static void private_sound_proc(void *param, byte *buf, int len); - static SoundProc _originalSoundProc; bool update_scalers(); void create_toolbar(); void update_game_settings(); void check_mappings(); - void get_sample_rate(); + void compute_sample_rate(); void retrieve_mouse_location(int &x, int &y); diff --git a/common/system.h b/common/system.h index 4fc4c0625b..b895a5cfba 100644 --- a/common/system.h +++ b/common/system.h @@ -814,15 +814,6 @@ public: */ virtual Audio::Mixer *getMixer() = 0; - /** - * Determine the output sample rate. Audio data provided by the sound - * callback will be played using this rate. - * @note Client code other than the sound mixer should _not_ use this - * method. Instead, call Mixer::getOutputRate()! - * @return the output sample rate - */ - virtual int getOutputSampleRate() const = 0; - //@} 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 -- cgit v1.2.3