00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "pandabase.h"
00021 #ifdef HAVE_RAD_MSS //[
00022
00023 #include "milesAudioSound.h"
00024 #include "milesAudioManager.h"
00025 #include "config_audio.h"
00026 #include "config_util.h"
00027 #include "config_express.h"
00028 #include "virtualFileSystem.h"
00029 #include "nullAudioSound.h"
00030 #include <algorithm>
00031
00032 int MilesAudioManager::_active_managers = 0;
00033 HDLSFILEID MilesAudioManager::_dls_field = NULL;
00034 bool bMilesShutdownCalled = false;
00035 bool bMilesShutdownAtExitRegistered = false;
00036
00037 PT(AudioManager) Create_AudioManager() {
00038 audio_debug("Create_AudioManager() Miles.");
00039 return new MilesAudioManager();
00040 }
00041
00042 void fMilesShutdown(void) {
00043 if(bMilesShutdownCalled)
00044 return;
00045
00046 bMilesShutdownCalled = true;
00047
00048 if (MilesAudioManager::_dls_field!=NULL) {
00049 HDLSDEVICE dls= NULL;
00050 AIL_quick_handles(0, 0, &dls);
00051 if(dls!=NULL) {
00052 AIL_DLS_unload(dls,MilesAudioManager::_dls_field);
00053 }
00054
00055 #ifndef NDEBUG //[
00056
00057 MilesAudioManager::_dls_field = NULL;
00058 #endif //]
00059 }
00060
00061
00062 #define SHUTDOWN_HACK
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 #ifdef SHUTDOWN_HACK
00073 HMDIDRIVER hMid=NULL;
00074 AIL_quick_handles(0, &hMid, 0);
00075 if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
00076 midiOutReset(hMid->hMidiOut);
00077 midiOutClose(hMid->hMidiOut);
00078 }
00079 #else
00080 audio_debug(" AIL_quick_shutdown()");
00081 AIL_quick_shutdown();
00082 #endif
00083 }
00084
00085
00086
00087
00088
00089
00090 MilesAudioManager::
00091 MilesAudioManager() {
00092 audio_debug("MilesAudioManager::MilesAudioManager()");
00093 audio_debug(" audio_active="<<audio_active);
00094 audio_debug(" audio_volume="<<audio_volume);
00095 _active = audio_active;
00096 _volume = audio_volume;
00097 _cache_limit = audio_cache_limit;
00098 _is_valid = true;
00099 _bHasMidiSounds = false;
00100 if (_active_managers==0) {
00101 S32 use_digital=(audio_play_wave || audio_play_mp3)?1:0;
00102 S32 use_MIDI=(audio_play_midi)?1:0;
00103 if (audio_play_midi && audio_software_midi) {
00104 use_MIDI=AIL_QUICK_DLS_ONLY;
00105 }
00106 audio_debug(" use_digital="<<use_digital);
00107 audio_debug(" use_MIDI="<<use_MIDI);
00108 audio_debug(" audio_output_rate="<<audio_output_rate);
00109 audio_debug(" audio_output_bits="<<audio_output_bits);
00110 audio_debug(" audio_output_channels="<<audio_output_channels);
00111 audio_debug(" audio_software_midi="<<audio_software_midi);
00112 #ifndef NDEBUG //[
00113 char version[8];
00114 AIL_MSS_version(version, 8);
00115 audio_debug(" Mss32.dll Version: "<<version);
00116 #endif //]
00117 if (AIL_quick_startup(use_digital,
00118 use_MIDI, audio_output_rate,
00119 audio_output_bits, audio_output_channels)) {
00120 if (audio_software_midi) {
00121
00122
00123 HDLSDEVICE dls;
00124 AIL_quick_handles(0, 0, &dls);
00125 nassertv(audio_dls_file);
00126 nassertv(!_dls_field);
00127 if (audio_dls_file->empty()) {
00128 get_gm_file_path(*audio_dls_file);
00129
00130 audio_info(" using default audio_dls_file: "<< (*audio_dls_file) );
00131 }
00132
00133 audio_debug(" audio_dls_file=\""<<*audio_dls_file<<"\"");
00134
00135
00136 _dls_field=AIL_DLS_load_file(dls, audio_dls_file->c_str(), 0);
00137 if (!_dls_field) {
00138 audio_error(" AIL_DLS_load_file() failed, \""<<AIL_last_error() <<"\" Switching to hardware midi");
00139 AIL_quick_shutdown();
00140 if (!AIL_quick_startup(use_digital, 1, audio_output_rate,
00141 audio_output_bits, audio_output_channels)) {
00142 audio_error(" midi hardware startup failed, "<<AIL_last_error());
00143 _is_valid = false;
00144 }
00145 } else {
00146 audio_info(" using Miles software midi");
00147 }
00148 } else {
00149 audio_info(" using Miles hardware midi");
00150 }
00151
00152 if (use_vfs) {
00153 AIL_set_file_callbacks(vfs_open_callback,
00154 vfs_close_callback,
00155 vfs_seek_callback,
00156 vfs_read_callback);
00157 }
00158 } else {
00159 audio_debug(" AIL_quick_startup failed: "<<AIL_last_error());
00160 _is_valid = false;
00161 }
00162 }
00163
00164
00165
00166 ++_active_managers;
00167 audio_debug(" _active_managers="<<_active_managers);
00168
00169 if (_is_valid) {
00170 assert(is_valid());
00171
00172 if(!bMilesShutdownAtExitRegistered) {
00173 bMilesShutdownAtExitRegistered = true;
00174 atexit(fMilesShutdown);
00175 }
00176 }
00177 }
00178
00179
00180
00181
00182
00183
00184 MilesAudioManager::
00185 ~MilesAudioManager() {
00186 audio_debug("MilesAudioManager::~MilesAudioManager()");
00187
00188 nassertv(_soundsOnLoan.empty());
00189 clear_cache();
00190 --_active_managers;
00191 audio_debug(" _active_managers="<<_active_managers);
00192 if (_active_managers==0) {
00193 if (audio_software_midi) {
00194 HDLSDEVICE dls;
00195 AIL_quick_handles(0, 0, &dls);
00196 AIL_DLS_unload(dls, _dls_field);
00197 #ifndef NDEBUG //[
00198
00199 _dls_field=0;
00200 #endif //]
00201 }
00202 audio_debug(" AIL_quick_shutdown()");
00203 AIL_quick_shutdown();
00204 bMilesShutdownCalled = true;
00205 }
00206 }
00207
00208
00209
00210
00211
00212
00213 bool MilesAudioManager::
00214 is_valid() {
00215 bool check=true;
00216 if (_sounds.size() != _lru.size()) {
00217 audio_debug("--sizes--");
00218 check=false;
00219 } else {
00220 LRU::const_iterator i=_lru.begin();
00221 for (; i != _lru.end(); ++i) {
00222 SoundMap::const_iterator smi=_sounds.find(**i);
00223 if (smi == _sounds.end()) {
00224 audio_debug("--"<<**i<<"--");
00225 check=false;
00226 break;
00227 }
00228 }
00229 }
00230 return _is_valid && check;
00231 }
00232
00233
00234
00235
00236
00237
00238 HAUDIO MilesAudioManager::
00239 load(Filename file_name) {
00240 HAUDIO audio;
00241
00242 if (use_vfs) {
00243 audio = AIL_quick_load(file_name.c_str());
00244
00245 } else {
00246 string stmp = file_name.to_os_specific();
00247 audio_debug(" \"" << stmp << "\"");
00248 audio = AIL_quick_load(stmp.c_str());
00249 }
00250
00251 if (!audio) {
00252 audio_error(" MilesAudioManager::load failed "<< AIL_last_error());
00253 }
00254 return audio;
00255 }
00256
00257
00258
00259
00260
00261
00262 PT(AudioSound) MilesAudioManager::
00263 get_sound(const string& file_name) {
00264 audio_debug("MilesAudioManager::get_sound(file_name=\""<<file_name<<"\")");
00265
00266 if(!is_valid()) {
00267 audio_debug("invalid MilesAudioManager returning NullSound");
00268 return get_null_sound();
00269 }
00270
00271 assert(is_valid());
00272 Filename path = file_name;
00273
00274 if (use_vfs) {
00275 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00276 vfs->resolve_filename(path, get_sound_path());
00277 } else {
00278 path.resolve_filename(get_sound_path());
00279 }
00280
00281 audio_debug(" resolved file_name is '"<<path<<"'");
00282
00283 HAUDIO audio=0;
00284
00285 SoundMap::const_iterator si=_sounds.find(path);
00286 if (si != _sounds.end()) {
00287
00288 audio = (*si).second;
00289 audio_debug(" sound found in pool 0x" << (void*)audio);
00290 } else {
00291
00292 audio=load(path);
00293 if (audio) {
00294 while (_sounds.size() >= (unsigned int)_cache_limit) {
00295 uncache_a_sound();
00296 }
00297
00298
00299
00300 pair<SoundMap::const_iterator, bool> ib
00301 =_sounds.insert(pair<string, HAUDIO>(path, audio));
00302 if (!ib.second) {
00303
00304 audio_debug(" failed map insert of "<<path);
00305 assert(is_valid());
00306 return get_null_sound();
00307 }
00308
00309
00310 si=ib.first;
00311 }
00312 }
00313
00314 PT(AudioSound) audioSound = 0;
00315 if (audio) {
00316 most_recently_used((*si).first);
00317 PT(MilesAudioSound) milesAudioSound
00318 =new MilesAudioSound(this, audio, (*si).first);
00319 nassertr(milesAudioSound, 0);
00320 milesAudioSound->set_active(_active);
00321 _soundsOnLoan.insert(milesAudioSound);
00322 audioSound=milesAudioSound;
00323 }
00324
00325 _bHasMidiSounds |= (file_name.find(".mid")!=string::npos);
00326 audio_debug(" returning 0x" << (void*)audioSound);
00327 assert(is_valid());
00328 return audioSound;
00329 }
00330
00331
00332
00333
00334
00335
00336 void MilesAudioManager::
00337 uncache_sound(const string& file_name) {
00338 audio_debug("MilesAudioManager::uncache_sound(file_name=\""
00339 <<file_name<<"\")");
00340 assert(is_valid());
00341 Filename path = file_name;
00342
00343 if (use_vfs) {
00344 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00345 vfs->resolve_filename(path, get_sound_path());
00346 } else {
00347 path.resolve_filename(get_sound_path());
00348 }
00349
00350 audio_debug(" path=\""<<path<<"\"");
00351 SoundMap::iterator i=_sounds.find(path);
00352 if (i != _sounds.end()) {
00353 assert(_lru.size()>0);
00354 LRU::iterator lru_i=find(_lru.begin(), _lru.end(), &(i->first));
00355 assert(lru_i != _lru.end());
00356 _lru.erase(lru_i);
00357 AIL_quick_unload(i->second);
00358 _sounds.erase(i);
00359 }
00360 assert(is_valid());
00361 }
00362
00363
00364
00365
00366
00367
00368 void MilesAudioManager::
00369 uncache_a_sound() {
00370 audio_debug("MilesAudioManager::uncache_a_sound()");
00371 assert(is_valid());
00372
00373 assert(_lru.size()>0);
00374 LRU::reference path=_lru.front();
00375 SoundMap::iterator i = _sounds.find(*path);
00376 assert(i != _sounds.end());
00377 _lru.pop_front();
00378
00379 if (i != _sounds.end()) {
00380 audio_debug(" uncaching \""<<i->first<<"\"");
00381 AIL_quick_unload(i->second);
00382 _sounds.erase(i);
00383 }
00384 assert(is_valid());
00385 }
00386
00387
00388
00389
00390
00391
00392 void MilesAudioManager::
00393 most_recently_used(const string& path) {
00394 audio_debug("MilesAudioManager::most_recently_used(path=\""
00395 <<path<<"\")");
00396 LRU::iterator i=find(_lru.begin(), _lru.end(), &path);
00397 if (i != _lru.end()) {
00398 _lru.erase(i);
00399 }
00400
00401 assert(find(_lru.begin(), _lru.end(), &path) == _lru.end());
00402 _lru.push_back(&path);
00403 assert(is_valid());
00404 }
00405
00406
00407
00408
00409
00410
00411 void MilesAudioManager::
00412 clear_cache() {
00413 audio_debug("MilesAudioManager::clear_cache()");
00414 if (_is_valid) { assert(is_valid()); }
00415 SoundMap::iterator i=_sounds.begin();
00416 for (; i!=_sounds.end(); ++i) {
00417 AIL_quick_unload(i->second);
00418 }
00419 _sounds.clear();
00420 _lru.clear();
00421 if (_is_valid) { assert(is_valid()); }
00422 }
00423
00424
00425
00426
00427
00428
00429 void MilesAudioManager::
00430 set_cache_limit(int count) {
00431 audio_debug("MilesAudioManager::set_cache_limit(count="
00432 <<count<<")");
00433 assert(is_valid());
00434 while (_lru.size() > (unsigned int) count) {
00435 uncache_a_sound();
00436 }
00437 _cache_limit=count;
00438 assert(is_valid());
00439 }
00440
00441
00442
00443
00444
00445
00446 int MilesAudioManager::
00447 get_cache_limit() {
00448 audio_debug("MilesAudioManager::get_cache_limit() returning "
00449 <<_cache_limit);
00450 return _cache_limit;
00451 }
00452
00453
00454
00455
00456
00457
00458 void MilesAudioManager::
00459 release_sound(MilesAudioSound* audioSound) {
00460 audio_debug("MilesAudioManager::release_sound(audioSound=\""
00461 <<audioSound->get_name()<<"\")");
00462 _soundsOnLoan.erase(audioSound);
00463 }
00464
00465
00466
00467
00468
00469
00470 void MilesAudioManager::
00471 set_volume(float volume) {
00472 audio_debug("MilesAudioManager::set_volume(volume="<<volume<<")");
00473 if (_volume!=volume) {
00474 _volume = volume;
00475
00476 AudioSet::iterator i=_soundsOnLoan.begin();
00477 for (; i!=_soundsOnLoan.end(); ++i) {
00478 (**i).set_volume((**i).get_volume());
00479 }
00480 }
00481 }
00482
00483 void MilesAudioManager::
00484 stop_all_sounds(void) {
00485 audio_debug("MilesAudioManager::stop_all_sounds()");
00486 AudioSet::iterator i=_soundsOnLoan.begin();
00487 for (; i!=_soundsOnLoan.end(); ++i) {
00488 if((**i).status()==AudioSound::PLAYING)
00489 (**i).stop();
00490 }
00491
00492 if(_bHasMidiSounds) {
00493 forceMidiReset();
00494 }
00495 }
00496
00497 void MilesAudioManager::
00498 forceMidiReset(void) {
00499 if(!miles_audio_force_midi_reset) {
00500 audio_debug("MilesAudioManager::skipping forceMidiReset");
00501 return;
00502 }
00503
00504 audio_debug("MilesAudioManager::ForceMidiReset");
00505
00506
00507
00508 HMDIDRIVER hMid=NULL;
00509 AIL_quick_handles(0, &hMid, 0);
00510 if ((hMid!=NULL) && (hMid->deviceid != MIDI_NULL_DRIVER) && (hMid->hMidiOut != NULL)) {
00511 audio_debug("MilesAudioManager::calling midiOutReset");
00512 midiOutReset(hMid->hMidiOut);
00513 }
00514 }
00515
00516
00517
00518
00519
00520
00521 float MilesAudioManager::
00522 get_volume() {
00523 audio_debug("MilesAudioManager::get_volume() returning "<<_volume);
00524 return _volume;
00525 }
00526
00527
00528
00529
00530
00531
00532 void MilesAudioManager::
00533 set_active(bool active) {
00534 audio_debug("MilesAudioManager::set_active(flag="<<active<<")");
00535 if (_active!=active) {
00536 _active=active;
00537
00538 AudioSet::iterator i=_soundsOnLoan.begin();
00539 for (; i!=_soundsOnLoan.end(); ++i) {
00540 (**i).set_active(_active);
00541 }
00542
00543 if((!_active) && _bHasMidiSounds) {
00544 forceMidiReset();
00545 }
00546 }
00547 }
00548
00549
00550
00551
00552
00553
00554 bool MilesAudioManager::
00555 get_active() {
00556 audio_debug("MilesAudioManager::get_active() returning "<<_active);
00557 return _active;
00558 }
00559
00560
00561
00562
00563
00564
00565
00566 bool MilesAudioManager::
00567 get_registry_entry(HKEY base, const char* subKeyName,
00568 const char* keyName, string& result) {
00569
00570 HKEY key;
00571 long r=RegOpenKeyEx(base, subKeyName, 0, KEY_QUERY_VALUE, &key);
00572 if (r==ERROR_SUCCESS) {
00573 DWORD len=0;
00574
00575 r=RegQueryValueEx(key, keyName, 0, 0, 0, &len);
00576 if (r==ERROR_SUCCESS) {
00577 char* src = new char[len];
00578 DWORD type;
00579
00580 r=RegQueryValueEx(key, keyName, 0, &type, (unsigned char*)src, &len);
00581 if (r==ERROR_SUCCESS) {
00582 if (type==REG_EXPAND_SZ) {
00583
00584 DWORD destSize=ExpandEnvironmentStrings(src, 0, 0);
00585
00586 char* dest = new char[destSize];
00587
00588 ExpandEnvironmentStrings(src, dest, destSize);
00589
00590 result=dest;
00591 delete [] dest;
00592 } else if (type==REG_SZ) {
00593 result=src;
00594 } else {
00595 audio_error("MilesAudioManager::get_reg_entry(): Unknown key type.");
00596 }
00597 }
00598 delete [] src;
00599 }
00600 RegCloseKey(key);
00601 }
00602
00603 return (r==ERROR_SUCCESS);
00604 }
00605
00606
00607
00608
00609
00610
00611 void MilesAudioManager::
00612 get_gm_file_path(string& result) {
00613 if(!get_registry_entry(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\DirectMusic", "GMFilePath", result)) {
00614 char sysdir[MAX_PATH+1];
00615 GetSystemDirectory(sysdir,MAX_PATH+1);
00616 result = sysdir;
00617 result.append("\\drivers\\gm.dls");
00618 }
00619
00620 audio_debug("MilesAudioManager::get_gm_file_path() result out=\""<<result<<"\"");
00621 }
00622
00623
00624
00625
00626
00627
00628
00629 U32 MilesAudioManager::
00630 vfs_open_callback(const char *filename, U32 *file_handle) {
00631 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00632 istream *istr = vfs->open_read_file(filename);
00633 if (istr == (istream *)NULL) {
00634
00635 milesAudio_cat.warning()
00636 << "Unable to open " << filename << "\n";
00637 *file_handle = 0;
00638 return 0;
00639 }
00640
00641
00642
00643
00644
00645
00646
00647 *file_handle = (U32)istr;
00648 return 1;
00649 }
00650
00651
00652
00653
00654
00655
00656
00657 U32 MilesAudioManager::
00658 vfs_read_callback(U32 file_handle, void *buffer, U32 bytes) {
00659 if (file_handle == 0) {
00660
00661 return 0;
00662 }
00663 istream *istr = (istream *)file_handle;
00664 istr->read((char *)buffer, bytes);
00665 size_t bytes_read = istr->gcount();
00666
00667 return bytes_read;
00668 }
00669
00670
00671
00672
00673
00674
00675
00676 S32 MilesAudioManager::
00677 vfs_seek_callback(U32 file_handle, S32 offset, U32 type) {
00678 if (file_handle == 0) {
00679
00680 return 0;
00681 }
00682 istream *istr = (istream *)file_handle;
00683
00684 ios::seekdir dir = ios::beg;
00685 switch (type) {
00686 case AIL_FILE_SEEK_BEGIN:
00687 dir = ios::beg;
00688 break;
00689 case AIL_FILE_SEEK_CURRENT:
00690 dir = ios::cur;
00691 break;
00692 case AIL_FILE_SEEK_END:
00693 dir = ios::end;
00694 break;
00695 }
00696
00697 istr->seekg(offset, dir);
00698 return istr->tellg();
00699 }
00700
00701
00702
00703
00704
00705
00706
00707 void MilesAudioManager::
00708 vfs_close_callback(U32 file_handle) {
00709 if (file_handle == 0) {
00710
00711 return;
00712 }
00713 istream *istr = (istream *)file_handle;
00714 delete istr;
00715 }
00716
00717
00718 #endif //]