Some work to make it work on a mac

This commit is contained in:
Roger Hughston 2006-09-22 19:32:30 +00:00
parent 60791e039a
commit 0e87c509ce
4 changed files with 105 additions and 221 deletions

View File

@ -27,14 +27,12 @@
#include "config_express.h"
#include "virtualFileSystem.h"
#include "nullAudioSound.h"
#include "mutexHolder.h"
#include <algorithm>
TypeHandle MilesAudioManager::_type_handle;
Mutex *MilesAudioManager::_static_lock;
int MilesAudioManager::_active_managers = 0;
bool MilesAudioManager::_miles_active = false;
HDLSFILEID MilesAudioManager::_dls_field = NULL;
@ -61,23 +59,10 @@ MilesAudioManager::
MilesAudioManager() {
audio_debug("MilesAudioManager::MilesAudioManager(), this = "
<< (void *)this);
if (_static_lock == NULL) {
Mutex *new_lock = new Mutex;
void *result = AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_static_lock, (void *)NULL, (void *)new_lock);
if (result != NULL) {
// Someone else must have assigned the mutex first. OK.
nassertv(_static_lock != new_lock);
delete new_lock;
}
nassertv((Mutex * TVOLATILE &)_static_lock != NULL);
}
MutexHolder st_holder(*(Mutex * TVOLATILE &)_static_lock);
if (_managers == (Managers *)NULL) {
_managers = new Managers;
}
_managers->insert(this);
audio_debug(" audio_active="<<audio_active);
audio_debug(" audio_volume="<<audio_volume);
_cleanup_required = true;
@ -93,7 +78,14 @@ MilesAudioManager() {
S32 use_MIDI=(audio_play_midi)?1:0;
if (audio_play_midi && audio_software_midi) {
use_MIDI=AIL_QUICK_DLS_ONLY;
}
#ifdef IS_OSX
use_MIDI=AIL_QUICK_DLS_ONLY;
audio_software_midi=true;
#endif
audio_debug(" use_digital="<<use_digital);
audio_debug(" use_MIDI="<<use_MIDI);
audio_debug(" audio_output_rate="<<audio_output_rate);
@ -124,7 +116,6 @@ MilesAudioManager() {
}
audio_debug(" dls_file=\""<<dls_file<<"\"");
// note: if AIL_DLS_load_file is not done, midi fails to play on some machines.
nassertv(_dls_field == NULL);
audio_debug(" AIL_DLS_load_file(dls, " << dls_file << ", 0)");
@ -179,21 +170,14 @@ MilesAudioManager() {
////////////////////////////////////////////////////////////////////
MilesAudioManager::
~MilesAudioManager() {
{
MutexHolder st_holder(*_static_lock);
audio_debug("MilesAudioManager::~MilesAudioManager(), this = "
<< (void *)this);
nassertv(_managers != (Managers *)NULL);
Managers::iterator mi = _managers->find(this);
if (mi != _managers->end()) {
// The manager might already have been removed from the list, if
// the user has already called shutdown().
_managers->erase(mi);
}
}
audio_debug("MilesAudioManager::~MilesAudioManager(), this = "
<< (void *)this);
nassertv(_managers != (Managers *)NULL);
Managers::iterator mi = _managers->find(this);
nassertv(mi != _managers->end());
_managers->erase(mi);
cleanup();
audio_debug("MilesAudioManager::~MilesAudioManager() finished");
}
@ -208,60 +192,27 @@ MilesAudioManager::
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
shutdown() {
Managers old_managers;
{
MutexHolder st_holder(*_static_lock);
audio_debug("shutdown(), _miles_active = " << _miles_active);
if (_managers != (Managers *)NULL) {
old_managers.swap(*_managers);
audio_debug("shutdown(), _miles_active = " << _miles_active);
if (_managers != (Managers *)NULL) {
Managers::iterator mi;
for (mi = _managers->begin(); mi != _managers->end(); ++mi) {
(*mi)->cleanup();
}
}
// We insist on cleaning up our manager pointers, rather than
// relying on their destructors, since there might be outstanding
// pointers to these somewhere that would otherwise prevent them
// from being cleaned up and therefore prevent Miles from being shut
// down properly. In order for this to work, we must write
// cleanup() so that it is safe to call it twice.
Managers::iterator mi;
for (mi = old_managers.begin(); mi != old_managers.end(); ++mi) {
(*mi)->cleanup();
}
// Another thread might conceivably have started up a new manager
// after we called shutdown(), which is technically legal and would
// incorrectly trigger the following assertion. However, presumably
// shutdown() will only be called as the application is shutting
// down anyway, and there won't be any other threads still out there
// creating audio managers (and if there were, it would defeat the
// purpose of shutdown() anyway).
nassertv(_active_managers == 0);
audio_debug("shutdown() finished");
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::is_valid
// Access: Public
// Access:
// Description: This is mostly for debugging, but it it could be
// used to detect errors in a release build if you
// don't mind the cpu cost.
////////////////////////////////////////////////////////////////////
bool MilesAudioManager::
is_valid() {
MutexHolder holder(_lock);
return do_is_valid();
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::do_is_valid
// Access: Private
// Description: Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
bool MilesAudioManager::
do_is_valid() {
bool check=true;
if (_sounds.size() != _lru.size()) {
audio_debug("-- Error _sounds.size() != _lru.size() --");
@ -374,88 +325,59 @@ get_sound(const string& file_name, bool) {
return get_null_sound();
}
assert(is_valid());
Filename path = file_name;
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
vfs->resolve_filename(path, get_sound_path());
audio_debug(" resolved file_name is '"<<path<<"'");
const string *cache_path = NULL;
PT(SoundData) sd;
// Get the sound, either from the cache or from a loader:
MutexHolder holder(_lock);
assert(do_is_valid());
SoundMap::const_iterator si = _sounds.find(path);
SoundMap::const_iterator si=_sounds.find(path);
if (si != _sounds.end()) {
// ...found the sound in the cache.
cache_path = &((*si).first);
sd = (*si).second;
audio_debug(" sound found in pool 0x" << (void*)sd);
}
if (sd == (SoundData *)NULL) {
} else {
// ...the sound was not found in the cache/pool.
// Ideally, we should release the lock while we're performing the
// actual load, so multiple threads can be loading sounds in
// parallel. However, it appears that Miles is internally not
// thread-safe, so we can't do that.
//_lock.release();
sd = load(path);
//_lock.lock();
if (sd != (SoundData *)NULL) {
SoundMap::const_iterator si = _sounds.find(path);
if (si != _sounds.end()) {
// Oops, someone else must have just put it in the cache.
// Throw away the sound object we just loaded.
cache_path = &((*si).first);
sd = (*si).second;
audio_debug(" sound found in pool 0x" << (void*)sd);
} else {
// OK, put the sound object we just loaded into the cache.
while (_sounds.size() >= (unsigned int)_cache_limit) {
uncache_a_sound();
}
// The following is roughly like: _sounds[path] = sd;
// But, it gives us an iterator into the map.
pair<SoundMap::const_iterator, bool> ib =
_sounds.insert(SoundMap::value_type(path, sd));
if (!ib.second) {
// The insert failed.
audio_debug(" failed map insert of "<<path);
assert(do_is_valid());
return get_null_sound();
}
// Get a reference to the path for the MilesAudioSound.
SoundMap::const_iterator si = ib.first;
cache_path = &((*si).first);
while (_sounds.size() >= (unsigned int)_cache_limit) {
uncache_a_sound();
}
// Put it in the pool:
// The following is roughly like: _sounds[path] = sd;
// But, it gives us an iterator into the map.
pair<SoundMap::const_iterator, bool> ib
=_sounds.insert(SoundMap::value_type(path, sd));
if (!ib.second) {
// The insert failed.
audio_debug(" failed map insert of "<<path);
assert(is_valid());
return get_null_sound();
}
// Set si, so that we can get a reference to the path
// for the MilesAudioSound.
si=ib.first;
}
}
// Create an AudioSound from the sound:
PT(AudioSound) audioSound;
PT(AudioSound) audioSound = 0;
if (sd != (SoundData *)NULL) {
nassertr(cache_path != NULL, NULL);
most_recently_used(cache_path);
PT(MilesAudioSound) milesAudioSound = new MilesAudioSound(this, sd, path);
nassertr(milesAudioSound, NULL);
most_recently_used((*si).first);
PT(MilesAudioSound) milesAudioSound
=new MilesAudioSound(this, sd, (*si).first);
nassertr(milesAudioSound, 0);
milesAudioSound->set_active(_active);
bool inserted = _sounds_on_loan.insert(milesAudioSound).second;
nassertr(inserted, milesAudioSound.p());
audioSound = milesAudioSound;
audioSound=milesAudioSound;
}
_hasMidiSounds |= (file_name.find(".mid")!=string::npos);
audio_debug(" returning 0x" << (void*)audioSound);
assert(do_is_valid());
assert(is_valid());
return audioSound;
}
@ -465,19 +387,17 @@ get_sound(const string& file_name, bool) {
// Description:
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
uncache_sound(const string &file_name) {
MutexHolder holder(_lock);
uncache_sound(const string& file_name) {
audio_debug("MilesAudioManager::uncache_sound(file_name=\""
<<file_name<<"\")");
assert(do_is_valid());
assert(is_valid());
Filename path = file_name;
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
vfs->resolve_filename(path, get_sound_path());
audio_debug(" path=\""<<path<<"\"");
SoundMap::iterator i = _sounds.find(path);
SoundMap::iterator i=_sounds.find(path);
if (i != _sounds.end()) {
assert(_lru.size()>0);
LRU::iterator lru_i=find(_lru.begin(), _lru.end(), &(i->first));
@ -485,18 +405,18 @@ uncache_sound(const string &file_name) {
_lru.erase(lru_i);
_sounds.erase(i);
}
assert(do_is_valid());
assert(is_valid());
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::uncache_a_sound
// Access: Private
// Description: Assumes the lock is already held.
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
uncache_a_sound() {
audio_debug("MilesAudioManager::uncache_a_sound()");
assert(do_is_valid());
assert(is_valid());
// uncache least recently used:
assert(_lru.size()>0);
LRU::reference path=_lru.front();
@ -508,26 +428,26 @@ uncache_a_sound() {
audio_debug(" uncaching \""<<i->first<<"\"");
_sounds.erase(i);
}
assert(do_is_valid());
assert(is_valid());
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::most_recently_used
// Access: Private
// Description: Assumes the lock is already held.
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
most_recently_used(const string *path) {
most_recently_used(const string& path) {
audio_debug("MilesAudioManager::most_recently_used(path=\""
<<path<<"\")");
LRU::iterator i=find(_lru.begin(), _lru.end(), path);
LRU::iterator i=find(_lru.begin(), _lru.end(), &path);
if (i != _lru.end()) {
_lru.erase(i);
}
// At this point, path should not exist in the _lru:
assert(find(_lru.begin(), _lru.end(), path) == _lru.end());
_lru.push_back(path);
assert(do_is_valid());
assert(find(_lru.begin(), _lru.end(), &path) == _lru.end());
_lru.push_back(&path);
assert(is_valid());
}
////////////////////////////////////////////////////////////////////
@ -537,22 +457,11 @@ most_recently_used(const string *path) {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
clear_cache() {
MutexHolder holder(_lock);
do_clear_cache();
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::do_clear_cache
// Access: Private
// Description: Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
do_clear_cache() {
audio_debug("MilesAudioManager::clear_cache()");
if (_is_valid) { assert(do_is_valid()); }
if (_is_valid) { assert(is_valid()); }
_sounds.clear();
_lru.clear();
if (_is_valid) { assert(do_is_valid()); }
if (_is_valid) { assert(is_valid()); }
}
////////////////////////////////////////////////////////////////////
@ -562,15 +471,13 @@ do_clear_cache() {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
set_cache_limit(unsigned int count) {
MutexHolder holder(_lock);
audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
assert(do_is_valid());
assert(is_valid());
while (_lru.size() > count) {
uncache_a_sound();
}
_cache_limit=count;
assert(do_is_valid());
assert(is_valid());
}
////////////////////////////////////////////////////////////////////
@ -580,8 +487,6 @@ set_cache_limit(unsigned int count) {
////////////////////////////////////////////////////////////////////
unsigned int MilesAudioManager::
get_cache_limit() const {
MutexHolder holder(_lock);
audio_debug("MilesAudioManager::get_cache_limit() returning "
<<_cache_limit);
return _cache_limit;
@ -594,8 +499,6 @@ get_cache_limit() const {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
release_sound(MilesAudioSound* audioSound) {
MutexHolder holder(_lock);
audio_debug("MilesAudioManager::release_sound(audioSound=\""
<<audioSound->get_name()<<"\"), this = " << (void *)this);
AudioSet::iterator ai = _sounds_on_loan.find(audioSound);
@ -771,6 +674,8 @@ stop_all_sounds() {
reduce_sounds_playing_to(0);
}
#ifdef WIN32
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::get_registry_entry
// Access: private
@ -816,7 +721,7 @@ get_registry_entry(HKEY base, const char* subKeyName,
return (r==ERROR_SUCCESS);
}
#endif
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::get_gm_file_path
// Access: private
@ -824,12 +729,21 @@ get_registry_entry(HKEY base, const char* subKeyName,
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
get_gm_file_path(string& result) {
#ifdef WIN32
if(!get_registry_entry(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\DirectMusic", "GMFilePath", result)) {
char sysdir[MAX_PATH+1];
GetSystemDirectory(sysdir,MAX_PATH+1);
result = sysdir;
result.append("\\drivers\\gm.dls");
}
#endif
#ifdef IS_OSX
result =
//"gs_instruments.dls";
"/System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls";
#endif
audio_debug("MilesAudioManager::get_gm_file_path() result out=\""<<result<<"\"");
}
@ -855,7 +769,9 @@ force_midi_reset() {
AIL_quick_handles(0, &hMid, 0);
if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
audio_debug("MilesAudioManager::calling midiOutReset");
#ifdef WIN32
midiOutReset(hMid->hMidiOut);
#endif
}
}
@ -868,40 +784,19 @@ force_midi_reset() {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
cleanup() {
{
MutexHolder holder(_lock);
audio_debug("MilesAudioManager::cleanup(), this = " << (void *)this
<< ", _cleanup_required = " << _cleanup_required);
if (!_cleanup_required) {
return;
}
// Be sure to cleanup associated sounds before cleaning up the manager:
AudioSet::iterator ai;
for (ai = _sounds_on_loan.begin(); ai != _sounds_on_loan.end(); ++ai) {
(*ai)->cleanup();
}
do_clear_cache();
_cleanup_required = false;
audio_debug("MilesAudioManager::cleanup(), this = " << (void *)this
<< ", _cleanup_required = " << _cleanup_required);
if (!_cleanup_required) {
return;
}
deactivate();
audio_debug("MilesAudioManager::cleanup() finished");
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::deactivate
// Access: Private, Static
// Description: Deactivates one manager. Grabs the static lock.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
deactivate() {
MutexHolder st_holder(*_static_lock);
// Be sure to cleanup associated sounds before cleaning up the manager:
AudioSet::iterator ai;
for (ai = _sounds_on_loan.begin(); ai != _sounds_on_loan.end(); ++ai) {
(*ai)->cleanup();
}
clear_cache();
nassertv(_active_managers > 0);
--_active_managers;
audio_debug(" _active_managers="<<_active_managers);
@ -921,6 +816,8 @@ deactivate() {
_miles_active = false;
}
}
_cleanup_required = false;
audio_debug("MilesAudioManager::cleanup() finished");
}
////////////////////////////////////////////////////////////////////

View File

@ -28,7 +28,6 @@
#include "pset.h"
#include "pmap.h"
#include "pdeque.h"
#include "pmutex.h"
class MilesAudioSound;
@ -66,8 +65,6 @@ public:
void stop_all_sounds();
private:
Mutex _lock; // Protects all the members of this class.
// The sound cache:
class SoundData : public ReferenceCount {
public:
@ -85,16 +82,16 @@ private:
typedef pmap<string, PT(SoundData) > SoundMap;
SoundMap _sounds;
typedef pset<MilesAudioSound *> AudioSet;
typedef pset<MilesAudioSound* > AudioSet;
// The offspring of this manager:
AudioSet _sounds_on_loan;
typedef pset<MilesAudioSound *> SoundsPlaying;
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;
typedef pdeque<const string* > LRU;
LRU _lru;
// State:
float _volume;
@ -102,51 +99,41 @@ private:
bool _active;
int _cache_limit;
bool _cleanup_required;
// keep a count for startup and shutdown:
static int _active_managers;
static bool _miles_active;
unsigned int _concurrent_sound_limit;
bool _is_valid;
bool _hasMidiSounds;
private:
// Static members. Protected by the following lock.
static Mutex *_static_lock;
// keep a count for startup and shutdown:
static int _active_managers;
static bool _miles_active;
// Optional Downloadable Sound field for software midi
static HDLSFILEID _dls_field;
typedef pset<MilesAudioManager *> Managers;
static Managers *_managers;
private:
bool do_is_valid();
void do_clear_cache();
PT(SoundData) load(Filename file_name);
// Tell the manager that the sound dtor was called.
void release_sound(MilesAudioSound* audioSound);
void most_recently_used(const string *path);
void most_recently_used(const string& path);
void uncache_a_sound();
void starting_sound(MilesAudioSound* audio);
void stopping_sound(MilesAudioSound* audio);
#ifdef WIN32
// utility function that should be moved to another class:
bool get_registry_entry(HKEY base,
const char* subKeyName,
const char* keyName,
string& result);
#endif
// get the default dls file path:
void get_gm_file_path(string& result);
void force_midi_reset();
void cleanup();
static void deactivate();
friend class MilesAudioSound;

View File

@ -66,7 +66,7 @@ namespace {
namespace {
AILSEQUENCECB sequence_callback = 0;
AILSAMPLECB sample_callback = 0;
const user_data_index = 7;
const int user_data_index = 7;
////////////////////////////////////////////////////////////////////
// Function: pandaAudioAilCallback_Sequence
@ -363,7 +363,7 @@ set_time(float time) {
time = max_time;
}
S32 millisecond_time=S32(1000*time);
S32 millisecond_time=(S32)(1000*time);
AIL_quick_set_ms_position(_audio, millisecond_time);
}
@ -462,7 +462,7 @@ set_play_rate(float play_rate) {
case AIL_QUICK_XMIDI_TYPE:
case AIL_QUICK_DLS_XMIDI_TYPE:
// midi uses whole percentage values 100 == 100%
_audio->speed = S32(play_rate*100.0f);
_audio->speed = (S32)(play_rate*100.0f);
if ((_audio->speed != -1) && (AIL_quick_status(_audio) == QSTAT_PLAYING)) {
AIL_set_sequence_tempo((HSEQUENCE)_audio->handle, _audio->speed, 0);
}
@ -471,7 +471,7 @@ set_play_rate(float play_rate) {
case AIL_QUICK_DIGITAL_TYPE:
case AIL_QUICK_MPEG_DIGITAL_TYPE:
// wave and mp3 use sample rate (e.g. 44100)
_audio->speed = S32(play_rate*float(_original_playback_rate));
_audio->speed = (S32)(play_rate*float(_original_playback_rate));
if ((_audio->speed != -1) && (AIL_quick_status(_audio) == QSTAT_PLAYING)) {
AIL_set_sample_playback_rate((HSAMPLE)_audio->handle, _audio->speed);
}

View File

@ -149,7 +149,7 @@ private:
// itwas set inactive.
bool _paused;
MilesAudioSound(MilesAudioManager *manager, MilesAudioManager::SoundData *sd,
MilesAudioSound(MilesAudioManager* manager, MilesAudioManager::SoundData *sd,
string file_name, float length=0.0f);
void cleanup();