changed the sound code: added reduce sounds to and set finished event

This commit is contained in:
Dave Schuyler 2003-08-19 23:19:28 +00:00
parent 8f02530c64
commit 24b2117dbc
20 changed files with 554 additions and 246 deletions

View File

@ -716,7 +716,8 @@ class ShowBase(DirectObject.DirectObject):
self.musicManagerIsValid=self.musicManager!=None \
and self.musicManager.isValid()
if self.musicManagerIsValid:
self.musicManager.setMutuallyExclusive(1) # ensure only 1 midi song is playing at a time
# ensure only 1 midi song is playing at a time:
self.musicManager.setConcurrentSoundLimit(1)
self.musicManager.setActive(self.musicActive)
# enableMusic/enableSoundEffects are meant to be called in response to a user request

View File

@ -79,7 +79,6 @@ create_AudioManager() {
if (!am->is_valid()) {
am = create_NullAudioManger();
}
am->_bExclusive = false;
return am;
}
@ -99,7 +98,3 @@ get_null_sound() {
return _null_sound;
}
void AudioManager::
set_mutually_exclusive(bool bExclusive) {
_bExclusive = bExclusive;
}

View File

@ -38,6 +38,14 @@ PUBLISHED:
static PT(AudioManager) create_AudioManager();
virtual ~AudioManager() {}
// If you're interested in knowing whether this audio manager
// is valid, here's the call to do it. It is not necessary
// to check whether the audio manager is valid before making other
// calls. You are free to use an invalid sound manager, you
// may get silent sounds from it though. The sound manager and
// the sounds it creates should not crash the application even
// when the objects are not valid.
virtual bool is_valid() = 0;
// Get a sound:
@ -51,12 +59,8 @@ PUBLISHED:
// in its pool/cache.
virtual void uncache_sound(const string& file_name) = 0;
virtual void clear_cache() = 0;
virtual void set_cache_limit(int count) = 0;
virtual int get_cache_limit() = 0;
// if set, turn off any currently-playing sounds before playing
// a new one (useful for midi songs)
void set_mutually_exclusive(bool bExclusive);
virtual void set_cache_limit(unsigned int count) = 0;
virtual unsigned int get_cache_limit() const = 0;
// Control volume:
// FYI:
@ -65,7 +69,7 @@ PUBLISHED:
// 0 = minimum; 1.0 = maximum.
// inits to 1.0.
virtual void set_volume(float volume) = 0;
virtual float get_volume() = 0;
virtual float get_volume() const = 0;
// Turn the manager on or off.
// If you play a sound while the manager is inactive, it won't start.
@ -76,14 +80,42 @@ PUBLISHED:
// they will start playing from the begining of their loop.
// inits to true.
virtual void set_active(bool flag) = 0;
virtual bool get_active() = 0;
virtual bool get_active() const = 0;
// This controls the number of sounds that you allow at once. This
// is more of a user choice -- it avoids talk over and the creation
// of a cacophony.
// It can also be used to help performance.
// 0 == unlimited.
// 1 == mutually exclusive (one sound at a time). Which is an example of:
// n == allow n sounds to be playing at the same time.
virtual void set_concurrent_sound_limit(unsigned int limit = 0) = 0;
virtual unsigned int get_concurrent_sound_limit() const = 0;
// This is likely to be a utility function for the concurrent_sound_limit
// options. It is exposed as an API, because it's reasonable that it
// may be useful to be here. It reduces the number of concurrently
// playing sounds to count by some implementation specific means.
// If the number of sounds currently playing is at or below count then
// there is no effect.
virtual void reduce_sounds_playing_to(unsigned int count) = 0;
// Stop playback on all sounds managed by this manager.
// This is effectively the same as reduce_sounds_playing_to(0), but
// this call may be for efficient on some implementations.
virtual void stop_all_sounds() = 0;
public:
static void register_AudioManager_creator(Create_AudioManager_proc* proc);
protected:
friend class AudioSound;
// Avoid adding data members (instance variables) to this mostly abstract
// base class. This allows implementors of various sound systems the
// best flexibility.
static Create_AudioManager_proc* _create_AudioManager;
bool _bExclusive;
PT(AudioSound) _null_sound;
AudioManager() {

View File

@ -84,6 +84,11 @@ PUBLISHED:
// inits to manager's state.
virtual void set_active(bool flag=true) = 0;
virtual bool get_active() const = 0;
// Set (or clear) the event that will be thrown when the sound
// finishes playing. To clear the event, pass an empty string.
virtual void set_finished_event(const string& event) = 0;
virtual const string& get_finished_event() const = 0;
// There is no set_name(), this is intentional.
virtual const string& get_name() const = 0;

View File

@ -86,7 +86,7 @@ clear_cache() {
// Description:
////////////////////////////////////////////////////////////////////
void NullAudioManager::
set_cache_limit(int) {
set_cache_limit(unsigned int) {
// intentionally blank.
}
@ -95,8 +95,8 @@ set_cache_limit(int) {
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
int NullAudioManager::
get_cache_limit() {
unsigned int NullAudioManager::
get_cache_limit() const {
// intentionally blank.
return 0;
}
@ -117,7 +117,7 @@ set_volume(float) {
// Description:
////////////////////////////////////////////////////////////////////
float NullAudioManager::
get_volume() {
get_volume() const {
return 0;
}
@ -137,6 +137,46 @@ set_active(bool) {
// Description:
////////////////////////////////////////////////////////////////////
bool NullAudioManager::
get_active() {
get_active() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: NullAudioManager::set_concurrent_sound_limit
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void NullAudioManager::
set_concurrent_sound_limit(unsigned int) {
// intentionally blank.
}
////////////////////////////////////////////////////////////////////
// Function: NullAudioManager::get_concurrent_sound_limit
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
unsigned int NullAudioManager::
get_concurrent_sound_limit() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: NullAudioManager::reduce_sounds_playing_to
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void NullAudioManager::
reduce_sounds_playing_to(unsigned int) {
// intentionally blank.
}
////////////////////////////////////////////////////////////////////
// Function: NullAudioManager::stop_all_sounds
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void NullAudioManager::
stop_all_sounds() {
// intentionally blank.
}

View File

@ -37,14 +37,21 @@ public:
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_cache_limit(unsigned int);
virtual unsigned int get_cache_limit() const;
virtual void set_volume(float);
virtual float get_volume();
virtual float get_volume() const;
virtual void set_active(bool);
virtual bool get_active();
virtual bool get_active() const;
virtual void set_concurrent_sound_limit(unsigned int limit);
virtual unsigned int get_concurrent_sound_limit() const;
virtual void reduce_sounds_playing_to(unsigned int count);
virtual void stop_all_sounds();
};
#endif /* __NULL_AUDIO_MANAGER_H__ */

View File

@ -20,6 +20,10 @@
#include "nullAudioSound.h"
namespace {
static const string blank="";
}
NullAudioSound::NullAudioSound() {
// Intentionally blank.
}
@ -84,8 +88,15 @@ bool NullAudioSound::get_active() const {
return false;
}
void NullAudioSound::set_finished_event(const string& event) {
// Intentionally blank.
}
const string& NullAudioSound::get_finished_event() const {
return blank;
}
const string& NullAudioSound::get_name() const {
static const string blank="";
return blank;
}

View File

@ -54,6 +54,9 @@ public:
void set_active(bool);
bool get_active() const;
void set_finished_event(const string& event);
const string& get_finished_event() const;
const string& get_name() const;

View File

@ -54,6 +54,7 @@ FmodAudioManager() {
_active = audio_active;
_cache_limit = audio_cache_limit;
_concurrent_sound_limit = 0;
// Initialize FMOD, if this is the first manager created.
_is_valid = true;
@ -62,20 +63,19 @@ FmodAudioManager() {
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;
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;
audio_error("Fmod initialization failure.");
_is_valid = false;
break;
}
}
while(0);
while(0); // curious -- why is there a non-loop here?
}
// increment regardless of whether an error has occured -- the
@ -222,7 +222,7 @@ get_sound(const string &file_name) {
// Build a new AudioSound from the audio data.
PT(AudioSound) audioSound = 0;
PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, stream, path,
length);
length);
fmodAudioSound->set_active(_active);
_soundsOnLoan.insert(fmodAudioSound);
audioSound = fmodAudioSound;
@ -263,7 +263,7 @@ uncache_sound(const string& file_name) {
// If the refcount is already zero, it can be
// purged right now!
audio_debug("FmodAudioManager::uncache_sound: purging "<<path
<< " from the cache.");
<< " from the cache.");
delete [] entry->data;
// Erase the sound from the LRU list as well.
@ -324,7 +324,7 @@ most_recently_used(const string& path) {
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::clear_cache
// Access: Public
// Description:
// Description: Clear out the sound cache.
////////////////////////////////////////////////////////////////////
void FmodAudioManager::
clear_cache() {
@ -340,7 +340,7 @@ clear_cache() {
SoundCacheEntry *entry = &(*itor).second;
if (entry->refcount == 0) {
audio_debug("FmodAudioManager::clear_cache: purging "<< (*itor).first
<< " from the cache.");
<< " from the cache.");
delete [] entry->data;
// Erase the sound from the LRU list as well.
@ -361,18 +361,15 @@ clear_cache() {
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::set_cache_limit
// Access: Public
// Description:
// Description: Set the number of sounds that the cache can hold.
////////////////////////////////////////////////////////////////////
void FmodAudioManager::
set_cache_limit(int count) {
audio_debug("FmodAudioManager::set_cache_limit(count="
<<count<<")");
set_cache_limit(unsigned int count) {
audio_debug("FmodAudioManager::set_cache_limit(count="<<count<<")");
assert(is_valid());
while (_lru.size() > (unsigned int) count) {
while (_lru.size() > count) {
uncache_a_sound();
}
_cache_limit = count;
assert(is_valid());
}
@ -385,7 +382,7 @@ set_cache_limit(int count) {
int FmodAudioManager::
get_cache_limit() {
audio_debug("FmodAudioManager::get_cache_limit() returning "
<<_cache_limit);
<<_cache_limit);
return _cache_limit;
}
@ -451,18 +448,56 @@ get_active() {
return _active;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::set_concurrent_sound_limit
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FmodAudioManager::
set_concurrent_sound_limit(unsigned int limit) {
_concurrent_sound_limit = limit;
reduce_sounds_playing_to(_concurrent_sound_limit);
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::get_concurrent_sound_limit
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
unsigned int FmodAudioManager::
get_concurrent_sound_limit() const {
return _concurrent_sound_limit;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::reduce_sounds_playing_to
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void FmodAudioManager::
reduce_sounds_playing_to(unsigned int count) {
// This is an example from Miles audio, this should be done for fmod:
//int limit = _sounds_playing.size() - count;
//while (limit-- > 0) {
// SoundsPlaying::iterator sound = _sounds_playing.begin();
// assert(sound != _sounds_playing.end());
// (**sound).stop();
//}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioManager::stop_all_sounds
// Access: Public
// Description: Stop playback on all sounds managed by this manager.
////////////////////////////////////////////////////////////////////
void FmodAudioManager::
stop_all_sounds(void) {
stop_all_sounds() {
audio_debug("FmodAudioManager::stop_all_sounds()");
AudioSet::iterator i=_soundsOnLoan.begin();
for (; i!=_soundsOnLoan.end(); ++i) {
if((**i).status()==AudioSound::PLAYING)
if ((**i).status()==AudioSound::PLAYING) {
(**i).stop();
}
}
}
@ -484,7 +519,7 @@ inc_refcount(const string& file_name) {
entry->refcount++;
entry->stale = false; // definitely not stale!
audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
<< entry->refcount);
<< entry->refcount);
}
////////////////////////////////////////////////////////////////////
@ -502,7 +537,7 @@ dec_refcount(const string& file_name) {
SoundCacheEntry *entry = &(*itor).second;
entry->refcount--;
audio_debug("FmodAudioManager: "<<path<<" has a refcount of "
<< entry->refcount);
<< entry->refcount);
if (entry->refcount == 0 && entry->stale) {
audio_debug("FmodAudioManager::dec_refcount: purging "<<path<< " from the cache.");
delete [] entry->data;
@ -537,7 +572,7 @@ load(const Filename& filename, size_t &size) const {
}
if (!bSupported) {
audio_error("FmodAudioManager::load: "<<filename
<<" is not a supported file format.");
<<" is not a supported file format.");
audio_error("Supported formats are: WAV, MP3, MIDI");
return NULL;
}

View File

@ -20,7 +20,7 @@
#ifndef __FMOD_AUDIO_MANAGER_H__
#define __FMOD_AUDIO_MANAGER_H__
#include <pandabase.h>
#include "pandabase.h"
#ifdef HAVE_FMOD //[
#include "audioManager.h"
@ -30,7 +30,7 @@ class FmodAudioSound;
#include "pmap.h"
#include "pset.h"
#include <fmod.h>
#include <fmod.h> // Is fmod.h really a system file? I think maybe this should be "fmod.h".
class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
// All of these methods are stubbed out to some degree.
@ -46,7 +46,7 @@ public:
virtual PT(AudioSound) get_sound(const string&);
virtual void uncache_sound(const string&);
virtual void clear_cache();
virtual void set_cache_limit(int);
virtual void set_cache_limit(unsigned int count);
virtual int get_cache_limit();
// Indicates that the given sound was the most recently used.
@ -60,7 +60,13 @@ public:
virtual void set_active(bool);
virtual bool get_active();
void stop_all_sounds();
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 stop_all_sounds();
protected:
// increment or decrement the refcount of the given file's cache entry.
@ -80,6 +86,7 @@ private:
typedef pset<FmodAudioSound* > AudioSet;
// The offspring of this manager:
AudioSet _soundsOnLoan;
unsigned int _concurrent_sound_limit;
// The Least Recently Used mechanism:
typedef pdeque<string> LRU;

View File

@ -34,14 +34,14 @@
FmodAudioSound::
FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
string file_name, float length)
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<<")");
<<", file_name="<<file_name<<")");
}
FmodAudioSound::
@ -56,16 +56,14 @@ 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();
}
if (_manager->stop_a_sound()) {
// stop another sound that parent mgr is playing
_manager->stop_all_sounds();
}
// Play the stream, but start it paused so we can set the volume and
// panning first.
@ -92,7 +90,9 @@ play() {
// 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));
while (!FSOUND_IsPlaying(_channel)) {
// intentinaly empty loop.
}
}
void FmodAudioSound::stop() {

View File

@ -69,6 +69,9 @@ public:
// inits to manager's state.
void set_active(bool active=true);
bool get_active() const;
void set_finished_event(const string& event);
const string& get_finished_event() const;
const string& get_name() const;
@ -92,7 +95,7 @@ private:
int _channel;
FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
string file_name, float length=0.0f);
string file_name, float length=0.0f);
// forbidden functions!
FmodAudioSound(const FmodAudioSound& rhs) {}

View File

@ -32,54 +32,49 @@
int MilesAudioManager::_active_managers = 0;
HDLSFILEID MilesAudioManager::_dls_field = NULL;
bool bMilesShutdownCalled = false;
bool bMilesShutdownAtExitRegistered = false;
PT(AudioManager) Create_AudioManager() {
audio_debug("Create_AudioManager() Miles.");
return new MilesAudioManager();
}
void fMilesShutdown(void) {
if(bMilesShutdownCalled)
return;
void CustomMilesShutdown() {
if (bMilesShutdownCalled) {
return;
}
bMilesShutdownCalled = true;
bMilesShutdownCalled = true;
if (MilesAudioManager::_dls_field!=NULL) {
HDLSDEVICE dls= NULL;
AIL_quick_handles(0, 0, &dls);
if(dls!=NULL) {
AIL_DLS_unload(dls,MilesAudioManager::_dls_field);
}
#ifndef NDEBUG //[
// Clear _dls_field in debug version (for assert in ctor):
MilesAudioManager::_dls_field = NULL;
#endif //]
if (MilesAudioManager::_dls_field!=NULL) {
HDLSDEVICE dls= NULL;
AIL_quick_handles(0, 0, &dls);
if (dls!=NULL) {
AIL_DLS_unload(dls,MilesAudioManager::_dls_field);
}
#ifndef NDEBUG //[
// Clear _dls_field in debug version (for assert in ctor):
MilesAudioManager::_dls_field = NULL;
#endif //]
}
#define SHUTDOWN_HACK
// if python crashes, the midi notes are left on,
// so we need to turn them off. Unfortunately
// in Miles 6.5, AIL_quick_shutdown() crashes
// when it's called from atexit after a python crash, probably
// because mss32.dll has already been unloaded
// workaround: use these internal values in the miles struct
// to reset the win32 midi ourselves
#ifdef SHUTDOWN_HACK
HMDIDRIVER hMid=NULL;
AIL_quick_handles(0, &hMid, 0);
if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
midiOutReset(hMid->hMidiOut);
midiOutClose(hMid->hMidiOut);
}
#else
audio_debug(" AIL_quick_shutdown()");
AIL_quick_shutdown();
#endif
#define SHUTDOWN_HACK
// if python crashes, the midi notes are left on,
// so we need to turn them off. Unfortunately
// in Miles 6.5, AIL_quick_shutdown() crashes
// when it's called from atexit after a python crash, probably
// because mss32.dll has already been unloaded
// workaround: use these internal values in the miles struct
// to reset the win32 midi ourselves
#ifdef SHUTDOWN_HACK
HMDIDRIVER hMid=NULL;
AIL_quick_handles(0, &hMid, 0);
if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
midiOutReset(hMid->hMidiOut);
midiOutClose(hMid->hMidiOut);
}
#else
audio_debug(" AIL_quick_shutdown()");
AIL_quick_shutdown();
#endif
}
////////////////////////////////////////////////////////////////////
@ -95,8 +90,9 @@ MilesAudioManager() {
_active = audio_active;
_volume = audio_volume;
_cache_limit = audio_cache_limit;
_concurrent_sound_limit = 0;
_is_valid = true;
_bHasMidiSounds = false;
_hasMidiSounds = false;
if (_active_managers==0) {
S32 use_digital=(audio_play_wave || audio_play_mp3)?1:0;
S32 use_MIDI=(audio_play_midi)?1:0;
@ -146,7 +142,7 @@ MilesAudioManager() {
audio_info(" using Miles software midi");
}
} else {
audio_info(" using Miles hardware midi");
audio_info(" using Miles hardware midi");
}
if (use_vfs) {
@ -169,9 +165,10 @@ MilesAudioManager() {
if (_is_valid) {
assert(is_valid());
if(!bMilesShutdownAtExitRegistered) {
bMilesShutdownAtExitRegistered = true;
atexit(fMilesShutdown);
static bool atexit_registered = false;
if(!atexit_registered) {
atexit_registered = true;
atexit(CustomMilesShutdown);
}
}
}
@ -185,7 +182,7 @@ MilesAudioManager::
~MilesAudioManager() {
audio_debug("MilesAudioManager::~MilesAudioManager()");
// Be sure to delete associated sounds before deleting the manager:
nassertv(_soundsOnLoan.empty());
nassertv(_sounds_on_loan.empty());
clear_cache();
--_active_managers;
audio_debug(" _active_managers="<<_active_managers);
@ -238,10 +235,8 @@ is_valid() {
HAUDIO MilesAudioManager::
load(Filename file_name) {
HAUDIO audio;
if (use_vfs) {
audio = AIL_quick_load(file_name.c_str());
} else {
string stmp = file_name.to_os_specific();
audio_debug(" \"" << stmp << "\"");
@ -318,11 +313,11 @@ get_sound(const string& file_name) {
=new MilesAudioSound(this, audio, (*si).first);
nassertr(milesAudioSound, 0);
milesAudioSound->set_active(_active);
_soundsOnLoan.insert(milesAudioSound);
_sounds_on_loan.insert(milesAudioSound);
audioSound=milesAudioSound;
}
_bHasMidiSounds |= (file_name.find(".mid")!=string::npos);
_hasMidiSounds |= (file_name.find(".mid")!=string::npos);
audio_debug(" returning 0x" << (void*)audioSound);
assert(is_valid());
return audioSound;
@ -406,7 +401,7 @@ most_recently_used(const string& path) {
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::clear_cache
// Access: Public
// Description:
// Description: Clear out the sound cache.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
clear_cache() {
@ -424,14 +419,13 @@ clear_cache() {
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::set_cache_limit
// Access: Public
// Description:
// Description: Set the number of sounds that the cache can hold.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
set_cache_limit(int count) {
audio_debug("MilesAudioManager::set_cache_limit(count="
<<count<<")");
set_cache_limit(unsigned int count) {
audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
assert(is_valid());
while (_lru.size() > (unsigned int) count) {
while (_lru.size() > count) {
uncache_a_sound();
}
_cache_limit=count;
@ -443,8 +437,8 @@ set_cache_limit(int count) {
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
int MilesAudioManager::
get_cache_limit() {
unsigned int MilesAudioManager::
get_cache_limit() const {
audio_debug("MilesAudioManager::get_cache_limit() returning "
<<_cache_limit);
return _cache_limit;
@ -459,7 +453,7 @@ void MilesAudioManager::
release_sound(MilesAudioSound* audioSound) {
audio_debug("MilesAudioManager::release_sound(audioSound=\""
<<audioSound->get_name()<<"\")");
_soundsOnLoan.erase(audioSound);
_sounds_on_loan.erase(audioSound);
}
////////////////////////////////////////////////////////////////////
@ -473,53 +467,43 @@ set_volume(float volume) {
if (_volume!=volume) {
_volume = volume;
// Tell our AudioSounds to adjust:
AudioSet::iterator i=_soundsOnLoan.begin();
for (; i!=_soundsOnLoan.end(); ++i) {
AudioSet::iterator i=_sounds_on_loan.begin();
for (; i!=_sounds_on_loan.end(); ++i) {
(**i).set_volume((**i).get_volume());
}
}
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::force_midi_reset
// Access: Public
// Description: ?????.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
stop_all_sounds(void) {
audio_debug("MilesAudioManager::stop_all_sounds()");
AudioSet::iterator i=_soundsOnLoan.begin();
for (; i!=_soundsOnLoan.end(); ++i) {
if((**i).status()==AudioSound::PLAYING)
(**i).stop();
force_midi_reset() {
if (!miles_audio_force_midi_reset) {
audio_debug("MilesAudioManager::skipping force_midi_reset");
return;
}
audio_debug("MilesAudioManager::force_midi_reset");
if(_bHasMidiSounds) {
forceMidiReset();
// sometimes Miles seems to leave midi notes hanging, even after stop is called,
// so perform an explicit reset using winMM.dll calls, just to ensure silence.
HMDIDRIVER hMid=NULL;
AIL_quick_handles(0, &hMid, 0);
if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
audio_debug("MilesAudioManager::calling midiOutReset");
midiOutReset(hMid->hMidiOut);
}
}
void MilesAudioManager::
forceMidiReset(void) {
if(!miles_audio_force_midi_reset) {
audio_debug("MilesAudioManager::skipping forceMidiReset");
return;
}
audio_debug("MilesAudioManager::ForceMidiReset");
// sometimes Miles seems to leave midi notes hanging, even after stop is called,
// so perform an explicit reset using winMM.dll calls, just to ensure silence.
HMDIDRIVER hMid=NULL;
AIL_quick_handles(0, &hMid, 0);
if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
audio_debug("MilesAudioManager::calling midiOutReset");
midiOutReset(hMid->hMidiOut);
}
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::get_volume
// Access: Public
// Description: get the overall volume
////////////////////////////////////////////////////////////////////
float MilesAudioManager::
get_volume() {
get_volume() const {
audio_debug("MilesAudioManager::get_volume() returning "<<_volume);
return _volume;
}
@ -535,13 +519,13 @@ set_active(bool active) {
if (_active!=active) {
_active=active;
// Tell our AudioSounds to adjust:
AudioSet::iterator i=_soundsOnLoan.begin();
for (; i!=_soundsOnLoan.end(); ++i) {
AudioSet::iterator i=_sounds_on_loan.begin();
for (; i!=_sounds_on_loan.end(); ++i) {
(**i).set_active(_active);
}
if((!_active) && _bHasMidiSounds) {
forceMidiReset();
if((!_active) && _hasMidiSounds) {
force_midi_reset();
}
}
}
@ -552,11 +536,86 @@ set_active(bool active) {
// Description:
////////////////////////////////////////////////////////////////////
bool MilesAudioManager::
get_active() {
get_active() const {
audio_debug("MilesAudioManager::get_active() returning "<<_active);
return _active;
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::starting_sound
// Access:
// Description: Inform the manager that a sound is about to play.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
starting_sound(MilesAudioSound* audio) {
if (_concurrent_sound_limit) {
reduce_sounds_playing_to(_concurrent_sound_limit);
}
_sounds_playing.insert(audio);
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::stoping_sound
// Access:
// Description: Inform the manager that a sound is finished or
// someone called stop on the sound (this should not
// be called if a sound is only paused).
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
stoping_sound(MilesAudioSound* audio) {
_sounds_playing.erase(audio);
if (_hasMidiSounds && _sounds_playing.size() == 0) {
force_midi_reset();
}
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::set_concurrent_sound_limit
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
set_concurrent_sound_limit(unsigned int limit) {
_concurrent_sound_limit = limit;
reduce_sounds_playing_to(_concurrent_sound_limit);
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::get_concurrent_sound_limit
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
unsigned int MilesAudioManager::
get_concurrent_sound_limit() const {
return _concurrent_sound_limit;
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::reduce_sounds_playing_to
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
reduce_sounds_playing_to(unsigned int count) {
int limit = _sounds_playing.size() - count;
while (limit-- > 0) {
SoundsPlaying::iterator sound = _sounds_playing.begin();
assert(sound != _sounds_playing.end());
(**sound).stop();
}
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::stop_all_sounds
// Access: Public
// Description: Stop playback on all sounds managed by this manager.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
stop_all_sounds() {
audio_debug("MilesAudioManager::stop_all_sounds()");
reduce_sounds_playing_to(0);
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::get_registry_entry
// Access: private

View File

@ -20,7 +20,7 @@
#ifndef __MILES_AUDIO_MANAGER_H__ //[
#define __MILES_AUDIO_MANAGER_H__
#include <pandabase.h>
#include "pandabase.h"
#ifdef HAVE_RAD_MSS //[
#include "audioManager.h"
@ -43,16 +43,21 @@ public:
PT(AudioSound) get_sound(const string& file_name);
void uncache_sound(const string& file_name);
void clear_cache();
void set_cache_limit(int count);
int get_cache_limit();
void set_cache_limit(unsigned int count);
unsigned int get_cache_limit() const;
void set_volume(float volume);
float get_volume();
float get_volume() const;
void set_active(bool active);
bool get_active();
bool get_active() const;
void set_concurrent_sound_limit(unsigned int limit = 0);
unsigned int get_concurrent_sound_limit() const;
void reduce_sounds_playing_to(unsigned int count);
void stop_all_sounds();
void forceMidiReset();
// Optional Downloadable Sound field for software midi:
// made public so C atexit fn can access it
@ -65,7 +70,11 @@ private:
typedef pset<MilesAudioSound* > AudioSet;
// The offspring of this manager:
AudioSet _soundsOnLoan;
AudioSet _sounds_on_loan;
typedef pset<MilesAudioSound* > SoundsPlaying;
// The sounds from this manager that are currently playing:
SoundsPlaying _sounds_playing;
// The Least Recently Used mechanism:
typedef pdeque<const string* > LRU;
@ -76,9 +85,10 @@ private:
int _cache_limit;
// keep a count for startup and shutdown:
static int _active_managers;
unsigned int _concurrent_sound_limit;
bool _is_valid;
bool _bHasMidiSounds;
bool _hasMidiSounds;
HAUDIO load(Filename file_name);
// Tell the manager that the sound dtor was called.
@ -87,6 +97,9 @@ private:
void most_recently_used(const string& path);
void uncache_a_sound();
void starting_sound(MilesAudioSound* audio);
void stoping_sound(MilesAudioSound* audio);
// utility function that should be moved to another class:
bool get_registry_entry(HKEY base,
const char* subKeyName,
@ -95,6 +108,8 @@ private:
// get the default dls file path:
void get_gm_file_path(string& result);
void force_midi_reset();
// These are "callback" functions that implement vfs-style I/O for
// Miles.
static U32 AILCALLBACK vfs_open_callback(const char *filename, U32 *file_handle);
@ -102,7 +117,7 @@ private:
static S32 AILCALLBACK vfs_seek_callback(U32 file_handle, S32 offset, U32 type);
static void AILCALLBACK vfs_close_callback(U32 file_handle);
friend MilesAudioSound;
friend class MilesAudioSound;
};
EXPCL_MILES_AUDIO PT(AudioManager) Create_AudioManager();

View File

@ -16,9 +16,10 @@
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "pandabase.h"
#ifdef HAVE_RAD_MSS //[
#include "throw_event.h"
#include "milesAudioSound.h"
#include "milesAudioManager.h"
@ -45,6 +46,72 @@
return 'x'; // bad.
}
}
AILSEQUENCECB sequence_callback = 0;
AILSAMPLECB sample_callback = 0;
const user_data_index = 7;
void AILCALLBACK
pandaAudioAilCallback_Sequence(HSEQUENCE S) {
assert(S);
audio_debug("pandaAudioAilCallback_Sequence(HSEQUENCE="<<((void*)S)<<")");
MilesAudioSound* sound = (MilesAudioSound*)AIL_sequence_user_data(
S, user_data_index);
assert(sound);
sound->finished();
if (sequence_callback) {
sequence_callback(S);
}
}
void AILCALLBACK
pandaAudioAilCallback_Sample(HSAMPLE S) {
assert(S);
audio_debug("pandaAudioAilCallback_Sample(HSAMPLE="<<((void*)S)<<")");
MilesAudioSound* sound = (MilesAudioSound*)AIL_sample_user_data(
S, user_data_index);
assert(sound);
sound->finished();
if (sample_callback) {
sample_callback(S);
}
}
void
panda_AIL_quick_set_finished_callback(HAUDIO audio, MilesAudioSound* sound) {
audio_debug("panda_AIL_quick_set_finished_callback(audio="<<((void*)audio)
<<", sound="<<((void*)sound)<<")");
if (!audio || !sound) {
return;
}
AIL_lock();
if (audio->handle != NULL) {
switch (audio->type) {
case AIL_QUICK_XMIDI_TYPE:
audio_debug(" AIL_register_sequence_callback");
AIL_set_sequence_user_data(
(HSEQUENCE)audio->handle, user_data_index, (long)sound);
sequence_callback=AIL_register_sequence_callback(
(HSEQUENCE)audio->handle, pandaAudioAilCallback_Sequence);
audio_debug( "AILCALLBACK "<<((void*)sequence_callback));
break;
case AIL_QUICK_DIGITAL_TYPE:
case AIL_QUICK_MPEG_DIGITAL_TYPE:
audio_debug(" AIL_register_EOS_callback");
AIL_set_sample_user_data(
(HSAMPLE)audio->handle, user_data_index, (long)sound);
sample_callback=AIL_register_EOS_callback(
(HSAMPLE)audio->handle, pandaAudioAilCallback_Sample);
audio_debug(" AILCALLBACK "<<((void*)sample_callback));
break;
default:
audio_debug(" unknown audio type");
break;
}
}
AIL_unlock();
}
}
#define miles_audio_debug(x) \
@ -72,6 +139,7 @@ MilesAudioSound(MilesAudioManager* manager,
MilesAudioSound::
~MilesAudioSound() {
miles_audio_debug("~MilesAudioSound()");
stop();
_manager->release_sound(this);
AIL_quick_unload(_audio);
}
@ -86,12 +154,14 @@ play() {
miles_audio_debug("play()");
if (_active) {
if(_manager->_bExclusive) {
// stop any other sound that parent mgr is playing
_manager->stop_all_sounds();
if (status() == AudioSound::PLAYING) {
stop();
}
_manager->starting_sound(this);
// Start playing:
if (AIL_quick_play(_audio, _loop_count)) {
panda_AIL_quick_set_finished_callback(_audio, this);
assert(status()==PLAYING);
audio_debug(" started sound " << _file_name );
} else {
audio_debug(" sound " << _file_name<<" failed to start, err: " <<AIL_last_error());
@ -105,27 +175,25 @@ play() {
void MilesAudioSound::
stop() {
#if 0
if(_file_name.find(".mid")!=string::npos) {
miles_audio_debug("stop() midi");
}
#endif
miles_audio_debug("stopping snd " << _file_name);
_paused=false;
miles_audio_debug("stop()");
_manager->stoping_sound(this);
// The _paused flag should not be cleared here. _paused is not like
// the Pause button on a cd/dvd player. It is used as a flag to say
// that it was looping when it was set inactive. There is no need to
// make this symetrical with play(). set_active() is the 'owner' of
// _paused. play() accesses _paused to help in the situation where
// someone calls play on an inactive sound().
// removing --> _paused=false;
AIL_quick_halt(_audio);
}
void MilesAudioSound::
halt() {
#if 0
if(_file_name.find(".mid")!=string::npos) {
miles_audio_debug("halt() midi");
int i=1;
finished() {
miles_audio_debug("finished()");
_manager->stoping_sound(this);
if (!_finished_event.empty()) {
throw_event(_finished_event);
}
#endif
miles_audio_debug("halt()");
AIL_quick_halt(_audio);
}
void MilesAudioSound::
@ -154,7 +222,7 @@ set_loop_count(unsigned long loop_count) {
// need to stop and start the sound, feel free. Or, maybe I'll spend
// time on it in the future. Please set the loop option before starting
// the sound.
halt();
stop();
play();
}
}
@ -234,43 +302,6 @@ get_volume() const {
return _volume;
}
void MilesAudioSound::
set_active(bool active) {
miles_audio_debug("set_active(active="<<active<<")");
if (_active!=active) {
_active=active;
if (_active) {
// ...activate the sound.
if (_paused
&&
_loop_count==0) {
// ...this sound was looping when it was paused.
_paused=false;
play();
}
} else {
// ...deactivate the sound.
if (status()==PLAYING) {
if (_loop_count==0) {
// ...we're pausing a looping sound.
_paused=true;
}
// unlike the user fn stop(), halt() does NOT alter the 'paused' status
// this is important, dont want to 'stop' infin looping sounds unless user
// explicitly uses "stop()"
halt();
}
}
}
}
bool MilesAudioSound::
get_active() const {
miles_audio_debug("get_active() returning "<<_active);
return _active;
}
void MilesAudioSound::
set_balance(float balance_right) {
miles_audio_debug("set_balance(balance_right="<<balance_right<<")");
@ -327,6 +358,51 @@ length() const {
return _length;
}
void MilesAudioSound::
set_active(bool active) {
miles_audio_debug("set_active(active="<<active<<")");
if (_active!=active) {
_active=active;
if (_active) {
// ...activate the sound.
if (_paused
&&
_loop_count==0) {
// ...this sound was looping when it was paused.
_paused=false;
play();
}
} else {
// ...deactivate the sound.
if (status()==PLAYING) {
if (_loop_count==0) {
// ...we're pausing a looping sound.
_paused=true;
}
stop();
}
}
}
}
bool MilesAudioSound::
get_active() const {
miles_audio_debug("get_active() returning "<<_active);
return _active;
}
void MilesAudioSound::
set_finished_event(const string& event) {
miles_audio_debug("set_finished_event(event="<<event<<")");
_finished_event = event;
}
const string& MilesAudioSound::
get_finished_event() const {
miles_audio_debug("get_finished_event() returning "<<_finished_event);
return _finished_event;
}
const string& MilesAudioSound::
get_name() const {
//audio_debug("MilesAudioSound::get_name() returning "<<_file_name);

View File

@ -83,6 +83,12 @@ public:
// inits to manager's state.
void set_active(bool active=true);
bool get_active() const;
// This is the string that throw_event() will throw
// when the sound finishes playing. It is not triggered
// when the sound is stopped with stop().
void set_finished_event(const string& event);
const string& get_finished_event() const;
const string& get_name() const;
@ -91,11 +97,7 @@ public:
AudioSound::SoundStatus status() const;
protected:
// halt is like stop(), except it should not be called by the user.
// halt() does not change the "paused" status of a sound, it just stops
// it from playing. This is useful when the sound needs to be deactivated
void halt(void);
void finished();
private:
HAUDIO _audio;
@ -104,14 +106,28 @@ private:
float _balance; // -1..1
mutable float _length; // in seconds.
unsigned long _loop_count;
// This is the string that throw_event() will throw
// when the sound finishes playing. It is not triggered
// when the sound is stopped with stop().
string _finished_event;
string _file_name;
// _active is for things like a 'turn off sound effects' in
// a preferences pannel.
// _active is not about whether a sound is currently playing.
// Use status() for info on whether the sound is playing.
bool _active;
// _paused is not like the Pause button on a cd/dvd player.
// It is used as a flag to say that the sound was looping when
// itwas set inactive.
bool _paused;
MilesAudioSound(MilesAudioManager* manager,
HAUDIO audio, string file_name, float length=0.0f);
friend class MilesAudioManager;
};

View File

@ -16,15 +16,15 @@
//
////////////////////////////////////////////////////////////////////
#include <bamReader.h>
#include <bamWriter.h>
#include <compose_matrix.h>
#include <datagram.h>
#include <datagramIterator.h>
#include <event.h>
#include <fftCompressor.h>
#include <indent.h>
#include <throw_event.h>
#include "bamReader.h"
#include "bamWriter.h"
#include "compose_matrix.h"
#include "datagram.h"
#include "datagramIterator.h"
#include "event.h"
#include "fftCompressor.h"
#include "indent.h"
#include "throw_event.h"
#include "animBundle.h"
#include "animBundleNode.h"

View File

@ -19,7 +19,7 @@
#ifndef THROW_EVENT_H
#define THROW_EVENT_H
#include <pandabase.h>
#include "pandabase.h"
#include "eventQueue.h"
#include "pt_Event.h"

View File

@ -19,8 +19,8 @@
#include "lerp.h"
#include <clockObject.h>
#include <throw_event.h>
#include "clockObject.h"
#include "throw_event.h"
TypeHandle Lerp::_type_handle;
TypeHandle AutonomousLerp::_type_handle;

View File

@ -73,8 +73,8 @@ apply_linear_force(ColliderDef &def, const LVector3f &force) {
LVector3f adjustment=force;
physics_debug(" adjustment set "<<adjustment<<" len "<<adjustment.length());
NodePath np(def._node);
CPT(TransformState) trans = np.get_net_transform();
//NodePath np(def._node);
//CPT(TransformState) trans = np.get_net_transform();
//adjustment=adjustment*trans->get_mat();
physics_debug(" adjustment trn "<<adjustment<<" len "<<adjustment.length());
@ -112,7 +112,10 @@ apply_linear_force(ColliderDef &def, const LVector3f &force) {
physics_debug(" vel pre friction "<<vel<<" len "<<vel.length());
float friction=frictionCoefficient*angle;
physics_debug(" friction "<<friction);
assert(friction>=0.0f && friction<=1.0f);
if (friction<0.0f && friction>1.0f) {
cerr<<"\n\nfriction error "<<friction<<endl;
friction=1.0f;
}
#if 0
float dt=ClockObject::get_global_clock()->get_dt();
vel *= (1.0f-friction) * dt * dt;