Cort Stratton's FMOD implementation

This commit is contained in:
David Rose 2003-02-06 23:57:57 +00:00
parent 264e112fad
commit 92fca841bd
16 changed files with 1096 additions and 0 deletions

View File

@ -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()

View File

@ -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

View File

@ -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]

View File

@ -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]

View File

@ -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]]

View File

@ -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

View File

@ -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 //]

View File

@ -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

View File

@ -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 <algorithm>
#include <cctype>
#include <fmod.h>
#include <iostream>
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="<<audio_active);
audio_debug(" audio_volume="<<audio_volume);
_active = audio_active;
// Initialize FMOD, if this is the first manager created.
if (_active_managers == 0) {
do {
audio_debug("Initializing FMOD for real.");
float fmod_dll_version = FSOUND_GetVersion();
if (fmod_dll_version < FMOD_VERSION) {
audio_error("Wrong FMOD DLL version. You have "<<fmod_dll_version
<<". You need "<<FMOD_VERSION);
_is_valid = false;
break;
}
if (FSOUND_Init(44100, 32, 0) == 0) {
audio_error("Fmod initialization failure.");
_is_valid = false;
break;
}
}
while(0);
_is_valid = true;
}
// increment regardless of whether an error has occured -- the
// destructor will do the right thing.
++_active_managers;
audio_debug(" _active_managers="<<_active_managers);
if (_is_valid) {
assert(is_valid());
}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::~FmodAudioManager
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
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();
}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::is_valid
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool FmodAudioManager::
is_valid() {
// verify the cache and LRU list here.
return true;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::get_sound
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PT(AudioSound) FmodAudioManager::
get_sound(const string &file_name) {
audio_debug("FmodAudioManager::get_sound(file_name=\""<<file_name<<"\")");
if(!is_valid()) {
audio_debug("invalid FmodAudioManager returning NullSound");
return new NullAudioSound();
}
assert(is_valid());
Filename path = file_name;
audio_debug(" resolved file_name is '"<<path<<"'");
// Get the sound, either from the cache or from disk.
SoundMap::iterator si = _sounds.find(path);
SoundCacheEntry *entry = NULL;
if (si != _sounds.end()) {
// The sound was found in the cache.
entry = &(*si).second;
audio_debug("Sound file '"<<path<<"' found in cache.");
} else {
// The sound was not found in the cache. Load it from disk.
SoundCacheEntry new_entry;
new_entry.size = get_file_size(path);
if (new_entry.size == 0) {
audio_error("FmodAudioManager::get_file_size failed.");
return 0;
}
new_entry.data = load(path, new_entry.size);
if (!new_entry.data) {
audio_error("FmodAudioManager::load failed.");
return 0;
}
new_entry.refcount = 0;
new_entry.stale = true;
// Add to the cache
entry = &new_entry;
_sounds[path] = new_entry;
}
assert(entry != 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;
string os_path = path.to_os_specific();
string suffix = path.get_extension();
std::transform(suffix.begin(), suffix.end(), suffix.begin(), tolower);
if (suffix == "mid" || suffix == "rmi" || suffix == "midi") {
stream = FSOUND_Stream_OpenFile(os_path.c_str(), 0, 0);
} else {
stream = FSOUND_Stream_OpenFile((const char*)(entry->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(\""<<file_name<<"\")");
Filename path = file_name;
assert(is_valid());
SoundMap::iterator itor = _sounds.find(path);
if (itor == _sounds.end()) {
audio_error("FmodAudioManager::uncache_sound: no such entry "<<file_name);
return;
}
// Mark the entry as stale -- when its refcount reaches zero, it will
// be removed from the cache. If the refcount is already zero, it can be
// purged right now!
SoundCacheEntry *entry = &(*itor).second;
if (entry->refcount == 0) {
audio_debug("FmodAudioManager::dec_refcount: purging "<<path
<< " from the cache.");
delete [] entry->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=\""
<<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="<<active<<")");
if (_active!=active) {
_active=active;
// Tell our AudioSounds to adjust:
AudioSet::iterator i=_soundsOnLoan.begin();
for (; i!=_soundsOnLoan.end(); ++i) {
(**i).set_active(_active);
}
}
_active = active;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::get_active
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool FmodAudioManager::
get_active() {
return _active;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::stop_all_sounds
// Access: Public
// Description: Stop playback on all sounds managed by this manager.
////////////////////////////////////////////////////////////////////
void FmodAudioManager::
stop_all_sounds(void) {
audio_debug("FmodAudioManager::stop_all_sounds()");
AudioSet::iterator i=_soundsOnLoan.begin();
for (; i!=_soundsOnLoan.end(); ++i) {
if((**i).status()==AudioSound::PLAYING)
(**i).stop();
}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::inc_refcount
// Access: Protected
// Description: Increments the refcount of a file's cache entry.
////////////////////////////////////////////////////////////////////
void FmodAudioManager::
inc_refcount(const string& file_name) {
Filename path = file_name;
SoundMap::iterator itor = _sounds.find(path.to_os_specific());
if (itor != _sounds.end()) {
SoundCacheEntry *entry = &(*itor).second;
entry->refcount++;
entry->stale = false; // definitely not stale!
audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
<< entry->refcount);
} else {
audio_debug("FmodAudioManager::inc_refcount: no such file "<<path);
}
}
////////////////////////////////////////////////////////////////////
// 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.to_os_specific());
if (itor != _sounds.end()) {
SoundCacheEntry *entry = &(*itor).second;
entry->refcount--;
audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
<< entry->refcount);
if (entry->refcount == 0 && entry->stale) {
audio_debug("FmodAudioManager: purging "<<path<< " from the cache.");
delete [] entry->data;
_sounds.erase(itor);
}
} else {
audio_debug("FmodAudioManager::dec_refcount: no such file "<<path);
}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::load
// Access: Private
// Description: Loads the specified file into memory.
// Returns NULL if an error occurs.
////////////////////////////////////////////////////////////////////
void* FmodAudioManager::
load(const Filename& filename, const size_t size) const {
// Check file type (based on filename suffix
string suffix = filename.get_extension();
std::transform(suffix.begin(), suffix.end(), suffix.begin(), tolower);
bool bSupported = false;
if (suffix == "wav" || suffix == "mp3" || suffix == "mid"
|| suffix == "rmi" || suffix == "midi") {
bSupported = true;
}
if (!bSupported) {
audio_error("FmodAudioManager::load: "<<filename
<<" is not a supported file format.");
audio_error("Supported formats are: WAV, MP3, MIDI");
return NULL;
}
// open the file.
string os_filename = filename.to_os_specific();
FILE *audioFile = fopen(os_filename.c_str(), "rb");
if (!audioFile) {
audio_error("File "<<filename<<" does not exist.");
return NULL;
}
// Read the entire file into memory.
char *buffer = new char[size];
if (buffer == NULL) {
audio_error("out-of-memory error while loading "<<filename);
fclose(audioFile);
return NULL;
}
long bytes_read = fread(buffer, size, 1, audioFile);
if (bytes_read != 1) {
audio_error("Read error while loading "<<filename);
fclose(audioFile);
delete [] buffer;
return NULL;
}
fclose(audioFile);
return buffer;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::get_file_size
// Access: Private
// Description: Calculates the size of the given file, in bytes.
////////////////////////////////////////////////////////////////////
size_t FmodAudioManager::
get_file_size(const Filename& filename) const {
// open the file.
string os_filename = filename.to_os_specific();
FILE *audioFile = fopen(os_filename.c_str(), "rb");
if (!audioFile) {
audio_error("File "<<filename<<" does not exist.");
return 0;
}
// Read the entire file into memory.
if (fseek(audioFile, 0, SEEK_END) != 0) {
audio_error("Seek error while loading "<<filename);
fclose(audioFile);
return 0;
}
size_t file_size = ftell(audioFile);
fclose(audioFile);
return file_size;
}
#endif //]

View File

@ -0,0 +1,93 @@
// Filename: fmodAudioManager.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_MANAGER_H__
#define __FMOD_AUDIO_MANAGER_H__
#include <pandabase.h>
#ifdef HAVE_FMOD //[
#include "audioManager.h"
class FmodAudioSound;
#include "filename.h"
#include "pmap.h"
#include "pset.h"
#include <fmod.h>
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<string, SoundCacheEntry > SoundMap;
SoundMap _sounds;
typedef pset<FmodAudioSound* > 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__ */

View File

@ -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 .
//
////////////////////////////////////////////////////////////////////

View File

@ -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 <pandabase.h>
#ifdef HAVE_FMOD //[
#include "fmodAudioSound.h"
#include "fmodAudioManager.h"
#include <cmath>
#ifndef NDEBUG //[
#define fmod_audio_debug(x) \
audio_debug("FmodAudioSound "<<" \""<<get_name()<<"\" "<< x )
#else //][
#define fmod_audio_debug(x) ((void)0)
#endif //]
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), _channel(-1) {
nassertv(!file_name.empty());
nassertv(audio_data != NULL);
audio_debug("FmodAudioSound(manager=0x"<<(void*)&manager
<<", file_name="<<file_name<<")");
}
FmodAudioSound::
~FmodAudioSound() {
fmod_audio_debug("~FmodAudioSound()");
this->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 "<<loop);
_loop_count = loop ? 0 : 1;
}
bool FmodAudioSound::get_loop() const {
fmod_audio_debug("get_loop() returning "<<(_loop_count==0));
return (_loop_count == 0);
}
void FmodAudioSound::set_loop_count(unsigned long loop_count) {
audio_error("FmodAudioSound::set_loop_count() -- not yet implemented");
fmod_audio_debug("set_loop_count() set to "<<loop_count);
_loop_count = loop_count;
}
unsigned long FmodAudioSound::get_loop_count() const {
fmod_audio_debug("get_loop_count() returning "<<_loop_count);
return _loop_count;
}
void FmodAudioSound::set_time(float start_time) {
if (start_time < 0.0f) {
fmod_audio_debug("set_time(): param "<<start_time<<" out of range.");
fmod_audio_debug("set_time(): clamping to zero.");
start_time = 0.0f;
} else if (start_time > _length) {
fmod_audio_debug("set_time(): param "<<start_time<<" out of range.");
fmod_audio_debug("set_time(): clamping to length ("<<_length<<".");
start_time = _length - 0.01;
}
// FMOD measures time in milliseconds, so scale up by 1000.
FSOUND_Stream_SetTime(_audio, start_time * 1000.0f);
}
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;
}
// 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 "<<current_time);
return current_time;
}
void FmodAudioSound::set_volume(float vol) {
if (vol < 0.0f) {
fmod_audio_debug("set_volume(): param "<<vol<<" out of range.");
fmod_audio_debug("set_volume(): clamping to zero.");
vol = 0.0f;
} else if (vol > 1.0f) {
fmod_audio_debug("set_volume(): param "<<vol<<" out of range.");
fmod_audio_debug("set_volume(): clamping to 1.0");
vol = 1.0f;
}
_volume = vol;
unsigned char new_volume = (unsigned char)(_volume*255.0f);
FSOUND_SetVolume(_channel, new_volume);
}
float FmodAudioSound::get_volume() const {
fmod_audio_debug("get_volume() returning "<<_volume);
return _volume;
}
void FmodAudioSound::set_balance(float bal) {
if (bal < -1.0f) {
fmod_audio_debug("set_balance(): param "<<bal<<" out of range.");
fmod_audio_debug("set_balance(): clamping to -1.0.");
bal = -1.0f;
} else if (bal > 1.0f) {
fmod_audio_debug("set_balance(): param "<<bal<<" out of range.");
fmod_audio_debug("set_balance(): clamping to 1.0");
bal = 1.0f;
}
_balance = bal;
unsigned char new_balance = (unsigned char)( (_balance+1.0f)*0.5f*255.0f);
FSOUND_SetPan(_channel, new_balance);
}
float FmodAudioSound::get_balance() const {
fmod_audio_debug("get_balance() returning "<<_balance);
return _balance;
}
void FmodAudioSound::set_active(bool active) {
fmod_audio_debug("set_active(active="<<active<<")");
if (!active) {
// Once looping works, a looping sound should be paused, not
// stopped. When the sound is activated again, it is unpaused.
this->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 //]

View File

@ -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 <pandabase.h>
#ifdef HAVE_FMOD //[
#include "audioSound.h"
class FmodAudioManager;
#include <fmod.h>
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__ */

View File

@ -0,0 +1,5 @@
/* Generated automatically by ppremake 1.11 from Sources.pp. */
/* ################################# DO NOT EDIT ########################### */
#include "fmod_audio_composite1.cxx"

View File

@ -0,0 +1,5 @@
#include "config_fmodAudio.cxx"
#include "fmodAudioManager.cxx"
#include "fmodAudioSound.cxx"

View File

@ -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