From be22aa9d1578886e60f8fc99eaabf8311c8a1621 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Mon, 15 May 2006 15:29:22 +0000 Subject: [PATCH] *** empty log message *** --- panda/src/audio/audio.h | 1 + panda/src/audio/audioDSP.cxx | 195 +++ panda/src/audio/audioDSP.h | 80 + panda/src/audio/audioManager.cxx | 107 +- panda/src/audio/audioManager.h | 57 + panda/src/audio/audioSound.cxx | 68 + panda/src/audio/audioSound.h | 229 +-- panda/src/audio/audio_composite1.cxx | 1 + panda/src/audio/config_audio.cxx | 74 +- panda/src/audio/config_audio.h | 32 +- panda/src/audio/nullAudioDSP.cxx | 187 +++ panda/src/audio/nullAudioDSP.h | 80 + panda/src/audiotraits/config_fmodAudio.cxx | 5 + panda/src/audiotraits/fmodAudioDSP.I | 25 + panda/src/audiotraits/fmodAudioDSP.cxx | 451 ++++++ panda/src/audiotraits/fmodAudioDSP.h | 164 ++ panda/src/audiotraits/fmodAudioManager.cxx | 1314 +++++++--------- panda/src/audiotraits/fmodAudioManager.h | 314 ++-- panda/src/audiotraits/fmodAudioSound.cxx | 1344 +++++++++++++---- panda/src/audiotraits/fmodAudioSound.h | 302 ++-- .../src/audiotraits/fmod_audio_composite1.cxx | 1 + panda/src/display/frameBufferProperties.I | 35 + panda/src/display/frameBufferProperties.cxx | 54 +- panda/src/display/frameBufferProperties.h | 37 +- panda/src/display/graphicsEngine.I | 9 +- panda/src/display/graphicsEngine.cxx | 47 +- panda/src/display/graphicsPipe.h | 1 + panda/src/wgldisplay/wglGraphicsPipe.cxx | 56 +- 28 files changed, 3723 insertions(+), 1547 deletions(-) create mode 100644 panda/src/audio/audioDSP.cxx create mode 100644 panda/src/audio/audioDSP.h create mode 100644 panda/src/audio/nullAudioDSP.cxx create mode 100644 panda/src/audio/nullAudioDSP.h create mode 100644 panda/src/audiotraits/fmodAudioDSP.I create mode 100644 panda/src/audiotraits/fmodAudioDSP.cxx create mode 100644 panda/src/audiotraits/fmodAudioDSP.h diff --git a/panda/src/audio/audio.h b/panda/src/audio/audio.h index 1c3ae2efa9..1bebf78b01 100644 --- a/panda/src/audio/audio.h +++ b/panda/src/audio/audio.h @@ -20,6 +20,7 @@ #define __AUDIO_H__ #include "audioSound.h" +#include "audioDSP.h" #include "audioManager.h" #endif /* __AUDIO_H__ */ diff --git a/panda/src/audio/audioDSP.cxx b/panda/src/audio/audioDSP.cxx new file mode 100644 index 0000000000..f0996a43c2 --- /dev/null +++ b/panda/src/audio/audioDSP.cxx @@ -0,0 +1,195 @@ +// Filename: audioDSP.cxx +// Created by: Stan Rosenbaum "Staque" - Spring 2006 +// +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "audioDSP.h" + +TypeHandle AudioDSP::_type_handle; + + + +//////////////////////////////////////////////////////////////////// +// Function: AudioDSP::reset +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void AudioDSP:: +reset() { + // intentionally blank +} + +//////////////////////////////////////////////////////////////////// +// Function: AudioDSP::remove +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void AudioDSP:: +remove() { + // intentionally blank +} + +//////////////////////////////////////////////////////////////////// +// Function: AudioDSP::set_bypass +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void AudioDSP:: +set_bypass(bool bypass) { + // intentionally blank +} + +//////////////////////////////////////////////////////////////////// +// Function: AudioDSP::get_bypass +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +bool AudioDSP::get_bypass() { + // intentionally blank + + return 0; + +} + + + +//////////////////////////////////////////////////////////////////// +// Function: AudioDSP::set_parameter +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void AudioDSP:: +set_parameter(const string &name, float value) { + // intentionally blank +} + + + +//////////////////////////////////////////////////////////////////// +// Function: AudioDSP::list_parameters_info +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void AudioDSP:: +list_parameters_info() { + int np = get_num_parameters(); + for (int i=0; i1.0 - virtual void set_3d_min_distance(float dist); - virtual float get_3d_min_distance() const; + // Controls the distance (in units) that this sound begins to fall off. + // Also affects the rate it falls off. + // Default is 1.0 + // Closer/Faster, <1.0 + // Farther/Slower, >1.0 + virtual void set_3d_min_distance(float dist); + virtual float get_3d_min_distance() const; - // Controls the maximum distance (in units) that this sound stops falling off. - // The sound does not stop at that point, it just doesn't get any quieter. - // You should rarely need to adjust this. - // Default is 1000000000.0 - virtual void set_3d_max_distance(float dist); - virtual float get_3d_max_distance() const; + // Controls the maximum distance (in units) that this sound stops falling off. + // The sound does not stop at that point, it just doesn't get any quieter. + // You should rarely need to adjust this. + // Default is 1000000000.0 + virtual void set_3d_max_distance(float dist); + virtual float get_3d_max_distance() const; - enum SoundStatus { BAD, READY, PLAYING }; - virtual SoundStatus status() const = 0; + virtual bool add_dsp(PT(AudioDSP) x); + virtual bool remove_dsp(PT(AudioDSP) x); -protected: - AudioSound(); + virtual float get_speaker_mix(int speaker); + virtual void set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float sideright); - friend class AudioManager; + virtual int get_priority(); + virtual void set_priority(int priority); -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - TypedReferenceCount::init_type(); - register_type(_type_handle, "AudioSound", - TypedReferenceCount::get_class_type()); - } - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + enum SoundStatus { BAD, READY, PLAYING }; + virtual SoundStatus status() const = 0; -private: - static TypeHandle _type_handle; + protected: + AudioSound(); + + friend class AudioManager; + + public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "AudioSound", + TypedReferenceCount::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + + private: + static TypeHandle _type_handle; }; #endif /* __AUDIOSOUND_H__ */ diff --git a/panda/src/audio/audio_composite1.cxx b/panda/src/audio/audio_composite1.cxx index 7d9e15ea4e..e320a2232d 100644 --- a/panda/src/audio/audio_composite1.cxx +++ b/panda/src/audio/audio_composite1.cxx @@ -2,6 +2,7 @@ #include "config_audio.cxx" #include "audioManager.cxx" #include "audioSound.cxx" +#include "audioDSP.cxx" #include "nullAudioManager.cxx" #include "nullAudioSound.cxx" diff --git a/panda/src/audio/config_audio.cxx b/panda/src/audio/config_audio.cxx index 1a4fb10a81..042364d397 100644 --- a/panda/src/audio/config_audio.cxx +++ b/panda/src/audio/config_audio.cxx @@ -24,62 +24,38 @@ Configure(config_audio); NotifyCategoryDef(audio, ""); - -ConfigVariableBool audio_active -("audio-active", true); - -ConfigVariableInt audio_cache_limit -("audio-cache-limit", 15, - PRC_DESC("The number of sounds in the cache.")); - -ConfigVariableDouble audio_volume -("audio-volume", 1.0f); - -ConfigVariableDouble audio_doppler_factor -("audio-doppler-factor", 1.0f); - -ConfigVariableDouble audio_distance_factor -("audio-distance-factor", 1.0f); - -ConfigVariableDouble audio_drop_off_factor -("audio-drop-off-factor", 1.0f); - -ConfigVariableInt audio_min_hw_channels -("audio-min-hw-channels", 15, - PRC_DESC("Guarantee this many channels on the local sound card, or just " - "play EVERYTHING in software.")); - -ConfigVariableBool audio_software_midi -("audio-software-midi", false); - -ConfigVariableFilename audio_dls_file -("audio-dls-file", ""); - -ConfigVariableBool audio_play_midi -("audio-play-midi", true); - -ConfigVariableBool audio_play_wave -("audio-play-wave", true); - -ConfigVariableBool audio_play_mp3 -("audio-play-mp3", true); - -ConfigVariableInt audio_output_rate -("audio-output-rate", 22050); - -ConfigVariableInt audio_output_bits -("audio-output-bits", 16); - -ConfigVariableInt audio_output_channels -("audio-output-channels", 2); - ConfigVariableString audio_library_name ("audio-library-name", "miles_audio"); +//I should note this somewhere. +//The actual number of sound one could play is 2 times whatever the default is here. +//In this case 32 * 2 = 64. +//The reason for this, is because of the way Panda creates two seperate audio managers. +//One for sound effects, the other for music files. +//At one time this used to be a concern, because wave files [WAV, AIF, MP3, etc...] and +//Music files [MID MOD IT] used to be treated differently. +//However in current Audio APIs [particularly FMOD] a sound file is treated the same +//no matter what it is. +ConfigVariableInt fmod_number_of_sound_channels +("fmod-number-of-sound-channels", 32, + PRC_DESC("Guarantee this many channels you will have with FMOD. AKA the max number of sounds you can play at one time.") ); + +ConfigVariableBool fmod_use_surround_sound +("fmod-use-surround-sound", false, + PRC_DESC("Determines if an FMOD Flavor of PANDA use 5.1 Surround Sound or Not.") ); + + +//ConfigVariableInt +//ConfigVariableDouble +//ConfigVariableBool +//ConfigVariableFilename + + ConfigureFn(config_audio) { AudioManager::init_type(); AudioSound::init_type(); + AudioDSP::init_type(); } diff --git a/panda/src/audio/config_audio.h b/panda/src/audio/config_audio.h index 7e57ef000c..bd032696b0 100644 --- a/panda/src/audio/config_audio.h +++ b/panda/src/audio/config_audio.h @@ -33,29 +33,19 @@ NotifyCategoryDecl(audio, EXPCL_PANDA, EXPTP_PANDA); -extern EXPCL_PANDA ConfigVariableBool audio_active; -extern EXPCL_PANDA ConfigVariableInt audio_cache_limit; -extern EXPCL_PANDA ConfigVariableDouble audio_volume; - -extern EXPCL_PANDA ConfigVariableDouble audio_doppler_factor; -extern EXPCL_PANDA ConfigVariableDouble audio_distance_factor; -extern EXPCL_PANDA ConfigVariableDouble audio_drop_off_factor; - -extern EXPCL_PANDA ConfigVariableInt audio_min_hw_channels; - -extern EXPCL_PANDA ConfigVariableBool audio_software_midi; -extern EXPCL_PANDA ConfigVariableFilename audio_dls_file; - -extern EXPCL_PANDA ConfigVariableBool audio_play_midi; -extern EXPCL_PANDA ConfigVariableBool audio_play_wave; -extern EXPCL_PANDA ConfigVariableBool audio_play_mp3; - -extern EXPCL_PANDA ConfigVariableInt audio_output_rate; -extern EXPCL_PANDA ConfigVariableInt audio_output_bits; -extern EXPCL_PANDA ConfigVariableInt audio_output_channels; - +//We Need This one. extern EXPCL_PANDA ConfigVariableString audio_library_name; +//This Specifies the number of possible [max] audio channels. +extern EXPCL_PANDA ConfigVariableInt fmod_number_of_sound_channels; + +//This is to turn on Surround Sound. +extern EXPCL_PANDA ConfigVariableBool fmod_use_surround_sound; + + + + + #ifndef NDEBUG //[ // Non-release build: #define audio_debug(msg) \ diff --git a/panda/src/audio/nullAudioDSP.cxx b/panda/src/audio/nullAudioDSP.cxx new file mode 100644 index 0000000000..a5b8418a39 --- /dev/null +++ b/panda/src/audio/nullAudioDSP.cxx @@ -0,0 +1,187 @@ +// Filename: nullAudioDSP.cxx +// Created by: Stan Rosenbaum "Staque" - Spring 2006 +// +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "nullAudioDSP.h" + +TypeHandle nullAudioDSP::_type_handle; + + + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::reset +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void nullAudioDSP:: +reset() { + // intentionally blank +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::remove +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void nullAudioDSP:: +remove() { + // intentionally blank +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::set_bypass +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void nullAudioDSP:: +set_bypass(bool bypass) { + // intentionally blank +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::get_bypass +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +bool nullAudioDSP::get_bypass() { + // intentionally blank + + return 0; + +} + + + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::set_parameter +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void nullAudioDSP:: +set_parameter(const string &name, float value) { + // intentionally blank +} + + + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::list_parameters_info +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void nullAudioDSP:: +list_parameters_info() { + // intentionally blank +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::get_num_parameters +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +int nullAudioDSP:: +get_num_parameters() { + // intentionally blank + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::get_parameter_name +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +string nullAudioDSP:: +get_parameter_name(int index) { + + return ""; +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::get_parameter_description +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +string nullAudioDSP:: +get_parameter_description(int index) { + // intentionally blank + return ""; +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::get_parameter_min +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +float nullAudioDSP:: +get_parameter_min(int index) { + // intentionally blank + return 0.0; +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::get_parameter_max +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +float nullAudioDSP:: +get_parameter_max(int index) { + // intentionally blank + return 1.0; +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::get_parameter_value +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +float nullAudioDSP:: +get_parameter_value(const string &name) { + // intentionally blank + return 1.0; +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::Constructor +// Access: Protected +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +nullAudioDSP::nullAudioDSP() { + // Intentionally blank. +} + +//////////////////////////////////////////////////////////////////// +// Function: nullAudioDSP::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +nullAudioDSP::~nullAudioDSP() { +} + diff --git a/panda/src/audio/nullAudioDSP.h b/panda/src/audio/nullAudioDSP.h new file mode 100644 index 0000000000..55af330252 --- /dev/null +++ b/panda/src/audio/nullAudioDSP.h @@ -0,0 +1,80 @@ +// Filename: nullAudioDSP.h +// Created by: Stan Rosenbaum "Staque" - Spring 2006 + +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef __NULLAUDIODSP_H__ +#define __NULLAUDIODSP_H__ + +#include "config_audio.h" +#include "typedReferenceCount.h" +#include "pointerTo.h" + +class AudioManager; + + +class EXPCL_PANDA nullAudioDSP : public TypedReferenceCount { + PUBLISHED: + virtual void reset(); + virtual void remove(); + virtual void set_bypass(bool bypass); + virtual void set_parameter(const string &name, float value); + virtual float get_parameter_value(const string &name); + + virtual bool get_bypass(); + void list_parameters_info(); + + virtual int get_num_parameters(); + virtual string get_parameter_name(int index); + virtual string get_parameter_description(int index); + virtual float get_parameter_min(int index); + virtual float get_parameter_max(int index); + + + virtual ~nullAudioDSP(); + + protected: + nullAudioDSP(); + + //////////////////////////////////////////////////////////// + //These are needed for Panda's Pointer System. DO NOT ERASE! + //////////////////////////////////////////////////////////// + + public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "nullAudioDSP", + TypedReferenceCount::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + + private: + static TypeHandle _type_handle; + + //////////////////////////////////////////////////////////// + //DONE + //////////////////////////////////////////////////////////// + + }; + +#endif /* __nullAudioDSP_H__ */ diff --git a/panda/src/audiotraits/config_fmodAudio.cxx b/panda/src/audiotraits/config_fmodAudio.cxx index 3d5f54fe30..c83ff4d818 100644 --- a/panda/src/audiotraits/config_fmodAudio.cxx +++ b/panda/src/audiotraits/config_fmodAudio.cxx @@ -23,6 +23,7 @@ #include "config_fmodAudio.h" #include "fmodAudioManager.h" #include "fmodAudioSound.h" +#include "fmodAudioDSP.h" #include "pandaSystem.h" #include "dconfig.h" @@ -52,6 +53,10 @@ init_libFmodAudio() { AudioManager::register_AudioManager_creator(Create_AudioManager); + FmodAudioManager::init_type(); + FmodAudioSound::init_type(); + FmodAudioDSP::init_type(); + PandaSystem *ps = PandaSystem::get_global_ptr(); ps->add_system("FMOD"); ps->add_system("audio"); diff --git a/panda/src/audiotraits/fmodAudioDSP.I b/panda/src/audiotraits/fmodAudioDSP.I new file mode 100644 index 0000000000..30a5196d7a --- /dev/null +++ b/panda/src/audiotraits/fmodAudioDSP.I @@ -0,0 +1,25 @@ +// Filename: fmodAudioDSP.I +// Created by: Stan Rosenbaum "Staque" - Spring 2006 +// +// +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + + + + + diff --git a/panda/src/audiotraits/fmodAudioDSP.cxx b/panda/src/audiotraits/fmodAudioDSP.cxx new file mode 100644 index 0000000000..c905249e6c --- /dev/null +++ b/panda/src/audiotraits/fmodAudioDSP.cxx @@ -0,0 +1,451 @@ +// Filename: fmodAudioDSP.cxx +// Created by: Stan Rosenbaum "Staque" - Spring 2006 +// +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "pandabase.h" +#include "dcast.h" + +#ifdef HAVE_FMOD //[ + +//Panda Headers +#include "config_audio.h" +#include "fmodAudioDSP.h" + + +TypeHandle FmodAudioDSP::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::FmodAudioDSP +// Access: Protected +// Description: Constructor +// This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +FmodAudioDSP::FmodAudioDSP(AudioManager *manager, AudioManager::DSP_category cat) { + // Intentionally blank. + + audio_debug("FmodAudioDSP::FmodAudioDSP() Creating new DSP " ); + + //Local Variables that are needed. + FMOD_RESULT result; + + //Assign the values we need + DCAST_INTO_V(_manager, manager); + + FMOD_DSP_TYPE dsptype = (FMOD_DSP_TYPE)cat; + + result = _manager->_system->createDSPByType( dsptype, &_dsp); + ERRCHECK(result); + + set_in_chain(false); + + cerr << get_dsp_name() << endl; + + audio_debug("DSP Loaded"); + +} + + + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::Destructor +// Access: Published, Virtual +// Description: DESTRUCTOR!!! +//////////////////////////////////////////////////////////////////// +FmodAudioDSP::~FmodAudioDSP() { + + audio_debug("FmodAudioSound::FmodAudioDSP() Destruction!!! " ); + + //Local Variables that are needed. + FMOD_RESULT result; + + result = _dsp->remove(); + ERRCHECK(result); + + result = _dsp->release(); + ERRCHECK(result); + + audio_debug("DSP GONE"); + +} + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::reset +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +// [This resets an FMOD DSP to its default values] +//////////////////////////////////////////////////////////////////// +void FmodAudioDSP::reset() { + + audio_debug("FmodAudioSound::reset() Reset DSP to default settings." ); + + //Local Variables that are needed. + FMOD_RESULT result; + + result = _dsp->reset(); + ERRCHECK(result); + + audio_debug("DSP Reset."); + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::remove +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +// [This removes the DSP from an Effects Chain] +//////////////////////////////////////////////////////////////////// +void FmodAudioDSP::remove() { + audio_debug("FmodAudioSound::remove() Removes a DSP from and effect chain." ); + + //Local Variables that are needed. + FMOD_RESULT result; + + result = _dsp->remove(); + ERRCHECK(result); + + audio_debug("DSP Removed from relative effects chain."); + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::set_bypass +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +// [This turns the Bypass for an Effect on and off]/ +//////////////////////////////////////////////////////////////////// +void FmodAudioDSP::set_bypass(bool bypass) { + audio_debug("FmodAudioSound::set_bypass() ." ); + + //Local Variables that are needed. + FMOD_RESULT result; + + result = _dsp->setBypass(bypass); + ERRCHECK(result); + + audio_debug("DSP Bypass set to:" << bypass ); +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::get_bypass +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +bool FmodAudioDSP::get_bypass() { + audio_debug("FmodAudioSound::get_bypass() ." ); + + //Local Variables that are needed. + FMOD_RESULT result; + + bool bypass; + + result = _dsp->getBypass(&bypass); + ERRCHECK(result); + + return bypass; + +} + + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::set_parameter +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +void FmodAudioDSP::set_parameter(const string &name, float value) { + + int parameterIndex = find_parameter(name); + if (parameterIndex < 0) { + return; + } + + //Local Variables that are needed. + FMOD_RESULT result; + + result = _dsp->setParameter(parameterIndex, value); + ERRCHECK(result); + +} + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::get_num_parameters +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +int FmodAudioDSP::get_num_parameters() { + audio_debug("FmodAudioSound::get_num_parameters() ." ); + + //Local Variables that are needed. + FMOD_RESULT result; + + int numOfParameters; + + result = _dsp->getNumParameters(&numOfParameters); + ERRCHECK(result); + + return numOfParameters; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::get_parameter_name +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +string FmodAudioDSP::get_parameter_name(int parameterIndex) { + // intentionally blank + + audio_debug("FmodAudioSound::get_parameter_name()" ); + + //Local Variables that are needed. + FMOD_RESULT result; + + //int parameterIndex; + char parameterName[32]; + char parameterLabel[32]; + char parameterDescription[32]; + int parameterDescriptionLength = 0; + float parameterMin; + float parameterMax; + + result = _dsp->getParameterInfo(parameterIndex, parameterName, parameterLabel, parameterDescription, parameterDescriptionLength, ¶meterMin, ¶meterMax); + ERRCHECK(result); + + string returnInfo = (parameterName); + + return returnInfo; + + //return ""; +} + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::get_parameter_description +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +// This Method actually returns FMOD's Parameter Label +// Information, and not Description. +// The reason is, that most of the FMOD's Description +// Properties seem to be empty. +// Also the Label sort of serves as as a description by +// return the type of unit the cooresponding parameter +// modifies for a DSP. +// IE. For the Echo. The first parameter is 'Delay' +// and the units for measuring the Delay is in Milliseconds. +// The Label returns Milliseconds letting you know that. +//////////////////////////////////////////////////////////////////// +string FmodAudioDSP::get_parameter_description(int parameterIndex) { + // intentionally blank + + audio_debug("FmodAudioSound::get_parameter_description()." ); + + //Local Variables that are needed. + FMOD_RESULT result; + + //int parameterIndex; + char parameterName[32]; + char parameterLabel[32]; + char parameterDescription[32]; + int parameterDescriptionLength = 0; + float parameterMin; + float parameterMax; + + result = _dsp->getParameterInfo(parameterIndex, parameterName, parameterLabel, parameterDescription, parameterDescriptionLength, ¶meterMin, ¶meterMax); + ERRCHECK(result); + + return parameterLabel; + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::get_parameter_min +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +float FmodAudioDSP::get_parameter_min(int parameterIndex) { + + audio_debug("FmodAudioSound::get_parameter_min()." ); + + //Local Variables that are needed. + FMOD_RESULT result; + + //int parameterIndex; + char parameterName[32]; + char parameterLabel[32]; + char parameterDescription[32]; + int parameterDescriptionLength = 0; + float parameterMin; + float parameterMax; + + result = _dsp->getParameterInfo(parameterIndex, parameterName, parameterLabel, parameterDescription, parameterDescriptionLength, ¶meterMin, ¶meterMax); + ERRCHECK(result); + + return parameterMin; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::get_parameter_max +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +float FmodAudioDSP::get_parameter_max(int parameterIndex) { + + audio_debug("FmodAudioSound::get_parameter_min()." ); + + //Local Variables that are needed. + FMOD_RESULT result; + + //int parameterIndex; + char parameterName[32]; + char parameterLabel[32]; + char parameterDescription[32]; + int parameterDescriptionLength = 0; + float parameterMin; + float parameterMax; + + result = _dsp->getParameterInfo(parameterIndex, parameterName, parameterLabel, parameterDescription, parameterDescriptionLength, ¶meterMin, ¶meterMax); + ERRCHECK(result); + + return parameterMax; +} + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::get_parameter_value +// Access: Published, Virtual +// Description: This is a thin wrapper around FMOD-EX. +// See the FMOD-EX documentation. +//////////////////////////////////////////////////////////////////// +float FmodAudioDSP::get_parameter_value(const string &name) { + + int parameterIndex = find_parameter(name); + if (parameterIndex < 0) { + return 0.0; + } + + //Local Variables that are needed. + FMOD_RESULT result; + + float parameterValue; + char valuestr[32]; + int valuestrlen = 32; + + + result = _dsp->getParameter(parameterIndex, ¶meterValue, valuestr, valuestrlen); + ERRCHECK(result); + + return parameterValue; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::find_parameter +// Access: Private +// Description: Convert a parameter name to an fmod parameter index. +//////////////////////////////////////////////////////////////////// +int FmodAudioDSP::find_parameter(const string &name) { + int np = get_num_parameters(); + for (int i=0; igetInfo(name, &version, &channels, &configwidth, &configheight); + ERRCHECK(result); + + string returnInfo = (name); + //returnInfo.append(" Version: "); + //returnInfo.append(version); + //returnInfo.append("\n"); + + return returnInfo; + +} + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::get_in_chain() +// Access: Published, Virtual +// Description: This is a functiont to query if a DSP have been assigned +// to the GLOBAL or a SOUND's effect chain. +// This is to make sure you 'remove' an effect from a chain +// before you move it somewhere else or destroy it. +//////////////////////////////////////////////////////////////////// +bool FmodAudioDSP::get_in_chain() { + + audio_debug("FmodAudioSound::get_in_chain()." ); + + return _in_chain; + + +} + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioDSP::set_in_chain() +// Access: Published, Virtual +// Description: This is a functiont to set if a DSP have been assigned +// to the GLOBAL or a SOUND's effect chain. +//////////////////////////////////////////////////////////////////// +void FmodAudioDSP::set_in_chain(bool chain_state) { + + audio_debug("FmodAudioSound::set_in_chain()." ); + + _in_chain = chain_state; + +} + + + +#endif //] diff --git a/panda/src/audiotraits/fmodAudioDSP.h b/panda/src/audiotraits/fmodAudioDSP.h new file mode 100644 index 0000000000..1856cac888 --- /dev/null +++ b/panda/src/audiotraits/fmodAudioDSP.h @@ -0,0 +1,164 @@ +// Filename: fmodAudioDSP.h +// Created by: Stan Rosenbaum "Staque" - Spring 2006 +// +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// +//[FIRST READ FmodAudioManager and then maybe FmodAudioSound for an Introduction +//if you haven't already]. +// +//Hello, all future Panda audio code people! This is my errata documentation to +//Help any future programmer maintain FMOD and PANDA. +// +//Finally let’s talk about the DSP, or Digital Signal Processing. To the layman, +//these are filters and shaders for sound. +// +//Currently FmodAudioDSP give you access to all of FMOD’s built in DSP functions. +// +//The enumerated list for the types are found in the ‘AudioManager.h’, but I will +//repeat it here for good fortune. +// +// enum DSP_category { +// // These enumerants line up one-to-one +// // with the FMOD DSP enumerants. +// DSP_unknown, +// DSP_mixer, +// DSP_oscillator, +// DSP_lowpass, +// DSP_itlowpass, +// DSP_highpass, +// DSP_echo, +// DSP_flange, +// DSP_distortion, +// DSP_normalize, +// DSP_parameq, +// DSP_pitchshift, +// DSP_chorus, +// DSP_reverb, +// DSP_vstplugin, +// DSP_winampplugin, +// DSP_itecho, +// DSP_COUNT +// }; +// +//Now, I want to point a couple things out. First, we have to place the above list +//in AudioManager.h because that was the only way to them to be ‘PUBLISHED’ in +//Panda’s Python bindings when you build Panda. +// +//Second, you only need to use the ‘it####’ named DSP effects if you are using +//mod/tracker files. [If you don’t know what a mod/tracker file is you probably +//aren’t using them so don’t worry about it.] +// +//I think that is everything, the DSP info was pretty short. +//////////////////////////////////////////////////////////////////// +// + + + +#ifndef __FMOD_AUDIO_DSP_H__ +#define __FMOD_AUDIO_DSP_H__ + +#include + +#ifdef HAVE_FMOD //[ + +#include "audioManager.h" +#include "audioDSP.h" + +#include +#include + +class EXPCL_FMOD_AUDIO FmodAudioDSP : public AudioDSP { + + public: + + FmodAudioDSP(AudioManager *mgr, AudioManager::DSP_category); + + virtual void reset(); + virtual void remove(); + virtual void set_bypass(bool bypass); + virtual void set_parameter(const string &name, float value); + virtual float get_parameter_value(const string &name); + + virtual bool get_bypass(); + + virtual int get_num_parameters(); + virtual string get_parameter_name(int index); + virtual string get_parameter_description(int index); + virtual float get_parameter_min(int index); + virtual float get_parameter_max(int index); + + bool get_in_chain(); + void set_in_chain(bool chain_state); + + virtual ~FmodAudioDSP(); + + protected: + virtual string get_dsp_name(); + + + private: + int find_parameter(const string &pn); + + bool _in_chain; + FmodAudioManager *_manager; + FMOD::DSP *_dsp; + + friend class FmodAudioManager; + friend class FmodAudioSound; + + + //////////////////////////////////////////////////////////// + //These are needed for Panda's Pointer System. DO NOT ERASE! + //////////////////////////////////////////////////////////// + + public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + AudioDSP::init_type(); + register_type(_type_handle, "FmodAudioDSP", AudioDSP::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() { + init_type(); + return get_class_type(); + } + + private: + static TypeHandle _type_handle; + + //////////////////////////////////////////////////////////// + //DONE + //////////////////////////////////////////////////////////// + +}; + +#include "fmodAudioDSP.I" + +#endif //] + +#endif /* __FMOD_AUDIO_DSP_H__ */ + + + + + + + + diff --git a/panda/src/audiotraits/fmodAudioManager.cxx b/panda/src/audiotraits/fmodAudioManager.cxx index ec2e463afb..2f042105a8 100644 --- a/panda/src/audiotraits/fmodAudioManager.cxx +++ b/panda/src/audiotraits/fmodAudioManager.cxx @@ -1,6 +1,8 @@ // Filename: fmodAudioManager.cxx // Created by: cort (January 22, 2003) // Prior system by: cary +// Rewrite [for new Version of FMOD-EX] by: Stan Rosenbaum "Staque" - Spring 2006 +// // //////////////////////////////////////////////////////////////////// // @@ -18,604 +20,460 @@ //////////////////////////////////////////////////////////////////// #include "pandabase.h" +#include "config_audio.h" +#include "dcast.h" + #ifdef HAVE_FMOD //[ +//Panda headers. #include "config_audio.h" -#include "config_util.h" -#include "config_express.h" -#include "filename.h" #include "fmodAudioManager.h" #include "fmodAudioSound.h" -#include "nullAudioSound.h" -#include "virtualFileSystem.h" -#include "string_utils.h" +#include "fmodAudioDSP.h" +//Needed so People use Panda's Generic UNIX Style Paths for Filename. +#include "filename.h" -#include -#include -#include -PT(AudioManager) Create_AudioManager() { - audio_debug("Create_AudioManager() Fmod."); - return new FmodAudioManager; +//FMOD Headers. +#include +#include + + +//////////////////////////////////////////////////////////////////// +// This in needed for Panda's Pointer System +// DO NOT ERASE! +//////////////////////////////////////////////////////////////////// + +TypeHandle FmodAudioManager::_type_handle; + +//////////////////////////////////////////////////////////////////// +// END OF POINTER THING +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// OK I am not sure if there is the best place for this one, +// but it seems to work. IE, the FmodSound and FmodDSP classes can find it. +// All FMOD API calls return a success or failure error. +// [I am sure there is a name for this type of programming but I don't know it.] +// Anyway, by adding the line "notify-level-audio debug" to the config.prc file +// of Panda, of the config.in file of MAKEPANDA, you can see the Debugs printed out at the +// Python Prompt +///////////////////////////////////////////////////////////////////// +void ERRCHECK(FMOD_RESULT result){ + audio_debug("FMOD State: "<< result <<" "<< FMOD_ErrorString(result) ); +} + + +PT(AudioManager) Create_AudioManager() { + audio_debug("Create_AudioManager() Fmod."); + return new FmodAudioManager; } -int FmodAudioManager::_active_managers = 0; //////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::FmodAudioManager -// Access: -// Description: +// Function: FmodAudioManager::FmodAudioManager() +// Access: Public +// Description: Constructor //////////////////////////////////////////////////////////////////// -FmodAudioManager:: -FmodAudioManager() { - audio_debug("FmodAudioManager::FmodAudioManager()"); - audio_debug(" audio_active="<getVersion(&version); + ERRCHECK(result); + + audio_debug("FMOD VERSION:" << hex << version ); + audio_debug("FMOD - Getting Version"); + + if (version < FMOD_VERSION){ + audio_debug("Error! You are using an old version of FMOD. This program requires:" << FMOD_VERSION); + } + + //Stick Surround Sound 5.1 thing Here. + + audio_debug("Checking for Surround Sound Flag.") + + cerr << fmod_use_surround_sound << endl ; + + if (fmod_use_surround_sound) { + audio_debug("Setting FMOD to use 5.1 Surround Sound.") + result = _system->setSpeakerMode( FMOD_SPEAKERMODE_5POINT1 ); + ERRCHECK(result); + } + + //Now we Initialize the System. + + audio_debug("FMOD::System_Init"); + result = _system->init(fmod_number_of_sound_channels, FMOD_INIT_NORMAL, 0); + ERRCHECK(result); + + if (result == FMOD_OK){ + audio_debug("FMOD Intialized OK, We are good to go Houston!"); + _is_valid = true; + } else { + audio_debug("Something is still wrong with FMOD! Check source."); + _is_valid = false; + } + + // This sets the distance factor for 3D audio to use feet. + // FMOD uses meters by default. + // Since Panda use feet we need to compensate for that with a factor of 3.28 + // + // This can be over written. You just need to call + // audio_3d_set_distance_factor(float factor) and set you new factor. + + _doppler_factor = 1; + _distance_factor = 3.28; + _drop_off_factor = 1; + + audio_debug("Setting 3D Audio settings: Doppler Factor, Distance Factor, Drop Off Factor"); + + result = _system->set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor); + ERRCHECK( result ); - if (_is_valid) { - nassertv(is_valid()); - } } //////////////////////////////////////////////////////////////////// // Function: FmodAudioManager::~FmodAudioManager // Access: Public -// Description: +// Description: DESTRCUTOR !!! //////////////////////////////////////////////////////////////////// -FmodAudioManager:: -~FmodAudioManager() { - // Be sure to delete associated sounds before deleting the manager! - nassertv(_soundsOnLoan.empty()); - clear_cache(); - --_active_managers; - audio_debug("~FmodAudioManager(): "<<_active_managers<<" still active"); - if (_active_managers == 0) { - audio_debug("Shutting down FMOD"); - FSOUND_Close(); - } +FmodAudioManager::~FmodAudioManager() { + // Be sure to delete associated sounds before deleting the manager! + audio_debug("~FmodAudioManager(): Closing Down"); + + FMOD_RESULT result; + + //Release DSPs First + _system_dsp.clear(); + + //Release Sounds Next + _all_sounds.clear(); + + //result = _system->close(); + //ERRCHECK(result); + + result = _system->release(); + ERRCHECK(result); + + audio_debug("~FmodAudioManager(): System Down."); + } //////////////////////////////////////////////////////////////////// // Function: FmodAudioManager::is_valid // Access: Public -// Description: +// Description: This just check to make sure the FMOD System is +// up and running correctly. +//////////////////////////////////////////////////////////////////// +bool FmodAudioManager::is_valid() { + audio_debug("FmodAudioManager::is_valid() = " << _is_valid ); + return _is_valid; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::get_sound() +// Access: Public +// Description: This is what creates a sound instance. +//////////////////////////////////////////////////////////////////// +PT(AudioSound) FmodAudioManager::get_sound(const string &file_name, bool positional) { + + audio_debug("FmodAudioManager::get_sound(file_name=\""<get_in_chain() ) { + + audio_debug("FmodAudioManager()::add_dsp"); + audio_debug("This DSP has already been assigned to the system or a sound."); + + return false; + + } else + { + + result = _system->addDSP( fdsp->_dsp ); + ERRCHECK( 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:: -is_valid() { - bool check=true; - if (_sounds.size() != _lru.size()) { - audio_debug("--sizes--"); - check=false; - } else { - LRU::const_iterator i=_lru.begin(); - for (; i != _lru.end(); ++i) { - SoundMap::const_iterator smi=_sounds.find(*i); - if (smi == _sounds.end()) { - audio_debug("--"<<*i<<"--"); - check=false; - break; - } - } - } - return _is_valid && check; +remove_dsp(PT(AudioDSP) x) { + // intentionally blank + + FMOD_RESULT result; + + FmodAudioDSP *fdsp; + DCAST_INTO_R(fdsp, x, false); + + if ( fdsp->get_in_chain() ) { + + result = fdsp->_dsp->remove(); + ERRCHECK( result ); + + _system_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: FmodAudioManager::getSpeakerSetup() +// Access: Published +// Description: This is to query if you are using a MultiChannel Setup. +//////////////////////////////////////////////////////////////////// +int FmodAudioManager:: +getSpeakerSetup() { + // intentionally blank + + FMOD_RESULT result; + FMOD_SPEAKERMODE speakerMode; + int returnMode; + + result = _system->getSpeakerMode( &speakerMode ); + ERRCHECK( result ); + + switch (speakerMode) { + case FMOD_SPEAKERMODE_RAW: + returnMode = 0; + break; + case FMOD_SPEAKERMODE_MONO: + returnMode = 1; + break; + case FMOD_SPEAKERMODE_STEREO: + returnMode = 2; + break; + case FMOD_SPEAKERMODE_QUAD: + returnMode = 3; + break; + case FMOD_SPEAKERMODE_SURROUND: + returnMode = 4; + break; + case FMOD_SPEAKERMODE_5POINT1: + returnMode = 5; + break; + case FMOD_SPEAKERMODE_7POINT1: + returnMode = 6; + break; + case FMOD_SPEAKERMODE_PROLOGIC: + returnMode = 7; + break; + case FMOD_SPEAKERMODE_MAX: + returnMode = 8; + break; + default: + returnMode = -1; + } + + return returnMode; } //////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::get_sound +// Function: FmodAudioManager::setSpeakerSetup() +// Access: Published +// Description: This is to set up FMOD to use a MultiChannel Setup. +// This method is pretty much useless. +// To set a speaker setup in FMOD for Surround Sound, +// stereo, or whatever you have to set the SpeakerMode +// BEFORE you Initialize FMOD. +// Since Panda Inits the FmodAudioManager right when you +// Start it up, you are never given an oppertunity to call +// this function. +// That is why I stuck a BOOL in the CONFIG.PRC file, whichs +// lets you flag if you want to use a Multichannel or not. +// That will set the speaker setup when an instance of this +// class is constructed. +// Still I put this here as a measure of good faith, since you +// can query the speaker setup after everything in Init. +// Also, maybe someone will completely hack Panda someday, in which +// one can init or re-init the AudioManagers after Panda is running. +//////////////////////////////////////////////////////////////////// +void FmodAudioManager:: +setSpeakerSetup(AudioManager::SPEAKERMODE_category cat) { + // intentionally blank + + audio_debug("FmodAudioSound::setSpeakerSetup() " ); + + //Local Variables that are needed. + FMOD_RESULT result; + + FMOD_SPEAKERMODE speakerModeType = (FMOD_SPEAKERMODE)cat; + + result = _system->setSpeakerMode( speakerModeType); + ERRCHECK(result); + + audio_debug("Speaker Mode Set"); + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::set_volume(float volume) +// Access: Public +// Description: +// There isn't a specific system volume function in FMOD-EX, +// so this function is moot now. +//////////////////////////////////////////////////////////////////// +void FmodAudioManager::set_volume(float volume) { + audio_debug("FmodAudioManager::set_volume()" ); + audio_debug("This function has no effect in this version." ) + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::get_volume() +// Access: Public +// Description: +// There isn't a specific system volume function in FMOD-EX, +// so this function is moot now. +//////////////////////////////////////////////////////////////////// +float FmodAudioManager::get_volume() const { + audio_debug("FmodAudioManager::get_volume() returning "); + audio_debug("This function has no effect in this version." ) + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::set_active(bool active) +// Access: Public +// Description: Turn on/off +// Again, this function is pretty much moot in this version now. +//////////////////////////////////////////////////////////////////// +void FmodAudioManager::set_active(bool active) { + audio_debug("FmodAudioManager::set_active(flag="<resolve_filename(path, get_sound_path()); - } - } else { // no suffix given. Search for supported file types of the same name. - audio_debug("FmodAudioManager::get_sound: \""<resolve_filename(path, get_sound_path())) { - break; // break out of loop with a valid type_i value and path with correct extension - } - } // end for loop - // if no valid file found - if (type_i == _supported_types.end() ) { - // just print a warning for now - audio_debug("FmodAudioManager::get_sound: \""<= (unsigned int)_cache_limit) { - nassertr(is_valid(), NULL); - if (!uncache_a_sound()) { - audio_warning(_sounds.size()+1 << " sounds cached. Limit is " << _cache_limit ); - break; - } - } - - si = _sounds.insert(SoundMap::value_type(path, new_entry)).first; - - // It's important that we assign entry to the address of the entry - // we just added to the map, and not to the address of the - // temporary variable new_entry, which we just defined locally and - // is about to go out of scope. - entry = &(*si).second; - } - nassertr(entry != NULL, NULL); - - // Create an FMOD object from the memory-mapped file. Here remains - // one last vestige of special-case MIDI code: apparently, FMOD - // doesn't like creating streams from memory-mapped MIDI files. - // They must therefore be streamed from disk every time. This - // causes strange things to happen when the same MIDI file is loaded - // twice, and played simultaneously...so, *don't do that then*. all - // I can say is that MIDI support will be significantly improved in - // FMOD v4.0! - FSOUND_STREAM *stream = NULL; - int flags = FSOUND_LOADMEMORY | FSOUND_MPEGACCURATE; - - // 3D sounds have to be mono. Forcing stereo streams - // to be mono will create a speed hit. - if (positional) { - flags |= FSOUND_HW3D | FSOUND_FORCEMONO; - } else { - flags |= FSOUND_2D; - } - if (audio_output_bits == 8) { - flags |= FSOUND_8BITS; - } else if (audio_output_bits == 16) { - flags |= FSOUND_16BITS; - } - if (audio_output_channels == 1) { - flags |= FSOUND_FORCEMONO; - } - - string os_path = path.to_os_specific(); - //string suffix = downcase(path.get_extension()); // declared above by RobCode - - if (suffix == "mid" || suffix == "rmi" || suffix == "midi") { - stream = FSOUND_Stream_Open(os_path.c_str(), 0, 0, 0); - } else { - stream = FSOUND_Stream_Open((const char*)(entry->data), - flags, 0, entry->size); - } - if (stream == NULL) { - audio_cat.error() - << "FmodAudioManager::get_sound(" << file_name << ", " << positional - << ") failed.\n"; - return get_null_sound(); - } - inc_refcount(path); - most_recently_used(path); - - // determine length of sound - float length = (float)FSOUND_Stream_GetLengthMs(stream) * 0.001f; - - // Build a new AudioSound from the audio data. - PT(AudioSound) audioSound = 0; - PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, stream, path, - length); - audio_debug("BOO!"); - fmodAudioSound->set_active(_active); - audio_debug("GAH!"); - _soundsOnLoan.insert(fmodAudioSound); - audio_debug("GIR!"); - audioSound = fmodAudioSound; - - audio_debug(" returning 0x" << (void*)audioSound); - nassertr(is_valid(), NULL); - audio_debug("GOO!"); - - return audioSound; +bool FmodAudioManager::get_active() const { + audio_debug("FmodAudioManager::get_active() returning "<<_active); + return _active; } //////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::uncache_sound -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -uncache_sound(const string& file_name) { - audio_debug("FmodAudioManager::uncache_sound(\""<resolve_filename(path, get_sound_path()); - audio_debug(" path=\""<refcount == 0) { - // If the refcount is already zero, it can be - // purged right now! - audio_debug("FmodAudioManager::uncache_sound: purging "<data; - - // Erase the sound from the LRU list as well. - nassertv(_lru.size()>0); - LRU::iterator lru_i=find(_lru.begin(), _lru.end(), itor->first); - nassertv(lru_i != _lru.end()); - _lru.erase(lru_i); - _sounds.erase(itor); - } else { - entry->stale = true; - } - - nassertv(is_valid()); -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::uncache_a_sound -// Access: Public -// Description: Uncaches the least recently used sound. -//////////////////////////////////////////////////////////////////// -bool FmodAudioManager:: -uncache_a_sound() { - audio_debug("FmodAudioManager::uncache_a_sound()"); - nassertr(is_valid(), false); - // uncache least recently used: - unsigned int orig_size = _lru.size(); - - for (LRU::iterator it = _lru.begin(); it != _lru.end(); it++) { - LRU::reference path=_lru.front(); - SoundMap::iterator i = _sounds.find(path); - if (i == _sounds.end()) continue; - audio_debug(" uncaching \""<first<<"\""); - uncache_sound(path); - nassertr(is_valid(), false); - if (_lru.size() < orig_size) return true; - } - return false; -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::most_recently_used -// Access: Public -// Description: Indicates that the given sound was the most recently used. -//////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -most_recently_used(const string& path) { - audio_debug("FmodAudioManager::most_recently_used(path=\"" - <refcount == 0) { - audio_debug("FmodAudioManager::clear_cache: purging "<< (*itor).first - << " from the cache."); - delete [] entry->data; - - // Erase the sound from the LRU list as well. - nassertv(_lru.size()>0); - LRU::iterator lru_i=find(_lru.begin(), _lru.end(), itor->first); - nassertv(lru_i != _lru.end()); - _lru.erase(lru_i); - _sounds.erase(itor); - - itor = _sounds.begin(); - } else { - entry->stale = true; - ++itor; - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::set_cache_limit -// Access: Public -// Description: Set the number of sounds that the cache can hold. -//////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -set_cache_limit(unsigned int count) { - audio_debug("FmodAudioManager::set_cache_limit(count="< count) { - nassertv(is_valid()); - uncache_a_sound(); - } - _cache_limit = count; - nassertv(is_valid()); -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::get_cache_limit -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -unsigned int FmodAudioManager:: -get_cache_limit() const { - audio_debug("FmodAudioManager::get_cache_limit() returning " - <<_cache_limit); - return _cache_limit; -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::release_sound -// Access: Private -// Description: -//////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -release_sound(FmodAudioSound* audioSound) { - audio_debug("FmodAudioManager::release_sound(audioSound=\"" - <get_name()<<"\")"); - dec_refcount(audioSound->get_name()); - _soundsOnLoan.erase(audioSound); -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::set_volume -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -set_volume(float volume) { - audio_debug("FmodAudioManager::set_volume(volume="< 0) { - SoundsPlaying::iterator sound = _sounds_playing.begin(); - nassertv(sound != _sounds_playing.end()); - (**sound).stop(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::stop_a_sound -// Access: Public -// Description: Stop playback on one sound managed by this manager. -//////////////////////////////////////////////////////////////////// -//void FmodAudioManager:: -//stop_a_sound() { -// audio_debug("FmodAudioManager::stop_a_sound()"); -// AudioSet::size_type s=_soundsOnLoan.size() - 1; -// reduce_sounds_playing_to(s); - //if (s == _soundsOnLoan.size()) return true; - //return false; -//} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::stop_all_sounds +// Function: FmodAudioManager::stop_all_sounds() // Access: Public // Description: Stop playback on all sounds managed by this manager. //////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -stop_all_sounds() { - audio_debug("FmodAudioManager::stop_all_sounds()"); - reduce_sounds_playing_to(0); - //AudioSet::iterator i=_soundsOnLoan.begin(); - //for (; i!=_soundsOnLoan.end(); ++i) { - // if ((**i).status()==AudioSound::PLAYING) { - // (**i).stop(); - // } - //} +void FmodAudioManager::stop_all_sounds() { + + audio_debug("FmodAudioManager::stop_all_sounds()" ); + + for (SoundSet::iterator i = _all_sounds.begin(); i != _all_sounds.end(); ++i) { + + (*i)->stop(); + + } + } //////////////////////////////////////////////////////////////////// @@ -625,35 +483,53 @@ stop_all_sounds() { // positioned sounds. Normally, you'd want to call this // once per iteration of your main loop. //////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -audio_3d_update() { - audio_debug("FmodAudioManager::audio_3d_update()"); - FSOUND_Update(); +void FmodAudioManager::audio_3d_update() { + audio_debug("FmodAudioManager::audio_3d_update()"); + audio_debug("Calling FMOD's update function"); + + _system->update(); + } //////////////////////////////////////////////////////////////////// // Function: FmodAudioManager::audio_3d_set_listener_attributes // Access: Public // Description: Set position of the "ear" that picks up 3d sounds +// NOW LISTEN UP!!! THIS IS IMPORTANT! +// Both Panda3D and FMOD use a left handed coordinate system. +// But there is a major difference! +// In Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up. +// In FMOD the Y-Axis is going up and the Z-Axis is going into the screen. +// The solution is simple, we just flip the Y and Z axis, as we move coordinates +// from Panda to FMOD and back. +// What does did mean to average Panda user? Nothing, they shouldn't notice anyway. +// But if you decide to do any 3D audio work in here you have to keep it in mind. +// I told you, so you can't say I didn't. //////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float vy, float vz, float fx, float fy, float fz, float ux, float uy, float uz) { - audio_debug("FmodAudioManager::audio_3d_set_listener_attributes()"); +void FmodAudioManager::audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float vy, float vz, float fx, float fy, float fz, float ux, float uy, float uz) { + audio_debug("FmodAudioManager::audio_3d_set_listener_attributes()"); - _listener_pos[0] = px; _listener_pos[1] = py; _listener_pos[2] = pz; - _listener_vel[0] = vx; _listener_vel[1] = vy; _listener_vel[2] = vz; - _listener_forward[0] = fx; _listener_forward[1] = fy; _listener_forward[2] = fz; - _listener_up[0] = ux; _listener_up[1] = uy; _listener_up[2] = uz; + FMOD_RESULT result; + + _position.x = px; + _position.y = pz; + _position.z = py; - //convert panda coordinates to fmod coordinates - float fmod_pos [] = {_listener_pos[0], _listener_pos[2], _listener_pos[1]}; - float fmod_vel [] = {_listener_vel[0], _listener_vel[2], _listener_vel[1]}; - float fmod_forward [] = {_listener_forward[0], _listener_forward[2], _listener_forward[1]}; - float fmod_up [] = {_listener_up[0], _listener_up[2], _listener_up[1]}; + _velocity.x = vx; + _velocity.y = vz; + _velocity.z = vy; + + _forward.x = fx; + _forward.y = fz; + _forward.z = fy; + + _up.x = ux; + _up.y = uz; + _up.z = uy; + + result = _system->set3DListenerAttributes( 0, &_position, &_velocity, &_forward, &_up); + ERRCHECK( result ); - FSOUND_3D_Listener_SetAttributes(fmod_pos, fmod_vel, - fmod_forward[0], fmod_forward[1], fmod_forward[2], - fmod_up[0], fmod_up[1], fmod_up[2]); } //////////////////////////////////////////////////////////////////// @@ -661,27 +537,9 @@ audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float v // Access: Public // Description: Get position of the "ear" that picks up 3d sounds //////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -audio_3d_get_listener_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz, float *fx, float *fy, float *fz, float *ux, float *uy, float *uz) { - audio_error("audio3dGetListenerAttributes: currently unimplemented. Get the attributes of the attached object"); - //audio_debug("FmodAudioManager::audio_3d_get_listener_attributes()"); - // NOTE: swap the +y with the +z axis to convert between FMOD - // coordinates and Panda3D coordinates - //float temp; - //temp = py; - //py = pz; - //pz = temp; +void FmodAudioManager::audio_3d_get_listener_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz, float *fx, float *fy, float *fz, float *ux, float *uy, float *uz) { + audio_error("audio3dGetListenerAttributes: currently unimplemented. Get the attributes of the attached object"); - //temp = vy; - //vy = vz; - //vz = temp; - - //float pos [] = {px, py, pz}; - //float vel [] = {vx, vy, vz}; - //float front [] = {fx, fz, fy}; - //float up [] = {ux, uz, uy}; - - //FSOUND_3D_Listener_GetAttributes(pos, vel, &front[0], &front[1], &front[2], &up[0], &up[1], &up[2]); } @@ -691,17 +549,17 @@ audio_3d_get_listener_attributes(float *px, float *py, float *pz, float *vx, flo // Description: Set units per meter (Fmod uses meters internally for // its sound-spacialization calculations) //////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -audio_3d_set_distance_factor(float factor) { - audio_debug("FmodAudioManager::audio_3d_set_distance_factor(factor="<set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor); + ERRCHECK( result ); + + } //////////////////////////////////////////////////////////////////// @@ -710,10 +568,10 @@ audio_3d_set_distance_factor(float factor) { // Description: Gets units per meter (Fmod uses meters internally for // its sound-spacialization calculations) //////////////////////////////////////////////////////////////////// -float FmodAudioManager:: -audio_3d_get_distance_factor() const { - audio_debug("FmodAudioManager::audio_3d_get_distance_factor()"); - return _distance_factor; +float FmodAudioManager::audio_3d_get_distance_factor() const { + audio_debug("FmodAudioManager::audio_3d_get_distance_factor()"); + + return _distance_factor; } //////////////////////////////////////////////////////////////////// @@ -722,17 +580,16 @@ audio_3d_get_distance_factor() const { // Description: Exaggerates or diminishes the Doppler effect. // Defaults to 1.0 //////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -audio_3d_set_doppler_factor(float factor) { - audio_debug("FmodAudioManager::audio_3d_set_doppler_factor(factor="<set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor); + ERRCHECK( result ); + } //////////////////////////////////////////////////////////////////// @@ -740,10 +597,10 @@ audio_3d_set_doppler_factor(float factor) { // Access: Public // Description: //////////////////////////////////////////////////////////////////// -float FmodAudioManager:: -audio_3d_get_doppler_factor() const { - audio_debug("FmodAudioManager::audio_3d_get_doppler_factor()"); - return _doppler_factor; +float FmodAudioManager::audio_3d_get_doppler_factor() const { + audio_debug("FmodAudioManager::audio_3d_get_doppler_factor()"); + + return _doppler_factor; } //////////////////////////////////////////////////////////////////// @@ -752,17 +609,16 @@ audio_3d_get_doppler_factor() const { // Description: Control the effect distance has on audability. // Defaults to 1.0 //////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -audio_3d_set_drop_off_factor(float factor) { - audio_debug("FmodAudioManager::audio_3d_set_drop_off_factor("<set3DSettings( _doppler_factor, _distance_factor, _drop_off_factor); + ERRCHECK( result ); + } //////////////////////////////////////////////////////////////////// @@ -770,137 +626,89 @@ audio_3d_set_drop_off_factor(float factor) { // Access: Public // Description: //////////////////////////////////////////////////////////////////// -float FmodAudioManager:: -audio_3d_get_drop_off_factor() const { - audio_debug("FmodAudioManager::audio_3d_get_drop_off_factor()"); - return _drop_off_factor; +float FmodAudioManager::audio_3d_get_drop_off_factor() const { + audio_debug("FmodAudioManager::audio_3d_get_drop_off_factor()"); + + return _drop_off_factor; + +} + + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::set_concurrent_sound_limit +// Access: Public +// Description: NOT USED FOR FMOD-EX!!! +//////////////////////////////////////////////////////////////////// +void FmodAudioManager::set_concurrent_sound_limit(unsigned int limit) { } //////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::inc_refcount -// Access: Protected -// Description: Increments the refcount of a file's cache entry. +// Function: FmodAudioManager::get_concurrent_sound_limit +// Access: Public +// Description: NOT USED FOR FMOD-EX!!! //////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -inc_refcount(const string& file_name) { - Filename path = file_name; - SoundMap::iterator itor = _sounds.find(path); - if (itor == _sounds.end()) { - audio_debug("FmodAudioManager::inc_refcount: no such file "<refcount++; - entry->stale = false; // definitely not stale! - audio_debug("FmodAudioManager: "<refcount); +unsigned int FmodAudioManager::get_concurrent_sound_limit() const { + return 0; } //////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::dec_refcount -// Access: Protected -// Description: Decrements the refcount of a file's cache entry. If -// the refcount reaches zero and the entry is stale, it -// will be removed from the cache. -//////////////////////////////////////////////////////////////////// -void FmodAudioManager:: -dec_refcount(const string& file_name) { - Filename path = file_name; - SoundMap::iterator itor = _sounds.find(path); - if (itor != _sounds.end()) { - SoundCacheEntry *entry = &(*itor).second; - entry->refcount--; - audio_debug("FmodAudioManager: "<refcount); - if (entry->refcount == 0 && entry->stale) { - audio_debug("FmodAudioManager::dec_refcount: purging "<data; - - // Erase the sound from the LRU list as well. - nassertv(_lru.size()>0); - LRU::iterator lru_i=find(_lru.begin(), _lru.end(), itor->first); - nassertv(lru_i != _lru.end()); - _lru.erase(lru_i); - _sounds.erase(itor); - } - } else { - audio_debug("FmodAudioManager::dec_refcount: no such file "<exists(filename)) { - audio_error("File " << filename << " does not exist."); - return NULL; - } - - PT(VirtualFile) audioFileHandle = vfs->get_file(binary_filename); - audioFile = audioFileHandle->open_read_file(true); - - if (audioFile == (istream *)NULL) { - // Unable to open. - audio_error("Unable to read " << filename << "."); - return NULL; - } - - // Determine the file size. - size = audioFileHandle->get_file_size(audioFile); - - // Read the entire file into memory. - char *buffer = new char[size]; - if (buffer == NULL) { - audio_error("out-of-memory error while loading "<close_read_file(audioFile); - return NULL; - } - audioFile->read(buffer, size); - if (!(*audioFile)) { - audio_error("Read error while loading "<close_read_file(audioFile); - delete [] buffer; - return NULL; - } - - audioFileHandle->close_read_file(audioFile); - return buffer; } + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::uncache_sound +// Access: Public +// Description: NOT USED FOR FMOD-EX!!! +// Clears a sound out of the sound cache. +//////////////////////////////////////////////////////////////////// +void FmodAudioManager::uncache_sound(const string& file_name) { + audio_debug("FmodAudioManager::uncache_sound(\""< // Is fmod.h really a system file? I think maybe this should be "fmod.h". +//The Includes needed for FMOD +#include +#include + +class FmodAudioSound; +class FmodAudioDSP; + +//////////////////////////////////////////////////////////////////// +// OK I am not sure if there is the best place for this one, +// but it seems to work. IE, the FmodSound and FmodDSP classes can find it. +// All FMOD API calls return a success or failure error. +// [I am sure there is a name for this type of programming but I don't know it.] +// Anyway, by adding the line "notify-level-audio debug" to the config.prc file +// of Panda, of the config.in file of MAKEPANDA, you can see the Debugs printed out at the +// Python Prompt +///////////////////////////////////////////////////////////////////// +void ERRCHECK(FMOD_RESULT result); + class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager { - // All of these methods are stubbed out to some degree. - // If you're looking for a starting place for a new AudioManager, - // please consider looking at the milesAudioManager. - -public: - FmodAudioManager(); - virtual ~FmodAudioManager(); - - virtual bool is_valid(); - - virtual PT(AudioSound) get_sound(const string&, bool positional = false); - virtual void uncache_sound(const string&); - virtual void clear_cache(); - virtual void set_cache_limit(unsigned int count); - virtual unsigned int get_cache_limit() const; + // All of these methods are stubbed out to some degree. + // If you're looking for a starting place for a new AudioManager, + // please consider looking at the milesAudioManager. + friend class FmodAudioSound; + friend class FmodAudioDSP; - // Indicates that the given sound was the most recently used. - void most_recently_used(const string& path); + public: - // Uncaches the least recently used sound. - bool uncache_a_sound(); + //Constructor and Destructor + FmodAudioManager(); + virtual ~FmodAudioManager(); - virtual void set_volume(float); - virtual float get_volume() const; - - virtual void set_active(bool); - virtual bool get_active() const; + virtual bool is_valid(); + + 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 void set_concurrent_sound_limit(unsigned int limit = 0); - virtual unsigned int get_concurrent_sound_limit() const; + virtual int getSpeakerSetup(); + virtual void setSpeakerSetup(SPEAKERMODE_category cat); - virtual void reduce_sounds_playing_to(unsigned int count); + virtual void set_volume(float); + virtual float get_volume() const; + + virtual void set_active(bool); + virtual bool get_active() const; - //virtual void stop_a_sound(); - virtual void stop_all_sounds(); + virtual void stop_all_sounds(); - // Changes to the positions of 3D spacialized sounds and the listener - // are all made at once when this method is called. It should be put - // in the main program loop. - virtual void audio_3d_update(); + // Changes to the positions of 3D spacialized sounds and the listener + // are all made at once when this method is called. It should be put + // in the main program loop. + virtual void audio_3d_update(); - // This controls the "set of ears" that listens to 3D spacialized sound - // px, py, pz are position coordinates. Can be 0.0f to ignore. - // vx, vy, vz are a velocity vector in UNITS PER SECOND (default: meters). - // fx, fy and fz are the respective components of a unit forward-vector - // ux, uy and uz are the respective components of a unit up-vector - // These changes will NOT be invoked until audio_3d_update() is called. - virtual void audio_3d_set_listener_attributes(float px, float py, float pz, - float vx, float xy, float xz, - float fx, float fy, float fz, - float ux, float uy, float uz); - virtual void audio_3d_get_listener_attributes(float *px, float *py, float *pz, - float *vx, float *vy, float *vz, - float *fx, float *fy, float *fz, - float *ux, float *uy, float *uz); - - // Control the "relative distance factor" for 3D spacialized audio. Default is 1.0 - // Fmod uses meters internally, so give a float in Units-per meter - // Don't know what Miles uses. - virtual void audio_3d_set_distance_factor(float factor); - virtual float audio_3d_get_distance_factor() const; + // This controls the "set of ears" that listens to 3D spacialized sound + // px, py, pz are position coordinates. Can be 0.0f to ignore. + // vx, vy, vz are a velocity vector in UNITS PER SECOND (default: meters). + // fx, fy and fz are the respective components of a unit forward-vector + // ux, uy and uz are the respective components of a unit up-vector + // These changes will NOT be invoked until audio_3d_update() is called. + virtual void audio_3d_set_listener_attributes(float px, float py, float pz, + float vx, float xy, float xz, + float fx, float fy, float fz, + float ux, float uy, float uz); - // Control the presence of the Doppler effect. Default is 1.0 - // Exaggerated Doppler, use >1.0 - // Diminshed Doppler, use <1.0 - virtual void audio_3d_set_doppler_factor(float factor); - virtual float audio_3d_get_doppler_factor() const; + // REMOVE THIS ONE + virtual void audio_3d_get_listener_attributes(float *px, float *py, float *pz, + float *vx, float *vy, float *vz, + float *fx, float *fy, float *fz, + float *ux, float *uy, float *uz); + + // Control the "relative distance factor" for 3D spacialized audio. Default is 1.0 + // Fmod uses meters internally, so give a float in Units-per meter + // Don't know what Miles uses. + virtual void audio_3d_set_distance_factor(float factor); + virtual float audio_3d_get_distance_factor() const; - // Exaggerate or diminish the effect of distance on sound. Default is 1.0 - // Faster drop off, use >1.0 - // Slower drop off, use <1.0 - virtual void audio_3d_set_drop_off_factor(float factor); - virtual float audio_3d_get_drop_off_factor() const; + // Control the presence of the Doppler effect. Default is 1.0 + // Exaggerated Doppler, use >1.0 + // Diminshed Doppler, use <1.0 + virtual void audio_3d_set_doppler_factor(float factor); + virtual float audio_3d_get_doppler_factor() const; -protected: - // increment or decrement the refcount of the given file's cache entry. - // sounds can only be uncached when their refcounts are zero. - void inc_refcount(const string& file_name); - void dec_refcount(const string& file_name); -private: - typedef struct { - size_t size; // size of the data field, in bytes - unsigned int refcount; // how many AudioSound objects are referencing me? - bool stale; // can this entry be purged from the cache? - char *data; // the memory-mapped audio file. - } SoundCacheEntry; - typedef phash_map SoundMap; - SoundMap _sounds; + // Exaggerate or diminish the effect of distance on sound. Default is 1.0 + // Faster drop off, use >1.0 + // Slower drop off, use <1.0 + virtual void audio_3d_set_drop_off_factor(float factor); + virtual float audio_3d_get_drop_off_factor() const; - typedef phash_set AudioSet; - // The offspring of this manager: - AudioSet _soundsOnLoan; - unsigned int _concurrent_sound_limit; + //THESE ARE NOT USED ANYMORE. + //THEY ARE ONLY HERE BECAUSE THEY are still needed by Miles. + //THESE are stubs in FMOD-EX version + //////////////////////////////////////////////////////////////////// + virtual void set_concurrent_sound_limit(unsigned int limit = 0); + virtual unsigned int get_concurrent_sound_limit() const; + virtual void reduce_sounds_playing_to(unsigned int count); + virtual void uncache_sound(const string&); + virtual void clear_cache(); + virtual void set_cache_limit(unsigned int count); + virtual unsigned int get_cache_limit() const; + //////////////////////////////////////////////////////////////////// - typedef phash_set SoundsPlaying; - // The sounds from this manager that are currently playing - SoundsPlaying _sounds_playing; + protected: - // The Least Recently Used mechanism: - typedef pdeque LRU; - LRU _lru; + // This is the main FMOD system varible. Without it you got nothing. + FMOD::System *_system; - // RobCode - // List of supported sound formats - typedef pvector SupportedTypes; - SupportedTypes _supported_types; + private: - void release_sound(FmodAudioSound *audioSound); + // This varible is something to receive the FMOD_RESULTs which we use to check + // FMOD's State + FMOD_VECTOR _position; + FMOD_VECTOR _velocity; + FMOD_VECTOR _forward; + FMOD_VECTOR _up; - int _cache_limit; - static int _active_managers; - bool _is_valid; - bool _active; - float _volume; - float _listener_pos [3]; - float _listener_vel [3]; - float _listener_forward [3]; - float _listener_up [3]; - float _distance_factor; - float _doppler_factor; - float _drop_off_factor; - - char* load(const Filename& filename, size_t &size) const; - friend class FmodAudioSound; + bool _is_valid; + bool _active; + + float _distance_factor; + float _doppler_factor; + float _drop_off_factor; + + //The Data Structure that holds all the sounds. + //BTW. Notice that this IS NOT A PT Structure. + //It probably should never bee either. + //We tried it as a PT, and you run into a problem with + //PANDA's garbage collection system, when you finally get around + //to destroying the sounds. + //So you are probably wondering why we even need a set like the one below by now. + //Mainly becuase we need something for the 'stop_all_sounds()' function. + //Which does just take it stop all the sounds at once [and believe it is needed at times.] + typedef pset SoundSet; + SoundSet _all_sounds; + + //The Data Structure that holds all the DSPs. + typedef pset DSPSet; + DSPSet _system_dsp; + + friend class FmodAudioSound; + + + //////////////////////////////////////////////////////////// + //These are needed for Panda's Pointer System. DO NOT ERASE! + //////////////////////////////////////////////////////////// + + public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + AudioManager::init_type(); + register_type(_type_handle, "FmodAudioManager", AudioManager::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() { + init_type(); + return get_class_type(); + } + + private: + static TypeHandle _type_handle; + + //////////////////////////////////////////////////////////// + //DONE + //////////////////////////////////////////////////////////// + }; EXPCL_FMOD_AUDIO PT(AudioManager) Create_AudioManager(); diff --git a/panda/src/audiotraits/fmodAudioSound.cxx b/panda/src/audiotraits/fmodAudioSound.cxx index d8b3d433cd..7000ef7c80 100644 --- a/panda/src/audiotraits/fmodAudioSound.cxx +++ b/panda/src/audiotraits/fmodAudioSound.cxx @@ -2,6 +2,8 @@ // Created by: cort (January 22, 2003) // Extended by: ben (October 22, 2003) // Prior system by: cary +// Rewrite [for new Version of FMOD-EX] by: Stan Rosenbaum "Staque" - Spring 2006 +// // //////////////////////////////////////////////////////////////////// // @@ -19,176 +21,311 @@ //////////////////////////////////////////////////////////////////// #include "pandabase.h" +#include "dcast.h" + #ifdef HAVE_FMOD //[ -#include "throw_event.h" +//Panda Headers +#include "config_audio.h" #include "fmodAudioSound.h" -#include "fmodAudioManager.h" +#include "fmodAudioDSP.h" -#include +TypeHandle FmodAudioSound::_type_handle; -#ifndef NDEBUG //[ - #define fmod_audio_debug(x) \ - audio_debug("FmodAudioSound "<<" \""<finished(); - return true; //make signed char happy -} - -//////////////////////////////////////////////////////////////////// -// Function: panda_Fmod_finished_callback -// Access: file scope -// Description: Sets up a finish callback for a sound. -//////////////////////////////////////////////////////////////////// -void -panda_Fmod_finished_callback( FSOUND_STREAM *audio, FmodAudioSound* sound ) { - if ( !audio || !sound ) {//sanity test - return; - } - audio_debug("panda_Fmod_finished_callback(audio="<<((void*)audio) - <<", sound="<<((void*)sound)<<")"); - FSOUND_STREAMCALLBACK callback = pandaFmodFinishedCallback_Stream; - //actual stream, callback func, pointer to FmodAudioSound - FSOUND_Stream_SetEndCallback( audio, callback, sound ); -} //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::FmodAudioSound -// Access: -// Description: constructor +// Access: public +// Description: CONSTRUCTOR +// All sound will DEFAULT load as a 2D sound unless +// otherwise specified. //////////////////////////////////////////////////////////////////// -FmodAudioSound:: -FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data, - string file_name, float length) - : _manager(manager), _audio(audio_data), _file_name(file_name), - _volume(1.0f), _balance(0), _loop_count(1), _length(length), - _active(true), _paused(false), _bExclusive(false),_channel(-1) { - _pos[0] = 0.0f; _pos[1] = 0.0f; _pos[2] = 0.0f; - _vel[0] = 0.0f; _vel[1] = 0.0f; _vel[2] = 0.0f; - _min_dist = 1.0f; _max_dist = 1000000000.0f; - nassertv(!file_name.empty()); - nassertv(audio_data != NULL); +FmodAudioSound::FmodAudioSound(AudioManager *manager, string file_name, bool positional) { + audio_debug("FmodAudioSound::FmodAudioSound() Creating new sound, filename: " << file_name ); + + //Local Variables that are needed. + FMOD_RESULT result; + + //Inits 3D Attributes + _location.x = 0; + _location.y = 0; + _location.z = 0; + + _velocity.x = 0; + _velocity.y = 0; + _velocity.z = 0; + + //Play Rate Variable + _playrate = 1; + + // These set the Speaker Levels to a default if you are using a MultiChannel Setup. + _frontleft = 1; + _frontright = 1; + _center = 1; + _sub = 1; + _backleft = 1; + _backright = 1; + _sideleft = 1; + _sideright = 1; + + //Assign the values we need + DCAST_INTO_V(_manager, manager); + + //_channel = 0; + _file_name = file_name; + + //Get the Speaker Mode [Important for later on.] + result = _manager->_system->getSpeakerMode( &_speakermode ); + ERRCHECK(result); + + if (positional == true) { + + result = _manager->_system->createSound( file_name.c_str(), FMOD_SOFTWARE | FMOD_3D , 0, &_sound); + ERRCHECK(result); + + //This is just to collect the defaults of the sound, so we don't + //Have to query FMOD everytime for the info. + //It is also important we get the '_sampleFrequency' variable here, for the + //'set_play_rate()' and 'get_play_rate()' methods later; + + result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority); + ERRCHECK(result); + + audio_debug("Sound loaded as 3D"); + + } else { + + result = _manager->_system->createSound( file_name.c_str(), FMOD_SOFTWARE | FMOD_2D , 0, &_sound); + ERRCHECK(result); + + //This is just to collect the defaults of the sound, so we don't + //Have to query FMOD everytime for the info. + //It is also important we get the '_sampleFrequency' variable here, for the + //'set_play_rate()' and 'get_play_rate()' methods later; + + result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority); + ERRCHECK(result); + + audio_debug("Sound loaded as 2D"); + + } - fmod_audio_debug("FmodAudioSound(manager="<<(void*)&manager - <<", file_name="<stop(); - _manager->release_sound(this); +FmodAudioSound::~FmodAudioSound() { + + audio_debug("FmodAudioSound::~FmodAudioSound() Closing this Sound Instance Down."); + + FMOD_RESULT result; + + //Remove me from table of all sounds. + _manager->_all_sounds.erase(this); + + //Release DSPs First + _sound_dsp.clear(); + + //The Release Sound + result = _sound->release(); + ERRCHECK(result); + + audio_debug("FmodAudioSound::~FmodAudioSound() FMOD Sound Released and Closed."); + } + //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound:: play // Access: public -// Description: Play a sound +// Description: Plays a sound. +// OK when you play a Sound a couple of things are going +// to happen. +// First Panda is going to check if the sound is in a pause +// State because of if a 'set_time()' has been called on the sound. +// Second, remember when I said channels don't exist unless a sound, +// is playing on them? Well they don't and therefore any associated +// DSP, looping, playback rate, pan, volume, or 3D information associated with +// that sound is not going to be known by that channel either. +// So all we do, is load a sound on a channel PAUSED. +// While the sound is paused, it sets up all the sound attributes, and +// then plays the sound. This all happens really fast, so you should +// notice a hit. +// And yes this is the FMOD way of doing things. +// +// The biggest problem with this comes when you are 'looping' sounds. +// In the 'prepare2DSound()' and prepare3DSound' [private methods +// which set up their respected type of sounds], I had to impliment the +// 'FMOD_CHANNEL_REUSE' flag. +// Remember back in the header file, where I said there is only one dedicated, +// Channel for each sound, where there is a reason for that. +// If you were to use 'FMOD_CHANNEL_FREE' each time you played a sound, +// FMOD would grab the first available channel and play the sound on that. +// This is bad for Panda because the FmodAudioSound class is only set up to +// remember only channel at a time. If we play a sound that is set to loop, and +// then trigger that sound to loop again, the reference to the Channel Object for a particular +// sound is replaced with the new, instance of the loop. Thus the previous sound keeps playing +// forever because we have lost the reference to it. +// But using the 'FMOD_CHANNEL_REUSE' flag, we avoid this problem, because the new call to play +// the looping sound will, play the sound on the previous allocated channel. +// The only to downside to this, is that playing a looping sound a second time, will cause the +// Previous instance to be cut off. +// +// Honestly, it should be easy to create a work around for this. So you could +// use the 'FMOD_CHANNEL_FREE' which will prevent the cutoff program, by creating +// a set, that keeps track of channels playing the same looping sound, when the sound is looping +// [or is really long, another possible scenerio for this problem]. +// +// But honestly the cutoff shouldn't be a big problem, in most cases. +// I just wanted to explain my reasoning here. +// //////////////////////////////////////////////////////////////////// -void FmodAudioSound:: -play() { - if (!_active) { - return; - } - // If the sound is already playing, stop it. - if (this->status() == AudioSound::PLAYING) { - this->stop(); - } -if (_bExclusive) { - // stop another sound that parent mgr is playing - _manager->stop_all_sounds(); - } +void FmodAudioSound::play() { + + audio_debug("FmodAudioSound::play() Going to play a sound." ); - panda_Fmod_finished_callback( _audio, this ); - // Play the stream, but start it paused so we can set the volume and - // panning first. - assert(_audio != NULL); - _channel = FSOUND_Stream_PlayEx(FSOUND_FREE, _audio, NULL, 1); - if (_channel == -1) { - fmod_audio_debug("play() failed"); - return; - } - - // Set volume. - unsigned char new_volume = (unsigned char)(_volume*255.0f); - FSOUND_SetVolume(_channel, new_volume); - - // Set panning. - unsigned char new_balance = (unsigned char)( (_balance+1.0f)*0.5f*255.0f); - FSOUND_SetPan(_channel, new_balance); + FMOD_RESULT result; + bool paused = 0; - // Set 3d attributes, if needed - if (FSOUND_Stream_GetMode(_audio) & FSOUND_HW3D) { - // Convert from Panda coordinates to Fmod coordinates - float fmod_pos [] = {_pos[0], _pos[2], _pos[1]}; - float fmod_vel [] = {_vel[0], _vel[2], _vel[1]}; - if(!FSOUND_3D_SetAttributes(_channel, fmod_pos, fmod_vel)) { - audio_error("Unable to set 3d attributes for "<<_file_name<<"!"); - } + result = _channel->getPaused(&paused); + ERRCHECK(result); - if(!FSOUND_3D_SetMinMaxDistance(_channel, _min_dist, _max_dist)) { - //Seems like the return value is documented incorrectly, so this error gets - //needlessly spammed - //audio_error("Unable to set 3d min/max distance for "<<_file_name<<"!"); - } - } - // Set looping -- unimplemented - - // Unpause and set status to playing - FSOUND_SetPaused(_channel, 0); - // Delay until the channel is actually playing. This shouldn't - // result in a noticeable delay, and allows you to immediately test - // the status of the sound after initiating playback. - while (!FSOUND_IsPlaying(_channel)) { - // intentinaly empty loop. - } + if ( paused ) { + + set_volume_on_channel(); + set_play_rate_on_channel(); + set_speaker_mix_or_balance_on_channel(); + add_dsp_on_channel(); + + result = _channel->setPaused(false); + ERRCHECK(result); + + } else { + + prepareSound(); + + set_volume_on_channel(); + set_play_rate_on_channel(); + set_speaker_mix_or_balance_on_channel();; + add_dsp_on_channel(); + + result = _channel->setPaused(false); + ERRCHECK(result); + + } + + audio_debug("FmodAudioSound::play() Sound should be playing (or played if it is really short)." ); + } + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::prepareSound +// Access: Private +// Description: Prepares a sound [GENERAL] +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::prepareSound() { + + audio_debug("FmodAudioSound::prepareSound()" ); + + FMOD_RESULT result; + bool paused = 0; + FMOD_MODE soundMode; + + audio_debug("FmodAudioSound::play() Going to perpare a sound." ); + + result = _sound->getMode(&soundMode); + ERRCHECK(result); + + if ( ( soundMode & FMOD_3D ) > 0 ) { + + prepare3DSound(); + + } else { + + prepare2DSound(); + + } + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::prepare2DSound +// Access: Private +// Description: Prepares a 2D sound. +// We need seperate 3D and 2D play commands, because of +// the way FMOD sets the 3D Attributes to the 'channel' a +// sound is playing on. +// Since a 'channel' is initialize when a sound is set to +// play to one, and then subsiquenctly destroyed once the +// sound is finished playing. +// +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::prepare2DSound() { + + audio_debug("FmodAudioSound::prepare2DSound()" ); + + FMOD_RESULT result; + + result = _manager->_system->playSound(FMOD_CHANNEL_REUSE, _sound, true, &_channel); + ERRCHECK(result); + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::prepare3DSound +// Access: Private +// Description: Prepares a 3D sound +// We need seperate 3D and 2D play commands, because of +// the way FMOD sets the 3D Attributes to the 'channel' a +// sound is playing on. +// Since a 'channel' is initialize when a sound is set to +// play to one, and then subsiquenctly destroyed once the +// sound is finished playing. +// +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::prepare3DSound() { + + audio_debug("FmodAudioSound::prepare2DSound()" ); + + FMOD_RESULT result; + + result = _manager->_system->playSound(FMOD_CHANNEL_REUSE, _sound, true, &_channel); + ERRCHECK(result); + + result = _channel->set3DAttributes( &_location, &_velocity ); + ERRCHECK(result); + +} + + + //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::stop // Access: public // Description: Stop a sound //////////////////////////////////////////////////////////////////// void FmodAudioSound::stop() { - if(!FSOUND_Stream_Stop(_audio)) { - audio_error("Stop failed!"); - } - _channel = -1; + + audio_debug("FmodAudioSound::stop() Going to stop a sound." ); + + //LOCALS + FMOD_RESULT result; + + result = _channel->stop(); + ERRCHECK(result); + + audio_debug("FmodAudioSound::stop() Sound should be stopped."); + } -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::finished -// Access: public -// Description: called by finishedCallback function when a sound -// terminates (but doesn't loop). -//////////////////////////////////////////////////////////////////// -void FmodAudioSound::finished() { - fmod_audio_debug("finished()"); - stop(); - if (!_finished_event.empty()) { - throw_event(_finished_event); - } -} + //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::set_loop @@ -196,20 +333,22 @@ void FmodAudioSound::finished() { // Description: Turns looping on and off //////////////////////////////////////////////////////////////////// void FmodAudioSound::set_loop(bool loop) { - fmod_audio_debug("set_loop() set to "<setMode(FMOD_LOOP_NORMAL); + ERRCHECK(result); + audio_debug("This sound is set to loop." ); + + } else { + result = _sound->setMode(FMOD_LOOP_OFF); + ERRCHECK(result); + audio_debug("FmodAudioSound::set_loop() This sound is set to one-shot." ); + } + } //////////////////////////////////////////////////////////////////// @@ -218,42 +357,82 @@ void FmodAudioSound::set_loop(bool loop) { // Description: Returns whether looping is on or off //////////////////////////////////////////////////////////////////// bool FmodAudioSound::get_loop() const { - // 0 means loop forever, - // >1 means loop that many times - // So _loop_count != 1 means we're looping - fmod_audio_debug("get_loop() returning "<<(_loop_count != 1)); - return (_loop_count != 1); + + audio_debug( "FmodAudioSound::get_loop() Retreiving a sound's loop state." ); + + // 0 means loop forever, + // >1 means loop that many times + // So _loop_count != 1 means we're looping + + FMOD_RESULT result; + FMOD_MODE loopMode; + bool loopState; + + result = _sound->getMode( &loopMode ); + ERRCHECK(result); + + if ( (loopMode & FMOD_LOOP_NORMAL) != 0 ) { + loopState = true; + } else { + loopState = false; + } + + return (loopState); } //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::set_loop_count // Access: public // Description: +// Panda uses 0 to mean loop forever. +// Fmod uses negative numbers to mean loop forever. +// (0 means don't loop, 1 means play twice, etc. +// We must convert! //////////////////////////////////////////////////////////////////// void FmodAudioSound::set_loop_count(unsigned long loop_count) { - // Panda uses 0 to mean loop forever. - // Fmod uses negative numbers to mean loop forever. - // (0 means don't loop, 1 means play twice, etc.) - // We must convert! - - fmod_audio_debug("set_loop_count() set to "<setLoopCount( -1 ); + ERRCHECK(result); + } else { + result = _sound->setLoopCount( numberOfLoops ); + ERRCHECK(result); + } + + audio_debug("FmodAudioSound::set_loop_count() Sound's loop count should be set to: " << loop_count); + } //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::get_loop_count // Access: public -// Description: +// Description: Return how many times a sound will loop. //////////////////////////////////////////////////////////////////// unsigned long FmodAudioSound::get_loop_count() const { - fmod_audio_debug("get_loop_count() returning "<<_loop_count); - return _loop_count; + + audio_debug("FmodAudioSound::get_loop_count() Getting the sound's loop count. "); + + FMOD_RESULT result; + int loop_count; + unsigned long returnedNumber; + + result = _sound->getLoopCount( &loop_count ); + ERRCHECK(result); + + audio_debug("FmodAudioSound::get_loop_count() returning "<< loop_count); + + returnedNumber = (unsigned long) loop_count; + + return loop_count; } //////////////////////////////////////////////////////////////////// @@ -262,17 +441,21 @@ unsigned long FmodAudioSound::get_loop_count() const { // Description: Sets the play position within the sound //////////////////////////////////////////////////////////////////// void FmodAudioSound::set_time(float start_time) { - if (start_time < 0.0f) { - fmod_audio_debug("set_time(): param "< _length) { - fmod_audio_debug("set_time(): param "<setPosition( startTime , FMOD_TIMEUNIT_MS ); + ERRCHECK(result); + } //////////////////////////////////////////////////////////////////// @@ -281,145 +464,202 @@ void FmodAudioSound::set_time(float start_time) { // Description: Gets the play position within the sound //////////////////////////////////////////////////////////////////// float FmodAudioSound::get_time() const { - // A bug in stream WAV files causes FSOUND_Stream_GetTime() to - // divide-by-zero somewhere if the stream isn't currently playing. - // In this case, we should just return zero. - if (!FSOUND_IsPlaying(_channel)) { - return 0.0f; - } + + audio_debug("FmodAudioSound::get_time() Going to get a sound's position" ); + + FMOD_RESULT result; + unsigned int current_time; + + result = _channel->getPosition( ¤t_time , FMOD_TIMEUNIT_MS ); + ERRCHECK(result); + + current_time = current_time / 1000; + + return current_time; - // FMOD measures time in milliseconds, so scale down by 1000. - float current_time = FSOUND_Stream_GetTime(_audio) * 0.001f; - //fmod_audio_debug("get_time() returning "< 1.0f) { - fmod_audio_debug("set_volume(): param "<setVolume( _volume ); + ERRCHECK(result); + + audio_debug("FmodAudioSound::set_volume() Setting volume to " << vol); + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_volume_on_channel() +// Access: Private +// Description: Set the volume on a prepared Sound channel. +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_volume_on_channel() { + + audio_debug("FmodAudioSound::set_volume() Going to set a sounds volume." ); + + FMOD_RESULT result; + + result = _channel->setVolume( _volume ); + ERRCHECK(result); + + audio_debug("FmodAudioSound::set_volume() Setting volume to " << _volume ); + } //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::get_volume // Access: public -// Description: +// Description: Gets the current volume of a sound. 1 is Max. O is Min. //////////////////////////////////////////////////////////////////// float FmodAudioSound::get_volume() const { - fmod_audio_debug("get_volume() returning "<<_volume); - return _volume; + + audio_debug("FmodAudioSound::get_volume() Going to get a sound's volume." ); + + return _volume; } //////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::set_balance +// Function: FmodAudioSound::set_balance(float bal) // Access: public // Description: -1.0 to 1.0 scale //////////////////////////////////////////////////////////////////// void FmodAudioSound::set_balance(float bal) { - if (bal < -1.0f) { - fmod_audio_debug("set_balance(): param "< 1.0f) { - fmod_audio_debug("set_balance(): param "<setDefaults( _sampleFrequency, _volume , _balance, _priority); + ERRCHECK(result); + + result = _channel->setPan( _balance ); + ERRCHECK(result); + + audio_debug("FmodAudioSound::set_balance() Setting Pan to " << bal); + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_balance_on_channel() +// Access: public +// Description: -1.0 to 1.0 scale Set the pan on a prepared Sound channel. +// -1 should be all the way left. +// 1 is all the way to the right. +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_balance_on_channel() { + + audio_debug("FmodAudioSound::set_balance() Going to set a sound's balance to " << _balance ); + + FMOD_RESULT result; + + result = _channel->setPan( _balance ); + ERRCHECK(result); + + audio_debug("FmodAudioSound::set_balance() Setting Pan to " << _balance); + } //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::get_balance // Access: public -// Description: +// Description: -1.0 to 1.0 scale +// -1 should be all the way left. +// 1 is all the way to the right. //////////////////////////////////////////////////////////////////// float FmodAudioSound::get_balance() const { - fmod_audio_debug("get_balance() returning "<<_balance); - return _balance; + + audio_debug("FmodAudioSound::get_balance() Going to get a sound's balance." ); + + return _balance; } //////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::set_play_rate +// Function: FmodAudioSound::set_play_rate(float rate) // Access: public -// Description: NOT IMPLEMENTED! DO NOT USE! +// Description: Sets the speed at which a sound plays back. +// The rate is a multiple of the sound, normal playback speed. +// IE 2 would play back 2 times fast, 3 would play 3 times, and so on. +// This can also be set to a negative number so a sound plays backwards. +// But rememeber if the sound is not playing, you must set the +// sound's time to its end to hear a song play backwards. //////////////////////////////////////////////////////////////////// void FmodAudioSound::set_play_rate(float rate) { - audio_error("set_play_rate not implemented under fmod"); + audio_debug("FmodAudioSound::set_play_rate() Going to set a sound's play rate to " << rate); + + FMOD_RESULT result; + float frequencyToSetChannelTo; + + _playrate = rate; + + if (rate == 1) { + result = _channel->setFrequency( _sampleFrequency ); + ERRCHECK(result); + } else { + frequencyToSetChannelTo = _sampleFrequency * rate ; + + result = _channel->setFrequency( frequencyToSetChannelTo ); + ERRCHECK(result); + + } + + audio_debug("FmodAudioSound::set_play_rate() Sound's balance set to " << rate); + } +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_play_rate_on_channel() +// Access: public +// Description: Set the play rate on a prepared Sound channel. +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_play_rate_on_channel() { + audio_debug("FmodAudioSound::set_play_rate() Going to set a sound's balance to " << _playrate); + + FMOD_RESULT result; + float frequencyToSetChannelTo; + + if ( _playrate == 1) { + result = _channel->setFrequency( _sampleFrequency ); + ERRCHECK(result); + } else { + frequencyToSetChannelTo = _sampleFrequency * _playrate ; + + result = _channel->setFrequency( frequencyToSetChannelTo ); + ERRCHECK(result); + + } + + audio_debug("FmodAudioSound::set_play_rate() Sound's balance set to " << _playrate); + +} + + + //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::get_play_rate // Access: public -// Description: NOT IMPLEMENTED! DO NOT USE! +// Description: //////////////////////////////////////////////////////////////////// float FmodAudioSound::get_play_rate() const { - return 1.0; + + audio_debug("FmodAudioSound::set_play_rate() Going to get a sound's balance."); + + return _playrate; } -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::set_active -// Access: public -// Description: -//////////////////////////////////////////////////////////////////// -void FmodAudioSound::set_active(bool active) { - fmod_audio_debug("set_active(active="<stop(); - } - _active = active; -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::get_active -// Access: public -// Description: -//////////////////////////////////////////////////////////////////// -bool FmodAudioSound::get_active() const { - fmod_audio_debug("get_active() returning "<<_active); - return _active; -} - -//////////////////////////////////////////////////////////////////// -// Function: FmodAudioSound::set_finished_event -// Access: public -// Description: Assign a string for the finished event to be referenced -// by in python by an accept method -//////////////////////////////////////////////////////////////////// -void FmodAudioSound:: -set_finished_event(const string& event) { - fmod_audio_debug("set_finished_event(event="<getLength( &length, FMOD_TIMEUNIT_MS ); + ERRCHECK(result); + + length = length / 1000; + + return length; } //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::set_3d_attributes // Access: public // Description: Set position and velocity of this sound +// NOW LISTEN UP!!! THIS IS IMPORTANT! +// Both Panda3D and FMOD use a left handed coordinate system. +// But there is a major difference! +// In Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up. +// In FMOD the Y-Axis is going up and the Z-Axis is going into the screen. +// The solution is simple, we just flip the Y and Z axis, as we move coordinates +// from Panda to FMOD and back. +// What does did mean to average Panda user? Nothing, they shouldn't notice anyway. +// But if you decide to do any 3D audio work in here you have to keep it in mind. +// I told you, so you can't say I didn't. //////////////////////////////////////////////////////////////////// -void FmodAudioSound:: -set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) { - fmod_audio_debug("Set 3d position and velocity (px="<set3DAttributes( &_location, &_velocity ); + ERRCHECK(result); + - if (FSOUND_Stream_GetMode(_audio) & FSOUND_HW3D) { - // Convert from Panda coordinates to Fmod coordinates - float fmod_pos [] = {_pos[0], _pos[2], _pos[1]}; - float fmod_vel [] = {_vel[0], _vel[2], _vel[1]}; - FSOUND_3D_SetAttributes(_channel, fmod_pos, fmod_vel); - } } //////////////////////////////////////////////////////////////////// // Function: FmodAudioSound::get_3d_attributes // Access: public // Description: Get position and velocity of this sound +// Currently unimplemented. Get the attributes of the attached object. //////////////////////////////////////////////////////////////////// -void FmodAudioSound:: -get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz) { - audio_error("get3dAttributes: Currently unimplemented. Get the attributes of the attached object."); - // NOTE: swap the +y with the +z axis to convert between FMOD - // coordinates and Panda3D coordinates - //float temp; - //temp = py; - //py = pz; - //pz = temp; +void FmodAudioSound::get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz) { + audio_error("get3dAttributes: Currently unimplemented. Get the attributes of the attached object."); - //temp = vy; - //vy = vz; - //vz = temp; - - //float pos [] = {px, py, pz}; - //float vel [] = {vx, vy, vz}; - //FSOUND_3D_GetAttributes(_channel, pos, vel); } //////////////////////////////////////////////////////////////////// @@ -489,12 +746,17 @@ get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float * // affects the rate it falls off. //////////////////////////////////////////////////////////////////// void FmodAudioSound::set_3d_min_distance(float dist) { - fmod_audio_debug("Set 3d min distance (min="<set3DMinMaxDistance( dist, _max_dist ); + ERRCHECK(result); + - if (FSOUND_Stream_GetMode(_audio) & FSOUND_HW3D) { - FSOUND_3D_SetMinMaxDistance(_channel, _min_dist,_max_dist); - } } //////////////////////////////////////////////////////////////////// @@ -503,7 +765,10 @@ void FmodAudioSound::set_3d_min_distance(float dist) { // Description: Get the distance that this sound begins to fall off //////////////////////////////////////////////////////////////////// float FmodAudioSound::get_3d_min_distance() const { - return _min_dist; + + audio_debug("FmodAudioSound::get_3d_min_distance() "); + + return _min_dist; } //////////////////////////////////////////////////////////////////// @@ -512,12 +777,16 @@ float FmodAudioSound::get_3d_min_distance() const { // Description: Set the distance that this sound stops falling off //////////////////////////////////////////////////////////////////// void FmodAudioSound::set_3d_max_distance(float dist) { - fmod_audio_debug("Set 3d max distance (max="<set3DMinMaxDistance( _min_dist, dist ); + ERRCHECK(result); + } //////////////////////////////////////////////////////////////////// @@ -526,7 +795,338 @@ void FmodAudioSound::set_3d_max_distance(float dist) { // Description: Get the distance that this sound stops falling off //////////////////////////////////////////////////////////////////// float FmodAudioSound::get_3d_max_distance() const { - return _max_dist; + + audio_debug("FmodAudioSound::get_3d_max_distance() "); + + 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) { + // intentionally blank + + audio_debug("FmodAudioManager()::add_dsp"); + + 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 ); + ERRCHECK(result); + if ( playingState ) { + result = _channel->addDSP( fdsp->_dsp ); + ERRCHECK( 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() { + // intentionally blank + + audio_debug("FmodAudioManager()::add_dsp_on_channel"); + + FMOD_RESULT result; + + for (DSPSet::iterator i = _sound_dsp.begin(); i != _sound_dsp.end(); ++i) { + + result = _channel->addDSP( (*i)->_dsp ); + ERRCHECK( 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) { +// intentionally blank + + audio_debug("FmodAudioManager()::remove_dsp()"); + + FMOD_RESULT result; + + FmodAudioDSP *fdsp; + DCAST_INTO_R(fdsp, x, false); + + if ( fdsp->get_in_chain() ) { + + result = fdsp->_dsp->remove(); + ERRCHECK( 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 +// Description: In Multichannel Speaker systems [like Surround]. +// Can pass in the ID of a specific speaker and get itself Volume level. +// Currenly that is set to the Following: +// 1 = Front Left +// 2 = Front Right +// 3 = Center +// 4 = Subwoofer +// 5 = Back Left +// 6 = Back Right +// 7 = Side Left +// 8 = Side Right +// Speakers which don't exist in some systems will simply be ignored. +// IE So a quadsystem would only return values on 1,2,5,6. +// +// But I haven't been able to test this yet, so I am jsut letting you know. +// +// BTW This will also work in Stereo speaker systems, but since +// PANDA/FMOD has a balance [pan] function what is the point? +//////////////////////////////////////////////////////////////////// +float FmodAudioSound::get_speaker_mix(int speaker) { + // intentionally blank + + audio_debug("FmodAudioSound::getSpeakerMix()"); + + FMOD_RESULT result; + float frontleft; + float frontright; + float center; + float sub; + float backleft; + float backright; + float sideleft; + float sideright; + + float returnValue; + + switch(speaker) { + + case 1: + result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); + ERRCHECK(result); + returnValue = frontleft; + break; + case 2: + result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); + ERRCHECK(result); + returnValue = frontright; + break; + case 3: + result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); + ERRCHECK(result); + returnValue = center; + break; + case 4: + result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); + ERRCHECK(result); + returnValue = sub; + break; + case 5: + result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); + ERRCHECK(result); + returnValue = backleft; + break; + case 6: + result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); + ERRCHECK(result); + returnValue = backright; + break; + case 7: + result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); + ERRCHECK(result); + returnValue = sideleft; + break; + case 8: + result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); + ERRCHECK(result); + returnValue = sideright; + break; + default: + cerr << "You specified a speaker which doesn't exist."; + + } + + + return returnValue; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_speaker_mix +// Access: Published +// Description: This sets the speaker mix for Surround Sound sytems. +// It required 8 parameters which match up to the following: +// 1 = Front Left +// 2 = Front Right +// 3 = Center +// 4 = Subwoofer +// 5 = Back Left +// 6 = Back Right +// 7 = Side Left +// 8 = Side Right +// Speakers which don't exist in some systems will simply be ignored. +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float sideright) { + // intentionally blank + + audio_debug("FmodAudioSound::setSpeakerMix()"); + + FMOD_RESULT result; + + _frontleft = frontleft; + _frontright = frontright; + _center = center; + _sub = sub; + _backleft = backleft; + _backright = backright; + _sideleft = sideleft; + _sideright = sideright; + + result = _channel->setSpeakerMix( _frontleft, _frontright, _center, _sub, _backleft, _backright, _sideleft, _sideright ); + ERRCHECK(result);; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_speaker_mix_on_channel +// Access: Published +// Description: Set the Speaker Mix for a sound on a prepared Sound channel. +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_speaker_mix_on_channel() { + // intentionally blank + + audio_debug("FmodAudioSound::setSpeakerMix()"); + + FMOD_RESULT result; + + result = _channel->setSpeakerMix( _frontleft, _frontright, _center, _sub, _backleft, _backright, _sideleft, _sideright ); + ERRCHECK(result);; +} + + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_speaker_mix_or_balance_on_channel +// Access: Private +// Description: This is simply a safety catch. +// If you are using a Stero speaker setup Panda will only pay attention +// to 'set_balance()' command when setting speaker balances. +// Other wise it will use 'set_speaker_mix'. +// I put this in, because other wise you end up with a sitation, +// where 'set_speaker_mix()' or 'set_balace()' will override any +// previous speaker balance setups. It all depends on which was called last. +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_speaker_mix_or_balance_on_channel() { + // intentionally blank + + audio_debug("FmodAudioSound::set_speaker_mix_or_balance_on_channel()"); + + FMOD_RESULT result; + FMOD_MODE soundMode; + + + result = _sound->getMode(&soundMode); + ERRCHECK(result); + + + if ( _speakermode == FMOD_SPEAKERMODE_STEREO ) { + + //FMOD Returns an error is you try and pan a sound in 3D Audio. + //Which makes sense. + //It is nothing serious, but might as well avoid it while we can. + if ( !( ( soundMode & FMOD_3D ) > 0 ) ) { + set_balance_on_channel(); + } + + } else { + + set_speaker_mix_on_channel(); + + } + +} + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::get_priority +// Access: Published +// Description: Sets the priority of a sound. +// This is what FMOD uses to determine is a sound will +// play if all the other real channels have been used up. +//////////////////////////////////////////////////////////////////// +int FmodAudioSound::get_priority() { + audio_debug("FmodAudioSound::get_priority()"); + return _priority; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_priority(int priority) +// Access: Published +// Description: Sets the Sound Priority [Whether is will be played +// over other sound when real audio channels become short. +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_priority(int priority) { + // intentionally blank + + audio_debug("FmodAudioSound::set_priority()"); + + FMOD_RESULT result; + + _priority = priority; + + result = _sound->setDefaults( _sampleFrequency, _volume , _balance, _priority); + ERRCHECK(result); } //////////////////////////////////////////////////////////////////// @@ -535,24 +1135,104 @@ float FmodAudioSound::get_3d_max_distance() const { // Description: Get status of the sound. //////////////////////////////////////////////////////////////////// AudioSound::SoundStatus FmodAudioSound::status() const { - // If the stream's channel isn't playing anything, then the stream - // definitely isn't playing. - if (!FSOUND_IsPlaying(_channel)) { - return AudioSound::READY; - } - - // If the channel is playing, see whether the current time is at the - // end of the file. If not, the stream is playing. - float current_time = this->get_time(); - if (current_time >= _length - 0.01f) { - // FMOD MIDI files don't stop automatically when they hit the end of the - // file. Their channel isn't released unless the stream is stopped - // explicitly. - FSOUND_Stream_Stop(_audio); - return AudioSound::READY; - } else { - return AudioSound::PLAYING; - } +// If the stream's channel isn't playing anything, then the stream +// definitely isn't playing. + + audio_debug("FmodAudioSound::status() "); + + FMOD_RESULT result; + bool playingState; + + if ( _channel != 0 ) { + result = _channel->isPlaying( &playingState ); + ERRCHECK(result); + } + + //audio_debug("If you get 'FMOD State: 32 An invalid object handle was used.' "); + //audio_debug("It doesn't mean there is a problem with FMOD or the sound."); + //audio_debug( "It just means your sound isn't playing." ); + + + if (playingState) { + return PLAYING; + } else { + return READY; + } + + //return BAD; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_active +// Access: public +// Description: NOT USED ANYMORE!!! +// +// +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_active(bool active) { + audio_debug( "set_active(active=" << active << ")" ); + audio_debug("NOT USED ANYMORE in FMOD-EX version of PANDA.") +} + + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::get_active +// Access: public +// Description: NOT 'REALLY' USED ANYMORE!!! +// This is actually an layover from the old version of the FMOD code. +// The old version used a weird cache system to keep track of the sounds' states. +// I just converted this method, to return if a sound is 'Playing' or not. +// This is not exactly how the orignal use of this function btu I figured I might +// as well get some use out of it. +//////////////////////////////////////////////////////////////////// +bool FmodAudioSound::get_active() const { + + audio_debug("FmodAudioSound::get_active() Going to get a sound's activity."); + audio_debug("NOT USED ANYMORE in FMOD-EX version of PANDA.") + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::finished +// Access: public +// Description: NOT USED ANYMORE!!! +// Called by finishedCallback function when a sound +// terminates (but doesn't loop). +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::finished() { + audio_debug("FmodAudioSound::finished()"); + audio_debug("NOT USED ANYMORE in FMOD-EX version of PANDA.") + stop(); + +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioSound::set_finished_event +// Access: public +// Description: NOT USED ANYMORE!!! +// Assign a string for the finished event to be referenced +// by in python by an accept method +// +//////////////////////////////////////////////////////////////////// +void FmodAudioSound::set_finished_event(const string& event) { + audio_debug("FmodAudioSound::set_finished_event(event="< + #ifdef HAVE_FMOD //[ #include "audioSound.h" -class FmodAudioManager; -#include + +#include +#include + +class FmodAudioDSP; class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound { -public: - ~FmodAudioSound(); - - // For best compatability, set the loop_count, start_time, - // volume, and balance, prior to calling play(). You may - // set them while they're playing, but it's implementation - // specific whether you get the results. - void play(); - void stop(); - - // loop: false = play once; true = play forever. - // inits to false. - void set_loop(bool loop=true); - bool get_loop() const; - - // loop_count: 0 = forever; 1 = play once; n = play n times. - // inits to 1. - void set_loop_count(unsigned long loop_count=1); - unsigned long get_loop_count() const; - - // 0 = begining; length() = end. - // inits to 0.0. - void set_time(float start_time=0.0); - float get_time() const; - - // 0 = minimum; 1.0 = maximum. - // inits to 1.0. - void set_volume(float volume=1.0); - float get_volume() const; - - // -1.0 is hard left - // 0.0 is centered - // 1.0 is hard right - // inits to 0.0. - void set_balance(float balance_right=0.0); - float get_balance() const; + public: - // play_rate is any positive float value. - // inits to 1.0. - void set_play_rate(float play_rate=1.0f); - float get_play_rate() const; + FmodAudioSound(AudioManager *manager, string file_name, bool positional ); + ~FmodAudioSound(); + + // For best compatability, set the loop_count, start_time, + // volume, and balance, prior to calling play(). You may + // set them while they're playing, but it's implementation + // specific whether you get the results. + void play(); + void stop(); + + // loop: false = play once; true = play forever. + // inits to false. + void set_loop(bool loop=true); + bool get_loop() const; + + // loop_count: 0 = forever; 1 = play once; n = play n times. + // inits to 1. + void set_loop_count(unsigned long loop_count=1); + unsigned long get_loop_count() const; + + // 0 = begining; length() = end. + // inits to 0.0. + void set_time(float start_time=0.0); + float get_time() const; + + // 0 = minimum; 1.0 = maximum. + // inits to 1.0. + void set_volume(float volume=1.0); + float get_volume() const; + + // -1.0 is hard left + // 0.0 is centered + // 1.0 is hard right + // inits to 0.0. + void set_balance(float balance_right=0.0); + float get_balance() const; - // inits to manager's state. - void set_active(bool active=true); - bool get_active() const; + // play_rate is any positive float value. + // inits to 1.0. + void set_play_rate(float play_rate=1.0f); + float get_play_rate() const; - void set_finished_event(const string& event); - const string& get_finished_event() const; - - const string& get_name() const; - - // return: playing time in seconds. - float length() const; + const string& get_name() const; + + // return: playing time in seconds. + float length() const; - // Controls the position of this sound's emitter. - // pos is a pointer to an xyz triplet of the emitter's position. - // vel is a pointer to an xyz triplet of the emitter's velocity. - void set_3d_attributes(float px, float py, float pz, - float vx, float vy, float vz); - void get_3d_attributes(float *px, float *py, float *pz, - float *vx, float *vy, float *vz); - void set_3d_min_distance(float dist); - float get_3d_min_distance() const; - void set_3d_max_distance(float dist); - float get_3d_max_distance() const; - - AudioSound::SoundStatus status() const; + // Controls the position of this sound's emitter. + // pos is a pointer to an xyz triplet of the emitter's position. + // vel is a pointer to an xyz triplet of the emitter's velocity. + void set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz); + void get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz); - void finished(); + void set_3d_min_distance(float dist); + float get_3d_min_distance() const; -protected: + void set_3d_max_distance(float dist); + float get_3d_max_distance() const; + + AudioSound::SoundStatus status() const; -private: - PT(FmodAudioManager) _manager; - FSOUND_STREAM *_audio; - string _file_name; - string _finished_event; - float _volume; // 0..1.0 - float _balance; // -1..1 - float _pos [3]; - float _vel [3]; - float _min_dist; - float _max_dist; - unsigned long _loop_count; - mutable float _length; // in seconds. - bool _active; - bool _paused; - bool _bExclusive; //stops all other sounds before playing when true - int _channel; + virtual bool add_dsp( PT(AudioDSP) dspToAdd ); + virtual bool remove_dsp( PT(AudioDSP) x); - FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data, - string file_name, float length=0.0f); + virtual float get_speaker_mix(int speaker); + virtual void set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float sideright); - // forbidden functions! - FmodAudioSound(const FmodAudioSound& rhs) {} - const FmodAudioSound& operator=(const FmodAudioSound& rhs) { return *this; } + //THESE ARE NOT USED ANYMORE. + //THEY ARE ONLY HERE BECAUSE THEY are still needed by Miles. + //THESE are stubs in FMOD-EX version + //////////////////////////////////////////////////////////////////// + void set_active(bool active=true); + bool get_active() const; - friend class FmodAudioManager; + void finished(); + void set_finished_event(const string& event); + const string& get_finished_event() const; + //////////////////////////////////////////////////////////////////// + + protected: + + private: + FmodAudioManager *_manager; + FMOD::Sound *_sound; + FMOD::Channel *_channel; + + string _file_name; + + float _volume; + float _balance; + float _playrate; + int _priority; + + float _sampleFrequency; + mutable float _length; //in seconds. + + FMOD_SPEAKERMODE _speakermode; + + float _frontleft; + float _frontright; + float _center; + float _sub; + float _backleft; + float _backright; + float _sideleft; + float _sideright; + + FMOD_VECTOR _location; + FMOD_VECTOR _velocity; + + float _min_dist; + float _max_dist; + + void play2DSound(); + void play3DSound(); + + void prepareSound(); + void prepare2DSound(); + void prepare3DSound(); + + void set_volume_on_channel(); + void set_balance_on_channel(); + void set_play_rate_on_channel(); + void set_speaker_mix_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; + + //THESE AREN'T USED ANYMORE. + //THEY ARE ONLY HERE BECAUSE THEY are still need by Miles. + //THESE are stubs in FMOD-EX version + string _finished_event; + + //////////////////////////////////////////////////////////// + //These are needed for Panda's Pointer System. DO NOT ERASE! + //////////////////////////////////////////////////////////// + + public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + AudioSound::init_type(); + register_type(_type_handle, "FmodAudioSound", AudioSound::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() { + init_type(); + return get_class_type(); + } + + private: + static TypeHandle _type_handle; + + //////////////////////////////////////////////////////////// + //DONE + //////////////////////////////////////////////////////////// }; #include "fmodAudioSound.I" diff --git a/panda/src/audiotraits/fmod_audio_composite1.cxx b/panda/src/audiotraits/fmod_audio_composite1.cxx index da514bbdd5..8032c7158e 100644 --- a/panda/src/audiotraits/fmod_audio_composite1.cxx +++ b/panda/src/audiotraits/fmod_audio_composite1.cxx @@ -2,4 +2,5 @@ #include "config_fmodAudio.cxx" #include "fmodAudioManager.cxx" #include "fmodAudioSound.cxx" +#include "fmodAudioDSP.cxx" diff --git a/panda/src/display/frameBufferProperties.I b/panda/src/display/frameBufferProperties.I index 924482495e..cfc0e93118 100644 --- a/panda/src/display/frameBufferProperties.I +++ b/panda/src/display/frameBufferProperties.I @@ -140,6 +140,31 @@ specifies_mode(int bits) const { return (_frame_buffer_mode & bits) != 0; } +//////////////////////////////////////////////////////////////////// +// Function: FrameBufferProperties::is_basic +// Access: Published +// Description: Returns true if the properties are extremely basic. +// The following count as basic: rgb or rgba, depth. +// If anything else is specified, the properties are +// non-basic. +//////////////////////////////////////////////////////////////////// +INLINE bool FrameBufferProperties:: +is_basic() const { + if (_frame_buffer_mode & (~(FM_alpha | FM_depth))) { + return false; + } + if (_depth_bits || _color_bits || _alpha_bits || _stencil_bits) { + return false; + } + if (_multisamples) { + return false; + } + if (_aux_rgba || _aux_hrgba || _aux_float) { + return false; + } + return true; +} + //////////////////////////////////////////////////////////////////// // Function: FrameBufferProperties::is_stereo // Access: Published @@ -544,6 +569,16 @@ set_specified() { recalc_buffer_mask(); } +//////////////////////////////////////////////////////////////////// +// Function: FrameBufferProperties::get_specified +// Access: Public +// Description: Returns the specified flags. +//////////////////////////////////////////////////////////////////// +INLINE int FrameBufferProperties:: +get_specified() const { + return _specified; +} + //////////////////////////////////////////////////////////////////// // Function: FrameBufferProperties::get_buffer_mask // Access: Public diff --git a/panda/src/display/frameBufferProperties.cxx b/panda/src/display/frameBufferProperties.cxx index 789a164d74..db44b7b3d3 100644 --- a/panda/src/display/frameBufferProperties.cxx +++ b/panda/src/display/frameBufferProperties.cxx @@ -61,7 +61,55 @@ operator = (const FrameBufferProperties ©) { //////////////////////////////////////////////////////////////////// bool FrameBufferProperties:: subsumes(const FrameBufferProperties &other) const { - // NOT IMPLEMENTED YET + if (other._specified & S_depth_bits) { + if (((_specified & S_depth_bits)==0) || (other._depth_bits > _depth_bits)) { + return false; + } + } + if (other._specified & S_color_bits) { + if (((_specified & S_color_bits)==0) || (other._color_bits > _color_bits)) { + return false; + } + } + if (other._specified & S_alpha_bits) { + if (((_specified & S_alpha_bits)==0) || (other._alpha_bits > _alpha_bits)) { + return false; + } + } + if (other._specified & S_stencil_bits) { + if (((_specified & S_stencil_bits)==0) || (other._stencil_bits > _stencil_bits)) { + return false; + } + } + if ((other._specified & S_multisamples) && (other._multisamples > 1)) { + // Multisample spec of 1 is ignored - 1 multisample is tautologous. + if (((_specified & S_multisamples)==0) || (other._multisamples > _multisamples)) { + return false; + } + } + if (other._specified & S_aux_rgba) { + if (((_specified & S_aux_rgba)==0) || (other._aux_rgba > _aux_rgba)) { + return false; + } + } + if (other._specified & S_aux_hrgba) { + if (((_specified & S_aux_hrgba)==0) || (other._aux_hrgba > _aux_hrgba)) { + return false; + } + } + if (other._specified & S_aux_float) { + if (((_specified & S_aux_float)==0) || (other._aux_float > _aux_float)) { + return false; + } + } + if (other._specified & S_frame_buffer_mode) { + if ((_specified & S_frame_buffer_mode)==0) { + return false; + } + if (other._frame_buffer_mode & (~_frame_buffer_mode)) { + return false; + } + } return true; } @@ -74,6 +122,7 @@ subsumes(const FrameBufferProperties &other) const { //////////////////////////////////////////////////////////////////// FrameBufferProperties FrameBufferProperties:: get_default() { + FrameBufferProperties props; int mode = 0; @@ -149,6 +198,9 @@ get_default() { if (framebuffer_stereo) { mode |= FM_stereo; } + if ((mode & FM_hardware) && (mode & FM_software)) { + mode = mode & ~(FM_hardware | FM_software); + } props.set_frame_buffer_mode(mode); props.set_depth_bits(depth_bits); diff --git a/panda/src/display/frameBufferProperties.h b/panda/src/display/frameBufferProperties.h index efe3ebb277..56e7b3d8b4 100644 --- a/panda/src/display/frameBufferProperties.h +++ b/panda/src/display/frameBufferProperties.h @@ -45,7 +45,7 @@ PUBLISHED: FM_index = 0x0001, FM_single_buffer = 0x0000, FM_double_buffer = 0x0002, - FM_triple_buffer = 0x0004, + FM_triple_buffer = 0x0006, FM_buffer = 0x0006, // == (FM_single_buffer | FM_double_buffer | FM_triple_buffer) FM_accum = 0x0008, FM_alpha = 0x0010, @@ -57,15 +57,33 @@ PUBLISHED: FM_software = 0x0200, FM_hardware = 0x0400, }; + + // This bitmask indicates which of the parameters in the properties + // structure have been filled in by the user, and which remain + // unspecified. + enum Specified { + S_frame_buffer_mode = 0x0001, + S_depth_bits = 0x0002, + S_color_bits = 0x0004, + S_alpha_bits = 0x0008, + S_stencil_bits = 0x0010, + S_multisamples = 0x0020, + S_aux_rgba = 0x0040, + S_aux_hrgba = 0x0080, + S_aux_float = 0x0100, + S_ALL_SPECIFIED = 0x01FF, + }; void clear(); INLINE void set_specified(); + INLINE int get_specified() const; INLINE int get_buffer_mask() const; INLINE bool is_any_specified() const; INLINE bool specifies_mode(int bit) const; INLINE bool is_single_buffered() const; INLINE bool is_stereo() const; - + INLINE bool is_basic() const; + bool subsumes(const FrameBufferProperties &prop) const; INLINE void set_frame_buffer_mode(int frameBuffer_mode); @@ -124,21 +142,6 @@ private: void recalc_buffer_mask(); private: - // This bitmask indicates which of the parameters in the properties - // structure have been filled in by the user, and which remain - // unspecified. - enum Specified { - S_frame_buffer_mode = 0x0001, - S_depth_bits = 0x0002, - S_color_bits = 0x0004, - S_alpha_bits = 0x0008, - S_stencil_bits = 0x0010, - S_multisamples = 0x0020, - S_aux_rgba = 0x0040, - S_aux_hrgba = 0x0080, - S_aux_float = 0x0100, - S_ALL_SPECIFIED = 0x01FF, - }; int _specified; int _flags; diff --git a/panda/src/display/graphicsEngine.I b/panda/src/display/graphicsEngine.I index 811a71a9a1..113626c1fd 100644 --- a/panda/src/display/graphicsEngine.I +++ b/panda/src/display/graphicsEngine.I @@ -126,7 +126,8 @@ make_window(GraphicsStateGuardian *gsg, const string &name, int sort) { // The hardwired size here is never used. GraphicsOutput *result = make_output(gsg->get_pipe(), name, sort, gsg->get_default_properties(), 50, 50, - GraphicsPipe::BF_require_window, + GraphicsPipe::BF_require_window | + GraphicsPipe::BF_fb_props_optional, gsg, NULL); return DCAST(GraphicsWindow, result); } @@ -150,7 +151,8 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name, props.set_frame_buffer_mode(props.get_frame_buffer_mode() & (~clear)); GraphicsOutput *result = make_output(gsg->get_pipe(), name, sort, gsg->get_default_properties(), x_size, y_size, - GraphicsPipe::BF_refuse_window, + GraphicsPipe::BF_refuse_window | + GraphicsPipe::BF_fb_props_optional, gsg, NULL); return result; } @@ -166,7 +168,8 @@ make_parasite(GraphicsOutput *host, const string &name, FrameBufferProperties props; GraphicsOutput *result = make_output(host->get_pipe(), name, sort, props, x_size, y_size, - GraphicsPipe::BF_require_parasite, + GraphicsPipe::BF_require_parasite | + GraphicsPipe::BF_fb_props_optional, host->get_gsg(), host); return result; } diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 9a6444e839..8b10e96055 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -332,6 +332,23 @@ make_output(GraphicsPipe *pipe, gsg = make_gsg(pipe, prop); } + // If there is a host window, and it is not yet initialized, + // then call open_windows to get the host ready. If that + // fails, give up on using the host window. + + if (host != (GraphicsOutput *)NULL) { + if ((!host->is_valid())|| + (!host->get_gsg()->is_valid())|| + (host->get_gsg()->needs_reset())) { + open_windows(); + } + if ((!host->is_valid())|| + (!host->get_gsg()->is_valid())|| + (host->get_gsg()->needs_reset())) { + host = NULL; + } + } + // Determine if a parasite buffer meets the user's specs. bool can_use_parasite = false; @@ -340,24 +357,23 @@ make_output(GraphicsPipe *pipe, ((flags&GraphicsPipe::BF_refuse_parasite)==0)&& ((flags&GraphicsPipe::BF_can_bind_color)==0)&& ((flags&GraphicsPipe::BF_can_bind_every)==0)&& - ((flags&GraphicsPipe::BF_rtt_cumulative)==0)&& - (prop.specifies_mode(FrameBufferProperties::FM_index)==false)&& - (prop.specifies_mode(FrameBufferProperties::FM_buffer)==false)&& - (prop.specifies_mode(FrameBufferProperties::FM_accum)==false)&& - (prop.specifies_mode(FrameBufferProperties::FM_stencil)==false)&& - (prop.specifies_mode(FrameBufferProperties::FM_multisample)==false)&& - (prop.get_aux_rgba() == 0)&& - (prop.get_aux_hrgba() == 0)&& - (prop.get_aux_float() == 0)) { - can_use_parasite = true; + ((flags&GraphicsPipe::BF_rtt_cumulative)==0)) { + if ((flags&GraphicsPipe::BF_fb_props_optional) || + (host->get_fb_properties().subsumes(prop))) { + can_use_parasite = true; + } } // If parasite buffers are preferred, then try a parasite first. + // Even if prefer-parasite-buffer is set, parasites are not preferred + // if the host window is too small, or if the host window does not + // have the requested properties. if ((prefer_parasite_buffer) && (can_use_parasite) && (x_size <= host->get_x_size())&& - (y_size <= host->get_y_size())) { + (y_size <= host->get_y_size())&& + (host->get_fb_properties().subsumes(prop))) { ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags); buffer->_sort = sort; do_add_window(buffer, gsg, threading_model); @@ -378,7 +394,14 @@ make_output(GraphicsPipe *pipe, } open_windows(); if (window->is_valid()) { - return window; + if (window->get_fb_properties().subsumes(prop)) { + return window; + } else { + if (flags & GraphicsPipe::BF_fb_props_optional) { + display_cat.warning() << "FrameBufferProperties available less than requested.\n"; + return window; + } + } } // No good; delete the window and keep trying. bool removed = remove_window(window); diff --git a/panda/src/display/graphicsPipe.h b/panda/src/display/graphicsPipe.h index 0abbeb54c0..b1cae08059 100644 --- a/panda/src/display/graphicsPipe.h +++ b/panda/src/display/graphicsPipe.h @@ -89,6 +89,7 @@ PUBLISHED: BF_can_bind_every = 0x0080, // Need capability: bind all bitplanes to a tex. BF_size_track_host = 0x0100, // Buffer should track the host size. BF_rtt_cumulative = 0x0200, // Buffer supports cumulative render-to-texture. + BF_fb_props_optional = 0x0400, // FrameBufferProperties can be ignored. }; INLINE bool is_valid() const; diff --git a/panda/src/wgldisplay/wglGraphicsPipe.cxx b/panda/src/wgldisplay/wglGraphicsPipe.cxx index 518296ab7f..8aaa100f3e 100644 --- a/panda/src/wgldisplay/wglGraphicsPipe.cxx +++ b/panda/src/wgldisplay/wglGraphicsPipe.cxx @@ -158,12 +158,16 @@ make_output(const string &name, ((flags&BF_size_track_host)!=0)|| ((flags&BF_rtt_cumulative)!=0)|| ((flags&BF_can_bind_color)!=0)|| - ((flags&BF_can_bind_every)!=0)|| - (properties.get_aux_rgba() > 0)|| - (properties.get_aux_hrgba() > 0)|| - (properties.get_aux_float() > 0)) { + ((flags&BF_can_bind_every)!=0)) { return NULL; } + if ((flags & BF_fb_props_optional)==0) { + if ((properties.get_aux_rgba() > 0)|| + (properties.get_aux_hrgba() > 0)|| + (properties.get_aux_float() > 0)) { + return NULL; + } + } return new wglGraphicsWindow(this, name, properties, x_size, y_size, flags, gsg, host); } @@ -175,19 +179,28 @@ make_output(const string &name, (!gl_support_fbo)|| (host==0)|| ((flags&BF_require_parasite)!=0)|| - ((flags&BF_require_window)!=0)|| - (properties.specifies_mode(FrameBufferProperties::FM_index))|| - (properties.specifies_mode(FrameBufferProperties::FM_buffer))|| - (properties.specifies_mode(FrameBufferProperties::FM_accum))|| - (properties.specifies_mode(FrameBufferProperties::FM_stencil))|| - (properties.specifies_mode(FrameBufferProperties::FM_multisample))) { + ((flags&BF_require_window)!=0)) { return NULL; } + // Early failure - if we are sure that this buffer WONT + // meet specs, we can bail out early. + if ((flags & BF_fb_props_optional)==0) { + if ((properties.has_mode(FrameBufferProperties::FM_index))|| + (properties.has_mode(FrameBufferProperties::FM_buffer))|| + (properties.has_mode(FrameBufferProperties::FM_accum))|| + (properties.has_mode(FrameBufferProperties::FM_stencil))|| + (properties.has_mode(FrameBufferProperties::FM_multisample))) { + return NULL; + } + } + // Early success - if we are sure that this buffer WILL + // meet specs, we can precertify it. if ((wglgsg != 0) && (wglgsg->is_valid()) && (!wglgsg->needs_reset()) && (wglgsg->_supports_framebuffer_object) && - (wglgsg->_glDrawBuffers != 0)) { + (wglgsg->_glDrawBuffers != 0)&& + (properties.is_basic())) { precertify = true; } return new GLGraphicsBuffer(this, name, properties, @@ -202,16 +215,25 @@ make_output(const string &name, ((flags&BF_require_window)!=0)|| ((flags&BF_size_track_host)!=0)|| ((flags&BF_rtt_cumulative)!=0)|| - ((flags&BF_can_bind_every)!=0)|| - (properties.get_aux_rgba() > 0)|| - (properties.get_aux_hrgba() > 0)|| - (properties.get_aux_float() > 0)) { + ((flags&BF_can_bind_every)!=0)) { return NULL; } + // Early failure - if we are sure that this buffer WONT + // meet specs, we can bail out early. + if ((flags & BF_fb_props_optional) == 0) { + if ((properties.get_aux_rgba() > 0)|| + (properties.get_aux_hrgba() > 0)|| + (properties.get_aux_float() > 0)) { + return NULL; + } + } + // Early success - if we are sure that this buffer WILL + // meet specs, we can precertify the window. if ((wglgsg != 0) && (wglgsg->is_valid()) && (!wglgsg->needs_reset()) && - (wglgsg->_supports_pbuffer)) { + (wglgsg->_supports_pbuffer) && + (properties.is_basic())) { precertify = true; } return new wglGraphicsBuffer(this, name, properties, @@ -525,7 +547,7 @@ get_properties(FrameBufferProperties &properties, HDC hdc, } else { mode |= FrameBufferProperties::FM_hardware; } - + if (pfd.cColorBits != 0) { mode |= FrameBufferProperties::FM_rgb; properties.set_color_bits(pfd.cColorBits);