From 610422eac9dbee5cfd12961c19d2aa47b3d3b826 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Wed, 22 Aug 2007 17:28:22 +0000 Subject: [PATCH] Redesigned DSP Filter control interface --- panda/src/audiotraits/fmodAudioManager.cxx | 280 +++++++++++++----- panda/src/audiotraits/fmodAudioManager.h | 22 +- panda/src/audiotraits/fmodAudioSound.cxx | 108 +------ panda/src/audiotraits/fmodAudioSound.h | 18 +- .../src/audiotraits/fmod_audio_composite1.cxx | 1 - 5 files changed, 213 insertions(+), 216 deletions(-) diff --git a/panda/src/audiotraits/fmodAudioManager.cxx b/panda/src/audiotraits/fmodAudioManager.cxx index 5b0a671f11..35d36e3244 100644 --- a/panda/src/audiotraits/fmodAudioManager.cxx +++ b/panda/src/audiotraits/fmodAudioManager.cxx @@ -30,7 +30,6 @@ #include "config_util.h" #include "fmodAudioManager.h" #include "fmodAudioSound.h" -#include "fmodAudioDSP.h" //Needed so People use Panda's Generic UNIX Style Paths for Filename. #include "filename.h" #include "virtualFileSystem.h" @@ -39,7 +38,7 @@ #include #include - +#define USER_DSP_MAGIC ((void*)0x7012AB35) TypeHandle FmodAudioManager::_type_handle; @@ -82,9 +81,9 @@ PT(AudioManager) Create_AudioManager() { //////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::FmodAudioManager() +// Function: FmodAudioManager::Constructor // Access: Public -// Description: Constructor +// Description: //////////////////////////////////////////////////////////////////// FmodAudioManager:: FmodAudioManager() { @@ -137,7 +136,8 @@ FmodAudioManager() { } //Now we Initialize the System. - result = _system->init(fmod_number_of_sound_channels, FMOD_INIT_NORMAL, 0); + int nchan = fmod_number_of_sound_channels; + result = _system->init(nchan, FMOD_INIT_NORMAL, 0); fmod_audio_errcheck("_system->init()", result); _system_is_valid = (result == FMOD_OK); @@ -173,18 +173,15 @@ FmodAudioManager() { } //////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::~FmodAudioManager +// Function: FmodAudioManager::Destructor // Access: Public -// Description: DESTRCUTOR !!! +// Description: //////////////////////////////////////////////////////////////////// FmodAudioManager:: ~FmodAudioManager() { // Be sure to delete associated sounds before deleting the manager! FMOD_RESULT result; - //Release DSPs First - _system_dsp.clear(); - //Release Sounds Next _all_sounds.clear(); @@ -210,6 +207,200 @@ is_valid() { return _is_valid; } +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::make_dsp +// Access: Private +// Description: Converts a FilterConfig to an FMOD_DSP +//////////////////////////////////////////////////////////////////// +FMOD::DSP *FmodAudioManager:: +make_dsp(const FilterProperties::FilterConfig &conf) { + FMOD_DSP_TYPE dsptype; + FMOD_RESULT result; + FMOD::DSP *dsp; + switch (conf._type) { + case FilterProperties::FT_lowpass: dsptype = FMOD_DSP_TYPE_LOWPASS; break; + case FilterProperties::FT_highpass: dsptype = FMOD_DSP_TYPE_HIGHPASS; break; + case FilterProperties::FT_echo: dsptype = FMOD_DSP_TYPE_ECHO; break; + case FilterProperties::FT_flange: dsptype = FMOD_DSP_TYPE_FLANGE; break; + case FilterProperties::FT_distort: dsptype = FMOD_DSP_TYPE_DISTORTION; break; + case FilterProperties::FT_normalize: dsptype = FMOD_DSP_TYPE_NORMALIZE; break; + case FilterProperties::FT_parameq: dsptype = FMOD_DSP_TYPE_PARAMEQ; break; + case FilterProperties::FT_pitchshift: dsptype = FMOD_DSP_TYPE_PITCHSHIFT; break; + case FilterProperties::FT_chorus: dsptype = FMOD_DSP_TYPE_CHORUS; break; + case FilterProperties::FT_reverb: dsptype = FMOD_DSP_TYPE_REVERB; break; + case FilterProperties::FT_compress: dsptype = FMOD_DSP_TYPE_COMPRESSOR; break; + default: + audio_error("Garbage in DSP configuration data"); + return NULL; + } + + result = _system->createDSPByType( dsptype, &dsp); + if (result != 0) { + audio_error("Could not create DSP object"); + return NULL; + } + + FMOD_RESULT res1=FMOD_OK; + FMOD_RESULT res2=FMOD_OK; + FMOD_RESULT res3=FMOD_OK; + FMOD_RESULT res4=FMOD_OK; + FMOD_RESULT res5=FMOD_OK; + FMOD_RESULT res6=FMOD_OK; + FMOD_RESULT res7=FMOD_OK; + FMOD_RESULT res8=FMOD_OK; + + switch (conf._type) { + case FilterProperties::FT_lowpass: + res1=dsp->setParameter(FMOD_DSP_LOWPASS_CUTOFF, conf._a); + res2=dsp->setParameter(FMOD_DSP_LOWPASS_RESONANCE, conf._b); + break; + case FilterProperties::FT_highpass: + res1=dsp->setParameter(FMOD_DSP_HIGHPASS_CUTOFF, conf._a); + res2=dsp->setParameter(FMOD_DSP_HIGHPASS_RESONANCE, conf._b); + break; + case FilterProperties::FT_echo: + res1=dsp->setParameter(FMOD_DSP_ECHO_DRYMIX, conf._a); + res2=dsp->setParameter(FMOD_DSP_ECHO_WETMIX, conf._b); + res3=dsp->setParameter(FMOD_DSP_ECHO_DELAY, conf._c); + res4=dsp->setParameter(FMOD_DSP_ECHO_DECAYRATIO, conf._d); + break; + case FilterProperties::FT_flange: + res1=dsp->setParameter(FMOD_DSP_FLANGE_DRYMIX, conf._a); + res2=dsp->setParameter(FMOD_DSP_FLANGE_WETMIX, conf._b); + res3=dsp->setParameter(FMOD_DSP_FLANGE_DEPTH, conf._c); + res4=dsp->setParameter(FMOD_DSP_FLANGE_RATE, conf._d); + break; + case FilterProperties::FT_distort: + res1=dsp->setParameter(FMOD_DSP_DISTORTION_LEVEL, conf._a); + break; + case FilterProperties::FT_normalize: + res1=dsp->setParameter(FMOD_DSP_NORMALIZE_FADETIME, conf._a); + res2=dsp->setParameter(FMOD_DSP_NORMALIZE_THRESHHOLD,conf._b); + res3=dsp->setParameter(FMOD_DSP_NORMALIZE_MAXAMP, conf._c); + break; + case FilterProperties::FT_parameq: + res1=dsp->setParameter(FMOD_DSP_PARAMEQ_CENTER, conf._a); + res2=dsp->setParameter(FMOD_DSP_PARAMEQ_BANDWIDTH, conf._b); + res3=dsp->setParameter(FMOD_DSP_PARAMEQ_GAIN, conf._c); + break; + case FilterProperties::FT_pitchshift: + res1=dsp->setParameter(FMOD_DSP_PITCHSHIFT_PITCH, conf._a); + res2=dsp->setParameter(FMOD_DSP_PITCHSHIFT_FFTSIZE, conf._b); + res3=dsp->setParameter(FMOD_DSP_PITCHSHIFT_OVERLAP, conf._c); + break; + case FilterProperties::FT_chorus: + res1=dsp->setParameter(FMOD_DSP_CHORUS_DRYMIX, conf._a); + res2=dsp->setParameter(FMOD_DSP_CHORUS_WETMIX1, conf._b); + res3=dsp->setParameter(FMOD_DSP_CHORUS_WETMIX2, conf._c); + res4=dsp->setParameter(FMOD_DSP_CHORUS_WETMIX3, conf._d); + res5=dsp->setParameter(FMOD_DSP_CHORUS_DELAY, conf._e); + res6=dsp->setParameter(FMOD_DSP_CHORUS_RATE, conf._f); + res7=dsp->setParameter(FMOD_DSP_CHORUS_DEPTH, conf._g); + res8=dsp->setParameter(FMOD_DSP_CHORUS_FEEDBACK, conf._h); + break; + case FilterProperties::FT_reverb: + res1=dsp->setParameter(FMOD_DSP_REVERB_DRYMIX, conf._a); + res2=dsp->setParameter(FMOD_DSP_REVERB_WETMIX, conf._b); + res3=dsp->setParameter(FMOD_DSP_REVERB_ROOMSIZE, conf._c); + res4=dsp->setParameter(FMOD_DSP_REVERB_DAMP, conf._d); + res5=dsp->setParameter(FMOD_DSP_REVERB_WIDTH, conf._e); + break; + case FilterProperties::FT_compress: + res1=dsp->setParameter(FMOD_DSP_COMPRESSOR_THRESHOLD, conf._a); + res2=dsp->setParameter(FMOD_DSP_COMPRESSOR_ATTACK, conf._b); + res3=dsp->setParameter(FMOD_DSP_COMPRESSOR_RELEASE, conf._c); + res4=dsp->setParameter(FMOD_DSP_COMPRESSOR_GAINMAKEUP,conf._d); + break; + } + + if ((res1!=FMOD_OK)||(res2!=FMOD_OK)||(res3!=FMOD_OK)||(res4!=FMOD_OK)|| + (res5!=FMOD_OK)||(res6!=FMOD_OK)||(res7!=FMOD_OK)||(res8!=FMOD_OK)) { + audio_error("Could not configure DSP"); + dsp->release(); + return NULL; + } + + dsp->setUserData(USER_DSP_MAGIC); + + return dsp; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::update_dsp_chain +// Access: Public +// Description: Alters a DSP chain to make it match the specified +// configuration. +// +// This is an inadequate implementation - it just +// clears the whole DSP chain and rebuilds it from +// scratch. A better implementation would compare +// the existing DSP chain to the desired one, and +// make incremental changes. This would prevent +// a "pop" sound when the changes are made. +//////////////////////////////////////////////////////////////////// +void FmodAudioManager:: +update_dsp_chain(FMOD::DSP *head, FilterProperties *config) { + const FilterProperties::ConfigVector &conf = config->get_config(); + FMOD_RESULT res1,res2,res3,res4,res5,res6; + while (1) { + int numinputs; + res1 = head->getNumInputs(&numinputs); + if (numinputs != 1) { + break; + } + FMOD::DSP *prev; + res2 = head->getInput(0, &prev); + void *userdata; + res3 = prev->getUserData(&userdata); + if (userdata != USER_DSP_MAGIC) { + break; + } + res4 = prev->remove(); + res5 = prev->release(); + if ((res1!=FMOD_OK)||(res2!=FMOD_OK)||(res3!=FMOD_OK)||(res4!=FMOD_OK)||(res5!=FMOD_OK)) { + audio_error("Could not clean up DSP chain."); + return; + } + } + + for (int i=0; i<(int)(conf.size()); i++) { + FMOD::DSP *dsp = make_dsp(conf[i]); + if (dsp == 0) break; + FMOD::DSP *prev; + res1 = head->getInput(0, &prev); + res2 = head->disconnectFrom(prev); + res3 = head->addInput(dsp); + res4 = dsp->addInput(prev); + res5 = dsp->setActive(true); + if ((res1!=FMOD_OK)||(res2!=FMOD_OK)||(res3!=FMOD_OK)||(res4!=FMOD_OK)||(res5!=FMOD_OK)) { + audio_error("Could not update DSP chain."); + return; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::configure_filters +// Access: Public +// Description: Configure the global DSP filter chain. +// +// FMOD has a relatively powerful DSP +// implementation. It is likely that most +// configurations will be supported. +//////////////////////////////////////////////////////////////////// +bool FmodAudioManager:: +configure_filters(FilterProperties *config) { + FMOD_RESULT result; + FMOD::DSP *head; + result = _system->getDSPHead(&head); + if (result != 0) { + audio_error("Getting DSP head: " << FMOD_ErrorString(result) ); + return false; + } + update_dsp_chain(head, config); + return true; +} + //////////////////////////////////////////////////////////////////// // Function: FmodAudioManager::get_sound() // Access: Public @@ -238,75 +429,6 @@ get_sound(const string &file_name, bool positional) { } -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::create_dsp() -// Access: Published -// Description: This is what creates a DSP instance. -//////////////////////////////////////////////////////////////////// -PT(AudioDSP) FmodAudioManager:: -create_dsp(DSP_category index) { - // Build a new AudioSound from the audio data. - PT(FmodAudioDSP) fmodAudioDSP = new FmodAudioDSP(this, index); - - return (AudioDSP*)fmodAudioDSP; -} - - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::add_dsp() -// Access: Published -// Description: This stick the DSP in the Global Effect Chain -// DSP effects here, affect all the SOUNDS being played -// in panda. -//////////////////////////////////////////////////////////////////// -bool FmodAudioManager:: -add_dsp( PT(AudioDSP) x) { - FMOD_RESULT result; - - FmodAudioDSP *fdsp; - - DCAST_INTO_R(fdsp, x, false); - - if ( fdsp->get_in_chain() ) { - return false; - } else { - result = _system->addDSP( fdsp->_dsp ); - fmod_audio_errcheck("_system->addDSP()", result); - _system_dsp.insert(fdsp); - fdsp->set_in_chain(true); - return true; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::remove_dsp() -// Access: Published -// Description: This removes the DSP from the Global Effect chain but does not destroy it. -// Just remember a "Removed" DSP is still availible for use -// in another chain Global or a specific sound. -//////////////////////////////////////////////////////////////////// -bool FmodAudioManager:: -remove_dsp(PT(AudioDSP) x) { - FMOD_RESULT result; - - FmodAudioDSP *fdsp; - DCAST_INTO_R(fdsp, x, false); - - if ( fdsp->get_in_chain() ) { - result = fdsp->_dsp->remove(); - fmod_audio_errcheck("_dsp->remove()", result); - - _system_dsp.erase(fdsp); - - fdsp->set_in_chain(false); - - return true; - } else { - return false; - } -} - - //////////////////////////////////////////////////////////////////// // Function: FmodAudioManager::getSpeakerSetup() // Access: Published diff --git a/panda/src/audiotraits/fmodAudioManager.h b/panda/src/audiotraits/fmodAudioManager.h index 9dc0894eee..3f14e2f9a8 100644 --- a/panda/src/audiotraits/fmodAudioManager.h +++ b/panda/src/audiotraits/fmodAudioManager.h @@ -89,13 +89,11 @@ #include class FmodAudioSound; -class FmodAudioDSP; extern void fmod_audio_errcheck(const char *context, FMOD_RESULT n); class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager { friend class FmodAudioSound; - friend class FmodAudioDSP; public: @@ -107,10 +105,6 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager { virtual PT(AudioSound) get_sound(const string&, bool positional = false); - virtual PT(AudioDSP) create_dsp(DSP_category); - virtual bool add_dsp(PT(AudioDSP) dspToAdd); - virtual bool remove_dsp(PT(AudioDSP) x); - virtual int getSpeakerSetup(); virtual void setSpeakerSetup(SpeakerModeCategory cat); @@ -186,9 +180,13 @@ private: static FMOD_RESULT F_CALLBACK seek_callback(void *handle, unsigned int pos, void *user_data); - + + FMOD::DSP *make_dsp(const FilterProperties::FilterConfig &conf); + void update_dsp_chain(FMOD::DSP *head, FilterProperties *config); + virtual bool configure_filters(FilterProperties *config); + private: - + static FMOD::System *_system; static pset _all_managers; @@ -206,18 +204,14 @@ private: // DLS info for MIDI files string _dlsname; FMOD_CREATESOUNDEXINFO _midi_info; - + bool _is_valid; bool _active; - + // The set of all sounds. Needed only to implement stop_all_sounds. typedef pset SoundSet; SoundSet _all_sounds; - // The Data Structure that holds all the DSPs. - typedef pset DSPSet; - DSPSet _system_dsp; - //////////////////////////////////////////////////////////// //These are needed for Panda's Pointer System. DO NOT ERASE! //////////////////////////////////////////////////////////// diff --git a/panda/src/audiotraits/fmodAudioSound.cxx b/panda/src/audiotraits/fmodAudioSound.cxx index 3626c07f58..dc42324fc9 100644 --- a/panda/src/audiotraits/fmodAudioSound.cxx +++ b/panda/src/audiotraits/fmodAudioSound.cxx @@ -28,7 +28,6 @@ //Panda Headers #include "config_audio.h" #include "fmodAudioSound.h" -#include "fmodAudioDSP.h" #include "string_utils.h" TypeHandle FmodAudioSound::_type_handle; @@ -144,9 +143,6 @@ FmodAudioSound:: //Remove me from table of all sounds. _manager->_all_sounds.erase(this); - //Release DSPs First - _sound_dsp.clear(); - //The Release Sound result = _sound->release(); fmod_audio_errcheck("_sound->release()", result); @@ -325,7 +321,7 @@ set_time(float start_time) { set_volume_on_channel(); set_play_rate_on_channel(); set_speaker_mix_or_balance_on_channel(); - add_dsp_on_channel(); + // add_dsp_on_channel(); set_3d_attributes_on_channel(); if (_active) { @@ -610,108 +606,6 @@ get_3d_max_distance() const { return _max_dist; } - - - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::add_dsp -// Access: Published -// Description: This adds a DSP effect to a Sound's personal DSP Chain. -// DSPs set here will only affect it respective sound. -// -//////////////////////////////////////////////////////////////////// -bool FmodAudioSound:: -add_dsp( PT(AudioDSP) x) { - FMOD_RESULT result; - bool playingState; - - FmodAudioDSP *fdsp; - DCAST_INTO_R(fdsp, x, false); - - if ( fdsp->get_in_chain() ) { - - audio_debug("This DSP has already been assigned to the system or a sound."); - - return false; - - } else { - - _sound_dsp.insert(fdsp); - - if ( _channel != 0 ) { - result = _channel->isPlaying( &playingState ); - fmod_audio_errcheck("_channel->isPlaying()", result); - if ( playingState ) { - result = _channel->addDSP( fdsp->_dsp ); - fmod_audio_errcheck("_channel->addDSP()", result); - } - } - - fdsp->set_in_chain(true); - - return true; - - } -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::add_dsp_on_channel() -// Access: Published -// Description: Sets the DSPs on a prepared Sound channel. -//////////////////////////////////////////////////////////////////// -void FmodAudioSound:: -add_dsp_on_channel() { - FMOD_RESULT result; - - for (DSPSet::iterator i = _sound_dsp.begin(); i != _sound_dsp.end(); ++i) { - if (_channel != 0) { - result = _channel->addDSP( (*i)->_dsp ); - if (result == FMOD_ERR_INVALID_HANDLE) { - _channel = 0; - } else { - fmod_audio_errcheck("_channel->addDSP()", result); - } - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::remove_dsp -// Access: Published -// Description: This will remove a DSP from a Sound's DSP Chain, but -// It will not destroy it! -// So in theory you could reuse the DSP for something else. -// In the Global Chain or another sound. -//////////////////////////////////////////////////////////////////// -bool FmodAudioSound:: -remove_dsp(PT(AudioDSP) x) { - FMOD_RESULT result; - - FmodAudioDSP *fdsp; - DCAST_INTO_R(fdsp, x, false); - - if ( fdsp->get_in_chain() ) { - - result = fdsp->_dsp->remove(); - fmod_audio_errcheck("_dsp->remove()", result); - - _sound_dsp.erase(fdsp); - - fdsp->set_in_chain(false); - - return true; - - } else { - - audio_debug("FmodAudioManager()::remove_dsp()"); - audio_debug("This DSP doesn't exist in this chain."); - - return false; - - } -} - - //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::get_speaker_mix // Access: Published diff --git a/panda/src/audiotraits/fmodAudioSound.h b/panda/src/audiotraits/fmodAudioSound.h index 6778267eaf..142ccf1a02 100644 --- a/panda/src/audiotraits/fmodAudioSound.h +++ b/panda/src/audiotraits/fmodAudioSound.h @@ -84,9 +84,6 @@ #include #include -class FmodAudioDSP; - - class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound { public: @@ -151,9 +148,6 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound { AudioSound::SoundStatus status() const; - virtual bool add_dsp( PT(AudioDSP) dspToAdd ); - virtual bool remove_dsp( PT(AudioDSP) x); - virtual float get_speaker_mix(AudioManager::SpeakerId speaker); virtual void set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float sideright); @@ -169,8 +163,6 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound { const string& get_finished_event() const; //////////////////////////////////////////////////////////////////// - protected: - private: PT(FmodAudioManager) _manager; FMOD::Sound *_sound; @@ -200,18 +192,14 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound { void set_play_rate_on_channel(); void set_speaker_mix_on_channel(); void set_3d_attributes_on_channel(); - void add_dsp_on_channel(); + // void add_dsp_on_channel(); void set_speaker_mix_or_balance_on_channel(); virtual int get_priority(); virtual void set_priority(int priority); - - //The Data Structure that holds all the DSPs. - typedef pset DSPSet; - DSPSet _sound_dsp; - + bool _active; - + // This reference-counting pointer is set to this while the sound is // playing, and cleared when we get an indication that the sound has // stopped. This prevents a sound from destructing while it is diff --git a/panda/src/audiotraits/fmod_audio_composite1.cxx b/panda/src/audiotraits/fmod_audio_composite1.cxx index 8032c7158e..da514bbdd5 100644 --- a/panda/src/audiotraits/fmod_audio_composite1.cxx +++ b/panda/src/audiotraits/fmod_audio_composite1.cxx @@ -2,5 +2,4 @@ #include "config_fmodAudio.cxx" #include "fmodAudioManager.cxx" #include "fmodAudioSound.cxx" -#include "fmodAudioDSP.cxx"