00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "milesAudioManager.h"
00017
00018 #ifdef HAVE_RAD_MSS //[
00019
00020 #include "milesAudioSound.h"
00021 #include "milesAudioSample.h"
00022 #include "milesAudioStream.h"
00023 #include "globalMilesManager.h"
00024 #include "config_audio.h"
00025 #include "config_util.h"
00026 #include "config_express.h"
00027 #include "virtualFileSystem.h"
00028 #include "nullAudioSound.h"
00029 #include "string_utils.h"
00030 #include "mutexHolder.h"
00031 #include "lightReMutexHolder.h"
00032
00033 #include <algorithm>
00034
00035
00036 TypeHandle MilesAudioManager::_type_handle;
00037
00038 AudioManager *Create_MilesAudioManager() {
00039 audio_debug("Create_MilesAudioManager()");
00040 return new MilesAudioManager();
00041 }
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 MilesAudioManager::
00052 MilesAudioManager() :
00053 _lock("MilesAudioManager::_lock"),
00054 _streams_lock("MilesAudioManager::_streams_lock"),
00055 _streams_cvar(_streams_lock)
00056 {
00057 audio_debug("MilesAudioManager::MilesAudioManager(), this = "
00058 << (void *)this);
00059 GlobalMilesManager::get_global_ptr()->add_manager(this);
00060 audio_debug(" audio_active="<<audio_active);
00061 audio_debug(" audio_volume="<<audio_volume);
00062 _cleanup_required = true;
00063 _active = audio_active;
00064 _volume = audio_volume;
00065 _play_rate = 1.0f;
00066 _cache_limit = audio_cache_limit;
00067 _concurrent_sound_limit = 0;
00068 _is_valid = true;
00069 _hasMidiSounds = false;
00070 _sounds_finished = false;
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 }
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 MilesAudioManager::
00094 ~MilesAudioManager() {
00095 audio_debug("MilesAudioManager::~MilesAudioManager(), this = "
00096 << (void *)this);
00097 cleanup();
00098 GlobalMilesManager::get_global_ptr()->remove_manager(this);
00099
00100 audio_debug("MilesAudioManager::~MilesAudioManager() finished");
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 void MilesAudioManager::
00113 shutdown() {
00114 audio_debug("shutdown() started");
00115 GlobalMilesManager::get_global_ptr()->cleanup();
00116 audio_debug("shutdown() finished");
00117 }
00118
00119
00120
00121
00122
00123
00124
00125
00126 bool MilesAudioManager::
00127 is_valid() {
00128 LightReMutexHolder holder(_lock);
00129 return do_is_valid();
00130 }
00131
00132
00133
00134
00135
00136
00137 PT(AudioSound) MilesAudioManager::
00138 get_sound(const string &file_name, bool, int) {
00139 LightReMutexHolder holder(_lock);
00140 audio_debug("MilesAudioManager::get_sound(file_name=\""<<file_name<<"\")");
00141
00142 if (!do_is_valid()) {
00143 audio_debug("invalid MilesAudioManager returning NullSound");
00144 return get_null_sound();
00145 }
00146
00147 Filename path = file_name;
00148
00149 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00150 vfs->resolve_filename(path, get_model_path());
00151 audio_debug("Reading "<<path);
00152 audio_debug(" resolved file_name is '"<<path<<"'");
00153
00154 PT(SoundData) sd;
00155
00156 SoundMap::const_iterator si=_sounds.find(path);
00157 if (si != _sounds.end()) {
00158
00159 sd = (*si).second;
00160 audio_debug(" sound found in pool 0x" << (void*)sd);
00161
00162 } else {
00163
00164 sd = load(path);
00165 if (sd != (SoundData *)NULL) {
00166 while (_sounds.size() >= (unsigned int)_cache_limit) {
00167 uncache_a_sound();
00168 }
00169
00170
00171
00172 pair<SoundMap::const_iterator, bool> ib
00173 = _sounds.insert(SoundMap::value_type(path, sd));
00174 if (!ib.second) {
00175
00176 audio_debug(" failed map insert of "<<path);
00177 nassertr(do_is_valid(), NULL);
00178 return get_null_sound();
00179 }
00180
00181
00182 si=ib.first;
00183 }
00184 }
00185
00186 PT(AudioSound) audioSound;
00187
00188 if (sd != (SoundData *)NULL) {
00189 most_recently_used((*si).first);
00190 if (sd->_file_type == AILFILETYPE_MIDI ||
00191 sd->_file_type == AILFILETYPE_XMIDI ||
00192 sd->_file_type == AILFILETYPE_XMIDI_DLS ||
00193 sd->_file_type == AILFILETYPE_XMIDI_MLS) {
00194
00195 audioSound = new MilesAudioSequence(this, sd, file_name);
00196
00197 } else if (!sd->_raw_data.empty()) {
00198
00199 audioSound = new MilesAudioSample(this, sd, file_name);
00200
00201 } else {
00202
00203 audioSound = new MilesAudioStream(this, file_name, path);
00204 }
00205
00206 audioSound->set_active(_active);
00207
00208 bool inserted = _sounds_on_loan.insert((MilesAudioSound *)audioSound.p()).second;
00209 nassertr(inserted, audioSound);
00210
00211 _hasMidiSounds |= (file_name.find(".mid")!=string::npos);
00212 } else {
00213
00214 audioSound = new NullAudioSound;
00215 }
00216
00217 audio_debug(" returning 0x" << (void*)audioSound);
00218 nassertr(do_is_valid(), NULL);
00219 return audioSound;
00220 }
00221
00222
00223
00224
00225
00226
00227 PT(AudioSound) MilesAudioManager::
00228 get_sound(MovieAudio *sound, bool, int) {
00229 nassert_raise("Miles audio manager does not support MovieAudio sources.");
00230 return NULL;
00231 }
00232
00233
00234
00235
00236
00237
00238 void MilesAudioManager::
00239 uncache_sound(const string &file_name) {
00240 audio_debug("MilesAudioManager::uncache_sound(file_name=\""
00241 <<file_name<<"\")");
00242 LightReMutexHolder holder(_lock);
00243 nassertv(do_is_valid());
00244 Filename path = file_name;
00245
00246 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00247 vfs->resolve_filename(path, get_model_path());
00248
00249 audio_debug(" path=\""<<path<<"\"");
00250 SoundMap::iterator i = _sounds.find(path);
00251 if (i != _sounds.end()) {
00252 nassertv(_lru.size() > 0);
00253 LRU::iterator lru_i = find(_lru.begin(), _lru.end(), &(i->first));
00254 nassertv(lru_i != _lru.end());
00255 _lru.erase(lru_i);
00256 _sounds.erase(i);
00257 }
00258 nassertv(do_is_valid());
00259 }
00260
00261
00262
00263
00264
00265
00266 void MilesAudioManager::
00267 clear_cache() {
00268 audio_debug("MilesAudioManager::clear_cache()");
00269 LightReMutexHolder holder(_lock);
00270 do_clear_cache();
00271 }
00272
00273
00274
00275
00276
00277
00278 void MilesAudioManager::
00279 set_cache_limit(unsigned int count) {
00280 LightReMutexHolder holder(_lock);
00281
00282 audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
00283 nassertv(do_is_valid());
00284 while (_lru.size() > count) {
00285 uncache_a_sound();
00286 }
00287 _cache_limit=count;
00288 nassertv(do_is_valid());
00289 }
00290
00291
00292
00293
00294
00295
00296 unsigned int MilesAudioManager::
00297 get_cache_limit() const {
00298 return _cache_limit;
00299 }
00300
00301
00302
00303
00304
00305
00306 void MilesAudioManager::
00307 set_volume(PN_stdfloat volume) {
00308 audio_debug("MilesAudioManager::set_volume(volume="<<volume<<")");
00309 LightReMutexHolder holder(_lock);
00310 if (_volume != volume) {
00311 _volume = volume;
00312
00313 AudioSet::iterator i = _sounds_on_loan.begin();
00314 for (; i!=_sounds_on_loan.end(); ++i) {
00315 (*i)->set_volume((*i)->get_volume());
00316 }
00317 }
00318 }
00319
00320
00321
00322
00323
00324
00325 PN_stdfloat MilesAudioManager::
00326 get_volume() const {
00327 return _volume;
00328 }
00329
00330
00331
00332
00333
00334
00335 void MilesAudioManager::
00336 set_play_rate(PN_stdfloat play_rate) {
00337 audio_debug("MilesAudioManager::set_play_rate(play_rate="<<play_rate<<")");
00338 LightReMutexHolder holder(_lock);
00339 if (_play_rate != play_rate) {
00340 _play_rate = play_rate;
00341
00342 AudioSet::iterator i = _sounds_on_loan.begin();
00343 for (; i != _sounds_on_loan.end(); ++i) {
00344 (*i)->set_play_rate((*i)->get_play_rate());
00345 }
00346 }
00347 }
00348
00349
00350
00351
00352
00353
00354 PN_stdfloat MilesAudioManager::
00355 get_play_rate() const {
00356 return _play_rate;
00357 }
00358
00359
00360
00361
00362
00363
00364 void MilesAudioManager::
00365 set_active(bool active) {
00366 audio_debug("MilesAudioManager::set_active(flag="<<active<<")");
00367 LightReMutexHolder holder(_lock);
00368 if (_active != active) {
00369 _active=active;
00370
00371 AudioSet::iterator i = _sounds_on_loan.begin();
00372 for (; i != _sounds_on_loan.end(); ++i) {
00373 (*i)->set_active(_active);
00374 }
00375
00376 if ((!_active) && _hasMidiSounds) {
00377 GlobalMilesManager::get_global_ptr()->force_midi_reset();
00378 }
00379 }
00380 }
00381
00382
00383
00384
00385
00386
00387 bool MilesAudioManager::
00388 get_active() const {
00389 return _active;
00390 }
00391
00392
00393
00394
00395
00396
00397 void MilesAudioManager::
00398 set_concurrent_sound_limit(unsigned int limit) {
00399 LightReMutexHolder holder(_lock);
00400 _concurrent_sound_limit = limit;
00401 do_reduce_sounds_playing_to(_concurrent_sound_limit);
00402 }
00403
00404
00405
00406
00407
00408
00409 unsigned int MilesAudioManager::
00410 get_concurrent_sound_limit() const {
00411 return _concurrent_sound_limit;
00412 }
00413
00414
00415
00416
00417
00418
00419 void MilesAudioManager::
00420 reduce_sounds_playing_to(unsigned int count) {
00421 LightReMutexHolder holder(_lock);
00422 do_reduce_sounds_playing_to(count);
00423 }
00424
00425
00426
00427
00428
00429
00430 void MilesAudioManager::
00431 stop_all_sounds() {
00432 audio_debug("MilesAudioManager::stop_all_sounds()");
00433 reduce_sounds_playing_to(0);
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443 void MilesAudioManager::audio_3d_set_listener_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz, PN_stdfloat fx, PN_stdfloat fy, PN_stdfloat fz, PN_stdfloat ux, PN_stdfloat uy, PN_stdfloat uz) {
00444 audio_debug("MilesAudioManager::audio_3d_set_listener_attributes()");
00445
00446 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00447 AIL_set_listener_3D_position(mgr->_digital_driver, px, pz, py);
00448 AIL_set_listener_3D_velocity_vector(mgr->_digital_driver, vx, vz, vy);
00449 AIL_set_listener_3D_orientation(mgr->_digital_driver, fx, fz, fy, ux, uz, uy);
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459 void MilesAudioManager::audio_3d_get_listener_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz, PN_stdfloat *fx, PN_stdfloat *fy, PN_stdfloat *fz, PN_stdfloat *ux, PN_stdfloat *uy, PN_stdfloat *uz) {
00460 audio_debug("MilesAudioManager::audio_3d_get_listener_attributes()");
00461
00462 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00463 float lpx, lpy, lpz, lvx, lvy, lvz, lfx, lfy, lfz, lux, luy, luz;
00464 AIL_listener_3D_position(mgr->_digital_driver, &lpx, &lpz, &lpy);
00465 AIL_listener_3D_velocity(mgr->_digital_driver, &lvx, &lvz, &lvy);
00466 AIL_listener_3D_orientation(mgr->_digital_driver, &lfx, &lfz, &lfy, &lux, &luz, &luy);
00467
00468 *px = lpx;
00469 *py = lpy;
00470 *pz = lpz;
00471 *vx = lvx;
00472 *vy = lvy;
00473 *vz = lvz;
00474 *fx = lfx;
00475 *fy = lfy;
00476 *fz = lfz;
00477 *ux = lux;
00478 *uy = luy;
00479 *uz = luz;
00480 }
00481
00482
00483
00484
00485
00486
00487
00488 void MilesAudioManager::audio_3d_set_distance_factor(PN_stdfloat factor) {
00489 audio_debug("MilesAudioManager::audio_3d_set_distance_factor( factor= " << factor << ")");
00490
00491 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00492 AIL_set_3D_distance_factor(mgr->_digital_driver, factor);
00493 }
00494
00495
00496
00497
00498
00499
00500 PN_stdfloat MilesAudioManager::audio_3d_get_distance_factor() const {
00501 audio_debug("MilesAudioManager::audio_3d_get_distance_factor()");
00502
00503 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00504 return AIL_3D_distance_factor(mgr->_digital_driver);
00505 }
00506
00507
00508
00509
00510
00511
00512
00513 void MilesAudioManager::audio_3d_set_doppler_factor(PN_stdfloat factor) {
00514 audio_debug("MilesAudioManager::audio_3d_set_doppler_factor(factor="<<factor<<")");
00515
00516 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00517 AIL_set_3D_doppler_factor(mgr->_digital_driver, factor);
00518 }
00519
00520
00521
00522
00523
00524
00525 PN_stdfloat MilesAudioManager::audio_3d_get_doppler_factor() const {
00526 audio_debug("MilesAudioManager::audio_3d_get_doppler_factor()");
00527
00528 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00529 return AIL_3D_doppler_factor(mgr->_digital_driver);
00530 }
00531
00532
00533
00534
00535
00536
00537
00538 void MilesAudioManager::audio_3d_set_drop_off_factor(PN_stdfloat factor) {
00539 audio_debug("MilesAudioManager::audio_3d_set_drop_off_factor("<<factor<<")");
00540
00541 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00542 AIL_set_3D_rolloff_factor(mgr->_digital_driver, factor);
00543 }
00544
00545
00546
00547
00548
00549
00550
00551 PN_stdfloat MilesAudioManager::audio_3d_get_drop_off_factor() const {
00552 audio_debug("MilesAudioManager::audio_3d_get_drop_off_factor()");
00553
00554 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00555 return AIL_3D_rolloff_factor(mgr->_digital_driver);
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 void MilesAudioManager::
00571 set_speaker_configuration(LVecBase3 *speaker1, LVecBase3 *speaker2, LVecBase3 *speaker3, LVecBase3 *speaker4, LVecBase3 *speaker5, LVecBase3 *speaker6, LVecBase3 *speaker7, LVecBase3 *speaker8, LVecBase3 *speaker9) {
00572 audio_debug("MilesAudioManager::set_speaker_configuration()");
00573
00574 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00575
00576 MSSVECTOR3D speakers[9];
00577
00578 if(speaker1 != NULL) {
00579 speakers[0].x = speaker1->get_x();
00580 speakers[0].y = speaker1->get_z();
00581 speakers[0].z = speaker1->get_y();
00582 }
00583 if(speaker2 != NULL) {
00584 speakers[1].x = speaker2->get_x();
00585 speakers[1].y = speaker2->get_z();
00586 speakers[1].z = speaker2->get_y();
00587 }
00588 if(speaker3 != NULL) {
00589 speakers[2].x = speaker3->get_x();
00590 speakers[2].y = speaker3->get_z();
00591 speakers[2].z = speaker3->get_y();
00592 }
00593 if(speaker4 != NULL) {
00594 speakers[3].x = speaker4->get_x();
00595 speakers[3].y = speaker4->get_z();
00596 speakers[3].z = speaker4->get_y();
00597 }
00598 if(speaker5 != NULL) {
00599 speakers[4].x = speaker5->get_x();
00600 speakers[4].y = speaker5->get_z();
00601 speakers[4].z = speaker5->get_y();
00602 }
00603 if(speaker6 != NULL) {
00604 speakers[5].x = speaker6->get_x();
00605 speakers[5].y = speaker6->get_z();
00606 speakers[5].z = speaker6->get_y();
00607 }
00608 if(speaker7 != NULL) {
00609 speakers[6].x = speaker7->get_x();
00610 speakers[6].y = speaker7->get_z();
00611 speakers[6].z = speaker7->get_y();
00612 }
00613 if(speaker8 != NULL) {
00614 speakers[7].x = speaker8->get_x();
00615 speakers[7].y = speaker8->get_z();
00616 speakers[7].z = speaker8->get_y();
00617 }
00618 if(speaker9 != NULL) {
00619 speakers[8].x = speaker9->get_x();
00620 speakers[8].y = speaker9->get_z();
00621 speakers[8].z = speaker9->get_y();
00622 }
00623
00624 if(speaker1 == NULL) {
00625 audio_error("No valid speaker positions specified in MilesAudioManager::set_speaker_configuration().");
00626 } else if(speaker2 == NULL) {
00627 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 1, 1.0);
00628 } else if(speaker3 == NULL) {
00629 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 2, 1.0);
00630 } else if(speaker4 == NULL) {
00631 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 3, 1.0);
00632 } else if(speaker5 == NULL) {
00633 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 4, 1.0);
00634 } else if(speaker6 == NULL) {
00635 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 5, 1.0);
00636 } else if(speaker7 == NULL) {
00637 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 6, 1.0);
00638 } else if(speaker8 == NULL) {
00639 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 7, 1.0);
00640 } else if(speaker9 == NULL) {
00641 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 8, 1.0);
00642 } else {
00643 AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 9, 1.0);
00644 }
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654 void MilesAudioManager::
00655 update() {
00656 {
00657 MutexHolder holder(_streams_lock);
00658 if (_stream_thread.is_null() && !_streams.empty()) {
00659
00660
00661 do_service_streams();
00662 }
00663 }
00664
00665 if (_sounds_finished) {
00666 _sounds_finished = false;
00667
00668
00669
00670
00671
00672
00673
00674 SoundsPlaying::iterator si = _sounds_playing.begin();
00675 while (si != _sounds_playing.end()) {
00676 MilesAudioSound *sound = (*si);
00677 ++si;
00678
00679 if (sound->status() == AudioSound::READY) {
00680 sound->stop();
00681 }
00682 }
00683 }
00684 }
00685
00686
00687
00688
00689
00690
00691 void MilesAudioManager::
00692 release_sound(MilesAudioSound *audioSound) {
00693 audio_debug("MilesAudioManager::release_sound(audioSound=\""
00694 <<audioSound->get_name()<<"\"), this = " << (void *)this);
00695 LightReMutexHolder holder(_lock);
00696 AudioSet::iterator ai = _sounds_on_loan.find(audioSound);
00697 if (ai != _sounds_on_loan.end()) {
00698 _sounds_on_loan.erase(ai);
00699 }
00700
00701 audio_debug("MilesAudioManager::release_sound() finished");
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711 void MilesAudioManager::
00712 cleanup() {
00713 audio_debug("MilesAudioManager::cleanup(), this = " << (void *)this
00714 << ", _cleanup_required = " << _cleanup_required);
00715 LightReMutexHolder holder(_lock);
00716 if (!_cleanup_required) {
00717 return;
00718 }
00719
00720
00721 AudioSet orig_sounds;
00722 orig_sounds.swap(_sounds_on_loan);
00723 AudioSet::iterator ai;
00724 for (ai = orig_sounds.begin(); ai != orig_sounds.end(); ++ai) {
00725 (*ai)->cleanup();
00726 }
00727
00728 do_clear_cache();
00729
00730
00731 if (!_stream_thread.is_null()) {
00732 milesAudio_cat.info()
00733 << "Stopping audio streaming thread.\n";
00734 PT(StreamThread) old_thread;
00735 {
00736 MutexHolder holder(_streams_lock);
00737 nassertv(!_stream_thread.is_null());
00738 _stream_thread->_keep_running = false;
00739 _streams_cvar.notify();
00740 old_thread = _stream_thread;
00741 _stream_thread.clear();
00742 }
00743 old_thread->join();
00744 }
00745
00746 _cleanup_required = false;
00747 audio_debug("MilesAudioManager::cleanup() finished");
00748 }
00749
00750
00751
00752
00753
00754
00755 void MilesAudioManager::
00756 output(ostream &out) const {
00757 LightReMutexHolder holder(_lock);
00758 out << get_type() << ": " << _sounds_playing.size()
00759 << " / " << _sounds_on_loan.size() << " sounds playing / total";
00760 }
00761
00762
00763
00764
00765
00766
00767 void MilesAudioManager::
00768 write(ostream &out) const {
00769 LightReMutexHolder holder(_lock);
00770
00771 out << (*this) << "\n";
00772 AudioSet::const_iterator ai;
00773 for (ai = _sounds_on_loan.begin(); ai != _sounds_on_loan.end(); ++ai) {
00774 MilesAudioSound *sound = (*ai);
00775 out << " " << *sound << "\n";
00776 }
00777
00778 size_t total_preload = 0;
00779 size_t num_preloaded = 0;
00780 SoundMap::const_iterator si;
00781 for (si = _sounds.begin(); si != _sounds.end(); ++si) {
00782 if (!(*si).second->_raw_data.empty()) {
00783 ++num_preloaded;
00784 total_preload += (*si).second->_raw_data.size();
00785 }
00786 }
00787 out << num_preloaded << " of " << _sounds.size() << " sounds preloaded, size used is " << (total_preload + 1023) / 1024 << "K\n";
00788
00789 {
00790 MutexHolder holder(_streams_lock);
00791 out << _streams.size() << " streams opened.\n";
00792 if (!_stream_thread.is_null()) {
00793 out << "(Audio streaming thread has been started.)\n";
00794 }
00795 }
00796
00797 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00798
00799 int num_samples = mgr->get_num_samples();
00800 out << num_samples << " sample handles allocated globally.\n";
00801
00802 int num_sequences = mgr->get_num_sequences();
00803 out << num_sequences << " sequence handles allocated globally.\n";
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813 bool MilesAudioManager::
00814 do_is_valid() {
00815 bool check = true;
00816 if (_sounds.size() != _lru.size()) {
00817 audio_debug("-- Error _sounds.size() != _lru.size() --");
00818 check = false;
00819
00820 } else {
00821 LRU::const_iterator i = _lru.begin();
00822 for (; i != _lru.end(); ++i) {
00823 SoundMap::const_iterator smi = _sounds.find(**i);
00824 if (smi == _sounds.end()) {
00825 audio_debug("-- "<<**i<<" in _lru and not in _sounds --");
00826 check = false;
00827 break;
00828 }
00829 }
00830 }
00831 return _is_valid && check;
00832 }
00833
00834
00835
00836
00837
00838
00839 void MilesAudioManager::
00840 do_reduce_sounds_playing_to(unsigned int count) {
00841 int limit = _sounds_playing.size() - count;
00842 while (limit-- > 0) {
00843 SoundsPlaying::iterator sound = _sounds_playing.begin();
00844 assert(sound != _sounds_playing.end());
00845 (**sound).stop();
00846 }
00847 }
00848
00849
00850
00851
00852
00853
00854 void MilesAudioManager::
00855 do_clear_cache() {
00856 if (_is_valid) { nassertv(do_is_valid()); }
00857 _sounds.clear();
00858 _lru.clear();
00859 if (_is_valid) { nassertv(do_is_valid()); }
00860 }
00861
00862
00863
00864
00865
00866
00867
00868
00869 void MilesAudioManager::
00870 start_service_stream(HSTREAM stream) {
00871 MutexHolder holder(_streams_lock);
00872 nassertv(find(_streams.begin(), _streams.end(), stream) == _streams.end());
00873 _streams.push_back(stream);
00874 _streams_cvar.notify();
00875
00876 if (_stream_thread.is_null() && Thread::is_threading_supported()) {
00877 milesAudio_cat.info()
00878 << "Starting audio streaming thread.\n";
00879 _stream_thread = new StreamThread(this);
00880 _stream_thread->start(TP_low, true);
00881 }
00882 }
00883
00884
00885
00886
00887
00888
00889
00890 void MilesAudioManager::
00891 stop_service_stream(HSTREAM stream) {
00892 MutexHolder holder(_streams_lock);
00893 Streams::iterator si = find(_streams.begin(), _streams.end(), stream);
00894 if (si != _streams.end()) {
00895 _streams.erase(si);
00896 }
00897 }
00898
00899
00900
00901
00902
00903
00904
00905 void MilesAudioManager::
00906 most_recently_used(const string &path) {
00907 audio_debug("MilesAudioManager::most_recently_used(path=\""
00908 <<path<<"\")");
00909 LRU::iterator i=find(_lru.begin(), _lru.end(), &path);
00910 if (i != _lru.end()) {
00911 _lru.erase(i);
00912 }
00913
00914 assert(find(_lru.begin(), _lru.end(), &path) == _lru.end());
00915 _lru.push_back(&path);
00916 nassertv(do_is_valid());
00917 }
00918
00919
00920
00921
00922
00923
00924 void MilesAudioManager::
00925 uncache_a_sound() {
00926 audio_debug("MilesAudioManager::uncache_a_sound()");
00927 nassertv(do_is_valid());
00928
00929 assert(_lru.size()>0);
00930 LRU::reference path=_lru.front();
00931 SoundMap::iterator i = _sounds.find(*path);
00932 assert(i != _sounds.end());
00933 _lru.pop_front();
00934
00935 if (i != _sounds.end()) {
00936 audio_debug(" uncaching \""<<i->first<<"\"");
00937 _sounds.erase(i);
00938 }
00939 nassertv(do_is_valid());
00940 }
00941
00942
00943
00944
00945
00946
00947 void MilesAudioManager::
00948 starting_sound(MilesAudioSound *audio) {
00949 LightReMutexHolder holder(_lock);
00950 if (_concurrent_sound_limit) {
00951 do_reduce_sounds_playing_to(_concurrent_sound_limit);
00952 }
00953 _sounds_playing.insert(audio);
00954 }
00955
00956
00957
00958
00959
00960
00961
00962
00963 void MilesAudioManager::
00964 stopping_sound(MilesAudioSound *audio) {
00965 LightReMutexHolder holder(_lock);
00966 _sounds_playing.erase(audio);
00967 if (_hasMidiSounds && _sounds_playing.size() == 0) {
00968 GlobalMilesManager::get_global_ptr()->force_midi_reset();
00969 }
00970 }
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981 PT(MilesAudioManager::SoundData) MilesAudioManager::
00982 load(const Filename &file_name) {
00983 PT(SoundData) sd = new SoundData;
00984
00985 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00986 PT(VirtualFile) file = vfs->get_file(file_name);
00987 if (file == (VirtualFile *)NULL) {
00988 milesAudio_cat.warning()
00989 << "No such file: " << file_name << "\n";
00990 return NULL;
00991 }
00992
00993 if (file->get_file_size() == 0) {
00994 milesAudio_cat.warning()
00995 << "File " << file_name << " is empty\n";
00996 return NULL;
00997 }
00998
00999 sd->_basename = file_name.get_basename();
01000
01001 string extension = sd->_basename.get_extension();
01002 if (extension == "pz") {
01003 extension = Filename(sd->_basename.get_basename_wo_extension()).get_extension();
01004 }
01005
01006 bool is_midi_file = (downcase(extension) == "mid");
01007
01008 if ((miles_audio_preload_threshold == -1 || file->get_file_size() < (off_t)miles_audio_preload_threshold) ||
01009 is_midi_file) {
01010
01011
01012
01013
01014 if (!file->read_file(sd->_raw_data, true)) {
01015 milesAudio_cat.warning()
01016 << "Unable to read " << file_name << "\n";
01017 return NULL;
01018 }
01019
01020 sd->_file_type =
01021 AIL_file_type(&sd->_raw_data[0], sd->_raw_data.size());
01022
01023 if (sd->_file_type == AILFILETYPE_MIDI) {
01024
01025
01026 void *xmi;
01027 U32 xmi_size;
01028 if (AIL_MIDI_to_XMI(&sd->_raw_data[0], sd->_raw_data.size(),
01029 &xmi, &xmi_size, 0)) {
01030 audio_debug("converted " << sd->_basename << " from standard MIDI ("
01031 << sd->_raw_data.size() << " bytes) to XMIDI ("
01032 << xmi_size << " bytes)");
01033
01034
01035
01036 sd->_raw_data.clear();
01037 sd->_raw_data.insert(sd->_raw_data.end(),
01038 (unsigned char *)xmi, (unsigned char *)xmi + xmi_size);
01039 AIL_mem_free_lock(xmi);
01040 sd->_file_type = AILFILETYPE_XMIDI;
01041 } else {
01042 milesAudio_cat.warning()
01043 << "Could not convert " << sd->_basename << " to XMIDI.\n";
01044 }
01045 }
01046
01047 bool expand_to_wav = false;
01048
01049 if (sd->_file_type != AILFILETYPE_MPEG_L3_AUDIO) {
01050 audio_debug(sd->_basename << " is not an mp3 file.");
01051 } else if ((int)sd->_raw_data.size() >= miles_audio_expand_mp3_threshold) {
01052 audio_debug(sd->_basename << " is too large to expand in-memory.");
01053 } else {
01054 audio_debug(sd->_basename << " will be expanded in-memory.");
01055 expand_to_wav = true;
01056 }
01057
01058 if (expand_to_wav) {
01059
01060
01061
01062 void *wav_data;
01063 U32 wav_data_size;
01064 if (AIL_decompress_ASI(&sd->_raw_data[0], sd->_raw_data.size(),
01065 sd->_basename.c_str(), &wav_data, &wav_data_size,
01066 NULL)) {
01067 audio_debug("expanded " << sd->_basename << " from " << sd->_raw_data.size()
01068 << " bytes to " << wav_data_size << " bytes.");
01069
01070 if (wav_data_size != 0) {
01071
01072
01073 sd->_raw_data.clear();
01074 sd->_raw_data.insert(sd->_raw_data.end(),
01075 (unsigned char *)wav_data, (unsigned char *)wav_data + wav_data_size);
01076 sd->_file_type = AILFILETYPE_PCM_WAV;
01077 sd->_basename.set_extension("wav");
01078 }
01079 AIL_mem_free_lock(wav_data);
01080
01081 } else {
01082 audio_debug("unable to expand " << sd->_basename);
01083 }
01084 }
01085
01086 } else {
01087
01088
01089
01090 }
01091
01092 return sd;
01093 }
01094
01095
01096
01097
01098
01099
01100
01101 void MilesAudioManager::
01102 thread_main(volatile bool &keep_running) {
01103 MutexHolder holder(_streams_lock);
01104
01105 while (keep_running) {
01106 if (_streams.empty()) {
01107
01108
01109 _streams_cvar.wait();
01110 } else {
01111 do_service_streams();
01112 }
01113
01114
01115 _streams_lock.release();
01116 Thread::force_yield();
01117 _streams_lock.acquire();
01118 }
01119 }
01120
01121
01122
01123
01124
01125
01126
01127 void MilesAudioManager::
01128 do_service_streams() {
01129 size_t i = 0;
01130 while (i < _streams.size()) {
01131 HSTREAM stream = _streams[i];
01132
01133
01134 _streams_lock.release();
01135 AIL_service_stream(stream, 0);
01136 Thread::consider_yield();
01137 _streams_lock.acquire();
01138
01139 ++i;
01140 }
01141 }
01142
01143
01144
01145
01146
01147
01148 MilesAudioManager::StreamThread::
01149 StreamThread(MilesAudioManager *mgr) :
01150 Thread("StreamThread", "StreamThread"),
01151 _mgr(mgr)
01152 {
01153 _keep_running = true;
01154 }
01155
01156
01157
01158
01159
01160
01161 void MilesAudioManager::StreamThread::
01162 thread_main() {
01163 _mgr->thread_main(_keep_running);
01164 }
01165
01166
01167
01168
01169
01170
01171 MilesAudioManager::SoundData::
01172 SoundData() :
01173 _raw_data(MilesAudioManager::get_class_type()),
01174 _has_length(false),
01175 _length(0.0f)
01176 {
01177 }
01178
01179
01180
01181
01182
01183
01184 MilesAudioManager::SoundData::
01185 ~SoundData() {
01186 }
01187
01188
01189
01190
01191
01192
01193 PN_stdfloat MilesAudioManager::SoundData::
01194 get_length() {
01195 if (!_has_length) {
01196
01197
01198 if (_raw_data.empty()) {
01199 _length = 0.0f;
01200 _has_length = true;
01201
01202 } else if (_file_type == AILFILETYPE_MPEG_L3_AUDIO) {
01203
01204
01205 audio_debug("Computing length of mp3 file " << _basename);
01206
01207 MP3_INFO info;
01208 AIL_inspect_MP3(&info, &_raw_data[0], _raw_data.size());
01209 _length = 0.0f;
01210 while (AIL_enumerate_MP3_frames(&info)) {
01211 _length += info.data_size * 8.0f / info.bit_rate;
01212 }
01213 _has_length = true;
01214
01215 } else if (_file_type == AILFILETYPE_PCM_WAV ||
01216 _file_type == AILFILETYPE_ADPCM_WAV ||
01217 _file_type == AILFILETYPE_OTHER_ASI_WAV) {
01218 audio_debug("Getting length of wav file " << _basename);
01219
01220 AILSOUNDINFO info;
01221 if (AIL_WAV_info(&_raw_data[0], &info)) {
01222 _length = (PN_stdfloat)info.samples / (PN_stdfloat)info.rate;
01223 audio_debug(info.samples << " samples at " << info.rate
01224 << "; length is " << _length << " seconds.");
01225 _has_length = true;
01226 }
01227 }
01228 }
01229
01230 nassertr(_has_length, 0.0f);
01231 return _length;
01232 }
01233
01234
01235
01236
01237
01238
01239 void MilesAudioManager::SoundData::
01240 set_length(PN_stdfloat length) {
01241 _length = length;
01242 _has_length = true;
01243 }
01244
01245 #endif //]