diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 6308fa090d..2e49874da3 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -210,6 +210,8 @@ class ShowBase(DirectObject.DirectObject): del self.win del self.winList del self.pipe + del self.musicManager + del self.sfxManagerList try: direct.panel.destroy() diff --git a/dtool/Config.pp b/dtool/Config.pp index 0375c667ca..2576e6bf77 100644 --- a/dtool/Config.pp +++ b/dtool/Config.pp @@ -365,6 +365,13 @@ #define RAD_MSS_LIBS Mss32 #defer HAVE_RAD_MSS $[libtest $[RAD_MSS_LPATH],$[RAD_MSS_LIBS]] +// Info for the Fmod audio engine +// note this may be overwritten in wintools Config.pp +#define FMOD_IPATH +#define FMOD_LPATH +#define FMOD_LIBS fmod +#defer HAVE_FMOD $[libtest $[FMOD_LPATH],$[FMOD_LIBS]] + // Info for http://www.sourceforge.net/projects/chromium // note this may be overwritten in wintools Config.pp #define CHROMIUM_IPATH /usr/include/chromium/include diff --git a/dtool/LocalSetup.pp b/dtool/LocalSetup.pp index d32c8bd755..509125f5ae 100644 --- a/dtool/LocalSetup.pp +++ b/dtool/LocalSetup.pp @@ -19,6 +19,9 @@ $[cdefine HAVE_PYTHON] /* Define if we have RAD game tools, Miles Sound System installed. */ $[cdefine HAVE_RAD_MSS] +/* Define if we have FMOD installed. */ +$[cdefine HAVE_FMOD] + /* Define if we have Freetype 2.0 or better available. */ $[cdefine HAVE_FREETYPE] diff --git a/dtool/Package.pp b/dtool/Package.pp index d67c1a30d3..0a10d45528 100644 --- a/dtool/Package.pp +++ b/dtool/Package.pp @@ -184,6 +184,11 @@ #set RAD_MSS_LIBS $[RAD_MSS_LIBS] #set HAVE_RAD_MSS $[HAVE_RAD_MSS] +#set FMOD_IPATH $[unixfilename $[FMOD_IPATH]] +#set FMOD_LPATH $[unixfilename $[FMOD_LPATH]] +#set FMOD_LIBS $[FMOD_LIBS] +#set HAVE_FMOD $[HAVE_FMOD] + #set CHROMIUM_IPATH $[unixfilename $[CHROMIUM_IPATH]] #set CHROMIUM_LPATH $[unixfilename $[CHROMIUM_LPATH]] #set CHROMIUM_LIBS $[CHROMIUM_LIBS] diff --git a/dtool/pptempl/Global.pp b/dtool/pptempl/Global.pp index 01680d5c7f..d5ec4a923a 100644 --- a/dtool/pptempl/Global.pp +++ b/dtool/pptempl/Global.pp @@ -236,6 +236,12 @@ #define rad_mss_libs $[RAD_MSS_LIBS] #endif +#if $[HAVE_FMOD] + #define fmod_ipath $[wildcard $[FMOD_IPATH]] + #define fmod_lpath $[wildcard $[FMOD_LPATH]] + #define fmod_libs $[FMOD_LIBS] +#endif + #if $[HAVE_CHROMIUM] #define chromium_ipath $[wildcard $[CHROMIUM_IPATH]] #define chromium_lpath $[wildcard $[CHROMIUM_LPATH]] diff --git a/panda/src/audiotraits/Sources.pp b/panda/src/audiotraits/Sources.pp index c884f21b12..ac619ff69f 100644 --- a/panda/src/audiotraits/Sources.pp +++ b/panda/src/audiotraits/Sources.pp @@ -21,6 +21,26 @@ #end lib_target +#begin lib_target + #define TARGET fmod_audio + #define BUILD_TARGET $[HAVE_FMOD] + #define USE_PACKAGES fmod + #define BUILDING_DLL BUILDING_FMOD_AUDIO + #define LOCAL_LIBS audio + #define WIN_SYS_LIBS $[WIN_SYS_LIBS] user32.lib advapi32.lib winmm.lib + + #define COMBINED_SOURCES $[TARGET]_composite1.cxx + + #define SOURCES \ + config_fmodAudio.h \ + fmodAudioManager.h \ + fmodAudioSound.I fmodAudioSound.h + + #define INCLUDED_SOURCES \ + config_fmodAudio.cxx fmodAudioManager.cxx fmodAudioSound.cxx + +#end lib_target + //#begin lib_target // #define TARGET audio_linux // #define BUILDING_DLL BUILDING_MISC diff --git a/panda/src/audiotraits/config_fmodAudio.cxx b/panda/src/audiotraits/config_fmodAudio.cxx new file mode 100644 index 0000000000..afac862b85 --- /dev/null +++ b/panda/src/audiotraits/config_fmodAudio.cxx @@ -0,0 +1,54 @@ +// Filename: config_fmodAudio.cxx +// Created by: cort +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "pandabase.h" +#ifdef HAVE_FMOD //[ + +#include "config_fmodAudio.h" +#include "fmodAudioManager.h" +#include "fmodAudioSound.h" +#include "dconfig.h" + +ConfigureDef(config_fmodAudio); +NotifyCategoryDef(fmodAudio, ""); + +ConfigureFn(config_fmodAudio) { + init_libFmodAudio(); +} + +//////////////////////////////////////////////////////////////////// +// Function: init_libFmodAudio +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void +init_libFmodAudio() { + static bool initialized = false; + if (initialized) { + return; + } + + initialized = true; + + AudioManager::register_AudioManager_creator(Create_AudioManager); +} + +#endif //] diff --git a/panda/src/audiotraits/config_fmodAudio.h b/panda/src/audiotraits/config_fmodAudio.h new file mode 100644 index 0000000000..344a3764a3 --- /dev/null +++ b/panda/src/audiotraits/config_fmodAudio.h @@ -0,0 +1,35 @@ +// Filename: config_fmodAudio.h +// Created by: cort +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONFIG_FMODAUDIO_H +#define CONFIG_FMODAUDIO_H + +#include "pandabase.h" + +#ifdef HAVE_FMOD //[ +#include "notifyCategoryProxy.h" +#include "dconfig.h" + +ConfigureDecl(config_fmodAudio, EXPCL_FMOD_AUDIO, EXPTP_FMOD_AUDIO); +NotifyCategoryDecl(fmodAudio, EXPCL_FMOD_AUDIO, EXPTP_FMOD_AUDIO); + +extern EXPCL_FMOD_AUDIO void init_libFmodAudio(); + +#endif //] + +#endif // CONFIG_FMODAUDIO_H diff --git a/panda/src/audiotraits/fmodAudioManager.cxx b/panda/src/audiotraits/fmodAudioManager.cxx new file mode 100644 index 0000000000..eaae30483e --- /dev/null +++ b/panda/src/audiotraits/fmodAudioManager.cxx @@ -0,0 +1,482 @@ +// Filename: fmodAudioManager.cxx +// Created by: cort (January 22, 2003) +// Prior system by: cary +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "pandabase.h" +#ifdef HAVE_FMOD //[ + +#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 +#include +#include +#include +using std::cerr; + +PT(AudioManager) Create_AudioManager() { + audio_debug("Create_AudioManager() Fmod."); + return new FmodAudioManager; +} + +int FmodAudioManager::_active_managers = 0; + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::FmodAudioManager +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +FmodAudioManager:: +FmodAudioManager() { + audio_debug("FmodAudioManager::FmodAudioManager()"); + audio_debug(" audio_active="<data), + flags, entry->size); + } + if (stream == NULL) { + audio_error("FmodAudioManager::get_sound failed."); + return 0; + } + inc_refcount(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); + fmodAudioSound->set_active(_active); + _soundsOnLoan.insert(fmodAudioSound); + audioSound = fmodAudioSound; + + audio_debug(" returning 0x" << (void*)audioSound); + assert(is_valid()); + return audioSound; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::uncache_sound +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void FmodAudioManager:: +uncache_sound(const string& file_name) { + audio_debug("FmodAudioManager::uncache_sound(\""<refcount == 0) { + audio_debug("FmodAudioManager::dec_refcount: purging "<data; + _sounds.erase(itor); + } else { + entry->stale = true; + } + + assert(is_valid()); +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::clear_cache +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void FmodAudioManager:: +clear_cache() { + // Mark all cache entries as stale. Delete those which already have + // refcounts of zero. + SoundMap::iterator itor = _sounds.begin(); + for( ; itor != _sounds.end(); ++itor) { + SoundCacheEntry *entry = &(*itor).second; + if (entry->refcount == 0) { + audio_debug("FmodAudioManager: purging "<< (*itor).first + << " from the cache."); + delete [] entry->data; + _sounds.erase(itor); + itor = _sounds.begin(); + } else { + entry->stale = true; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::set_cache_limit +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void FmodAudioManager:: +set_cache_limit(int) { + // intentionally blank. +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::get_cache_limit +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +int FmodAudioManager:: +get_cache_limit() { + // intentionally blank. + return 0; +} + +//////////////////////////////////////////////////////////////////// +// 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) { + // intentionally blank. +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::get_volume +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +float FmodAudioManager:: +get_volume() { + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::set_active +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void FmodAudioManager:: +set_active(bool active) { + audio_debug("FmodAudioManager::set_active(flag="<refcount++; + entry->stale = false; // definitely not stale! + audio_debug("FmodAudioManager: "<refcount); + } else { + audio_debug("FmodAudioManager::inc_refcount: no such file "<refcount--; + audio_debug("FmodAudioManager: "<refcount); + if (entry->refcount == 0 && entry->stale) { + audio_debug("FmodAudioManager: purging "<data; + _sounds.erase(itor); + } + } else { + audio_debug("FmodAudioManager::dec_refcount: no such file "< +#ifdef HAVE_FMOD //[ + +#include "audioManager.h" +class FmodAudioSound; +#include "filename.h" +#include "pmap.h" +#include "pset.h" + +#include + +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&); + virtual void uncache_sound(const string&); + virtual void clear_cache(); + virtual void set_cache_limit(int); + virtual int get_cache_limit(); + + virtual void set_volume(float); + virtual float get_volume(); + + virtual void set_active(bool); + virtual bool get_active(); + void stop_all_sounds(); + +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? + void *data; // the memory-mapped audio file. + } SoundCacheEntry; + typedef pmap SoundMap; + SoundMap _sounds; + + typedef pset AudioSet; + // The offspring of this manager: + AudioSet _soundsOnLoan; + + void release_sound(FmodAudioSound *audioSound); + + static int _active_managers; + bool _is_valid; + bool _active; + + void* load(const Filename& filename, const size_t size) const; + size_t get_file_size(const Filename& filename) const; + + friend FmodAudioSound; +}; + +EXPCL_FMOD_AUDIO PT(AudioManager) Create_AudioManager(); + +#endif //] + +#endif /* __FMOD_AUDIO_MANAGER_H__ */ diff --git a/panda/src/audiotraits/fmodAudioSound.I b/panda/src/audiotraits/fmodAudioSound.I new file mode 100644 index 0000000000..3ceafae70e --- /dev/null +++ b/panda/src/audiotraits/fmodAudioSound.I @@ -0,0 +1,24 @@ +// Filename: fmodAudioSound.I +// Created by: cort (January 22, 2003) +// Prior system by: cary +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + + + + + diff --git a/panda/src/audiotraits/fmodAudioSound.cxx b/panda/src/audiotraits/fmodAudioSound.cxx new file mode 100644 index 0000000000..636608ab63 --- /dev/null +++ b/panda/src/audiotraits/fmodAudioSound.cxx @@ -0,0 +1,239 @@ +// Filename: fmodAudioSound.cxx +// Created by: cort (January 22, 2003) +// Prior system by: cary +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include +#ifdef HAVE_FMOD //[ + +#include "fmodAudioSound.h" +#include "fmodAudioManager.h" + +#include + +#ifndef NDEBUG //[ + #define fmod_audio_debug(x) \ + audio_debug("FmodAudioSound "<<" \""<stop(); + _manager->release_sound(this); +} + +void FmodAudioSound:: +play() { + if (!_active) { + return; + } + + if(_manager->_bExclusive) { + // stop any other sound that parent mgr is playing + _manager->stop_all_sounds(); + } + + // If the sound is already playing, stop it. + if (this->status() == AudioSound::PLAYING) { + this->stop(); + } + + // Play the stream, but start it paused so we can set the volume and + // panning first. + bool bStatusOK = false; + 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); + + // 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)); +} + +void FmodAudioSound::stop() { + FSOUND_Stream_Stop(_audio); + _channel = -1; +} + +void FmodAudioSound::set_loop(bool loop) { + audio_error("FmodAudioSound::set_loop() -- not yet implemented"); + fmod_audio_debug("set_loop() set to "< _length) { + fmod_audio_debug("set_time(): param "< 1.0f) { + fmod_audio_debug("set_volume(): param "< 1.0f) { + fmod_audio_debug("set_balance(): param "<stop(); + } + _active = active; +} + +bool FmodAudioSound::get_active() const { + fmod_audio_debug("get_active() returning "<<_active); + return _active; +} + +const string& FmodAudioSound::get_name() const { + //fmod_audio_debug("get_name() returning "<<_file_name); + return _file_name; +} + +float FmodAudioSound::length() const { + return _length; +} + +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; + } +} + +#endif //] diff --git a/panda/src/audiotraits/fmodAudioSound.h b/panda/src/audiotraits/fmodAudioSound.h new file mode 100644 index 0000000000..105ce02a2f --- /dev/null +++ b/panda/src/audiotraits/fmodAudioSound.h @@ -0,0 +1,108 @@ +// Filename: fmodAudioSound.h +// Created by: cort (January 22, 2003) +// Prior system by: cary +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef __FMOD_AUDIO_SOUND_H__ +#define __FMOD_AUDIO_SOUND_H__ + +#include +#ifdef HAVE_FMOD //[ + +#include "audioSound.h" +class FmodAudioManager; +#include + + +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; + + // inits to manager's state. + void set_active(bool active=true); + bool get_active() const; + + const string& get_name() const; + + // return: playing time in seconds. + float length() const; + + AudioSound::SoundStatus status() const; + +protected: + +private: + FSOUND_STREAM *_audio; + PT(FmodAudioManager) _manager; + float _volume; // 0..1.0 + float _balance; // -1..1 + mutable float _length; // in seconds. + unsigned long _loop_count; + string _file_name; + bool _active; + bool _paused; + int _channel; + + FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data, + string file_name, float length=0.0f); + + // forbidden functions! + FmodAudioSound(const FmodAudioSound& rhs) {} + const FmodAudioSound& operator=(const FmodAudioSound& rhs) { return *this; } + + friend class FmodAudioManager; +}; + +#include "fmodAudioSound.I" + +#endif //] + +#endif /* __FMOD_AUDIO_SOUND_H__ */ diff --git a/panda/src/audiotraits/fmod_audio_composite.cxx b/panda/src/audiotraits/fmod_audio_composite.cxx new file mode 100644 index 0000000000..9548c61dae --- /dev/null +++ b/panda/src/audiotraits/fmod_audio_composite.cxx @@ -0,0 +1,5 @@ +/* Generated automatically by ppremake 1.11 from Sources.pp. */ +/* ################################# DO NOT EDIT ########################### */ + +#include "fmod_audio_composite1.cxx" + diff --git a/panda/src/audiotraits/fmod_audio_composite1.cxx b/panda/src/audiotraits/fmod_audio_composite1.cxx new file mode 100644 index 0000000000..da514bbdd5 --- /dev/null +++ b/panda/src/audiotraits/fmod_audio_composite1.cxx @@ -0,0 +1,5 @@ + +#include "config_fmodAudio.cxx" +#include "fmodAudioManager.cxx" +#include "fmodAudioSound.cxx" + diff --git a/panda/src/pandabase/pandasymbols.h b/panda/src/pandabase/pandasymbols.h index 3fd7b28af5..80ed8d25d3 100644 --- a/panda/src/pandabase/pandasymbols.h +++ b/panda/src/pandabase/pandasymbols.h @@ -52,6 +52,14 @@ #define EXPTP_MILES_AUDIO extern #endif +#ifdef BUILDING_FMOD_AUDIO + #define EXPCL_FMOD_AUDIO __declspec(dllexport) + #define EXPTP_FMOD_AUDIO +#else + #define EXPCL_FMOD_AUDIO __declspec(dllimport) + #define EXPTP_FMOD_AUDIO extern +#endif + #ifdef BUILDING_PANDA #define EXPCL_PANDA __declspec(dllexport) #define EXPTP_PANDA