Panda3D

milesAudioManager.cxx

00001 // Filename: milesAudioManager.cxx
00002 // Created by:  skyler (June 6, 2001)
00003 // Prior system by: cary
00004 //
00005 ////////////////////////////////////////////////////////////////////
00006 //
00007 // PANDA 3D SOFTWARE
00008 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00009 //
00010 // All use of this software is subject to the terms of the revised BSD
00011 // license.  You should have received a copy of this license along
00012 // with this source code in a file named "LICENSE."
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 //     Function: MilesAudioManager::Constructor
00045 //       Access: Public
00046 //  Description: Create an audio manager.  This may open the Miles
00047 //               sound system if there were no other MilesAudioManager
00048 //               instances.  Subsequent managers may use the same
00049 //               Miles resources.
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   // We used to hang a call to a force-shutdown function on atexit(),
00073   // so that any running sounds (particularly MIDI sounds) would be
00074   // silenced on exit, especially a sudden exit triggered by a Python
00075   // exception.  But that causes problems because Miles itself also
00076   // hangs a force-shutdown function on atexit(), and you can't call
00077   // AIL_cleanup() twice--that results in a crash.
00078 
00079   // Nowadays, we provide the AudioManager::shutdown() method instead,
00080   // which allows the app to force all sounds to stop cleanly before
00081   // we get to the atexit() stack.  In Python, we guarantee that this
00082   // method will be called in the sys.exitfunc chain.
00083 }
00084 
00085 ////////////////////////////////////////////////////////////////////
00086 //     Function: MilesAudioManager::Destructor
00087 //       Access: Public, Virtual
00088 //  Description: Clean up this audio manager and possibly release
00089 //               the Miles resources that are reserved by the 
00090 //               application (the later happens if this is the last
00091 //               active manager).
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 //     Function: MilesAudioManager::shutdown
00105 //       Access: Public, Virtual
00106 //  Description: Call this at exit time to shut down the audio system.
00107 //               This will invalidate all currently-active
00108 //               AudioManagers and AudioSounds in the system.  If you
00109 //               change your mind and want to play sounds again, you
00110 //               will have to recreate all of these objects.
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 //     Function: MilesAudioManager::is_valid
00121 //       Access: Public, Virtual
00122 //  Description: This is mostly for debugging, but it it could be
00123 //               used to detect errors in a release build if you
00124 //               don't mind the cpu cost.
00125 ////////////////////////////////////////////////////////////////////
00126 bool MilesAudioManager::
00127 is_valid() {
00128   LightReMutexHolder holder(_lock);
00129   return do_is_valid();
00130 }
00131 
00132 ////////////////////////////////////////////////////////////////////
00133 //     Function: MilesAudioManager::get_sound
00134 //       Access: Public, Virtual
00135 //  Description:
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   // Get the sound, either from the cache or from a loader:
00156   SoundMap::const_iterator si=_sounds.find(path);
00157   if (si != _sounds.end()) {
00158     // ...found the sound in the cache.
00159     sd = (*si).second;
00160     audio_debug("  sound found in pool 0x" << (void*)sd);
00161 
00162   } else {
00163     // ...the sound was not found in the cache/pool.
00164     sd = load(path);
00165     if (sd != (SoundData *)NULL) {
00166       while (_sounds.size() >= (unsigned int)_cache_limit) {
00167         uncache_a_sound();
00168       }
00169       // Put it in the pool:
00170       // The following is roughly like: _sounds[path] = sd;
00171       // But, it gives us an iterator into the map.
00172       pair<SoundMap::const_iterator, bool> ib
00173           = _sounds.insert(SoundMap::value_type(path, sd));
00174       if (!ib.second) {
00175         // The insert failed.
00176         audio_debug("  failed map insert of "<<path);
00177         nassertr(do_is_valid(), NULL);
00178         return get_null_sound();
00179       }
00180       // Set si, so that we can get a reference to the path
00181       // for the MilesAudioSound.
00182       si=ib.first;
00183     }
00184   }
00185   // Create an AudioSound from the sound:
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       // MIDI file.
00195       audioSound = new MilesAudioSequence(this, sd, file_name);
00196 
00197     } else if (!sd->_raw_data.empty()) {
00198       // WAV or MP3 file preloaded into memory.
00199       audioSound = new MilesAudioSample(this, sd, file_name);
00200 
00201     } else {
00202       // WAV or MP3 file streamed from disk.
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     // Couldn't load the file; just return a NullAudioSound.
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 //     Function: MilesAudioManager::get_sound
00224 //       Access: Public, Virtual
00225 //  Description:
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 //     Function: MilesAudioManager::uncache_sound
00235 //       Access: Public, Virtual
00236 //  Description:
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 //     Function: MilesAudioManager::clear_cache
00263 //       Access: Public, Virtual
00264 //  Description: Clear out the sound cache.
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 //     Function: MilesAudioManager::set_cache_limit
00275 //       Access: Public, Virtual
00276 //  Description: Set the number of sounds that the cache can hold.
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 //     Function: MilesAudioManager::get_cache_limit
00293 //       Access: Public, Virtual
00294 //  Description:
00295 ////////////////////////////////////////////////////////////////////
00296 unsigned int MilesAudioManager::
00297 get_cache_limit() const {
00298   return _cache_limit;
00299 }
00300 
00301 ////////////////////////////////////////////////////////////////////
00302 //     Function: MilesAudioManager::set_volume
00303 //       Access: Public, Virtual
00304 //  Description: set the overall volume
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     // Tell our AudioSounds to adjust:
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 //     Function: MilesAudioManager::get_volume
00322 //       Access: Public, Virtual
00323 //  Description: get the overall volume
00324 ////////////////////////////////////////////////////////////////////
00325 PN_stdfloat MilesAudioManager::
00326 get_volume() const {
00327   return _volume;
00328 }
00329 
00330 ////////////////////////////////////////////////////////////////////
00331 //     Function: MilesAudioManager::set_play_rate
00332 //       Access: Public
00333 //  Description: set the overall play rate
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     // Tell our AudioSounds to adjust:
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 //     Function: MilesAudioManager::get_play_rate
00351 //       Access: Public
00352 //  Description: get the overall speed/pitch/play rate
00353 ////////////////////////////////////////////////////////////////////
00354 PN_stdfloat MilesAudioManager::
00355 get_play_rate() const {
00356   return _play_rate;
00357 }
00358 
00359 ////////////////////////////////////////////////////////////////////
00360 //     Function: MilesAudioManager::set_active
00361 //       Access: Public, Virtual
00362 //  Description: turn on/off
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     // Tell our AudioSounds to adjust:
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 //     Function: MilesAudioManager::get_active
00384 //       Access: Public, Virtual
00385 //  Description:
00386 ////////////////////////////////////////////////////////////////////
00387 bool MilesAudioManager::
00388 get_active() const {
00389   return _active;
00390 }
00391 
00392 ////////////////////////////////////////////////////////////////////
00393 //     Function: MilesAudioManager::set_concurrent_sound_limit
00394 //       Access: Public, Virtual
00395 //  Description: 
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 //     Function: MilesAudioManager::get_concurrent_sound_limit
00406 //       Access: Public, Virtual
00407 //  Description: 
00408 ////////////////////////////////////////////////////////////////////
00409 unsigned int MilesAudioManager::
00410 get_concurrent_sound_limit() const {
00411   return _concurrent_sound_limit;
00412 }
00413 
00414 ////////////////////////////////////////////////////////////////////
00415 //     Function: MilesAudioManager::reduce_sounds_playing_to
00416 //       Access: Public, Virtual
00417 //  Description: 
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 //     Function: MilesAudioManager::stop_all_sounds
00427 //       Access: Public, Virtual
00428 //  Description: Stop playback on all sounds managed by this manager.
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 //     Function: MilesAudioManager::audio_3d_set_listener_attributes
00438 //       Access: Public
00439 //  Description: Set spatial attributes of the listener for 3D
00440 //               sounds.  Note that Y and Z are switched to
00441 //               translate into Miles's coordinate system.
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 //     Function: MilesAudioManager::audio_3d_get_listener_attributes
00454 //       Access: Public
00455 //  Description: Get spatial attributes of the listener for 3D
00456 //               sounds.  Note that Y and Z are switched to
00457 //               translate from Miles's coordinate system.
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 //     Function: MilesAudioManager::audio_3d_set_distance_factor
00484 //       Access: Public
00485 //  Description: Set factor to allow user to easily work in a
00486 //               different scale.  1.0 represents meters.
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 //     Function: MilesAudioManager::audio_3d_get_distance_factor
00497 //       Access: Public
00498 //  Description: Get factor controlling working units.
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 //     Function: MilesAudioManager::audio_3d_set_doppler_factor
00509 //       Access: Public
00510 //  Description: Exaggerates or diminishes the Doppler effect. 
00511 //               Defaults to 1.0
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 //     Function: MilesAudioManager::audio_3d_get_doppler_factor
00522 //       Access: Public
00523 //  Description: Get the factor controlling the Doppler effect.
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 //     Function: MilesAudioManager::audio_3d_set_drop_off_factor
00534 //       Access: Public
00535 //  Description: Control the effect distance has on audability.
00536 //               Defaults to 1.0
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 //     Function: MilesAudioManager::audio_3d_get_drop_off_factor
00547 //       Access: Public
00548 //  Description: Get the factor controlling how quickly sound falls
00549 //               off with distance.
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 //     Function: MilesAudioManager::set_speaker_configuration
00560 //       Access: Published
00561 //  Description: Works similarly to MilesAudioSound::set_speaker_levels,
00562 //               but specifies the 3D positions of the speakers in space.
00563 //
00564 //               Once a NULL value is found for a speaker position,
00565 //               no more speaker positions will be used.
00566 //
00567 //               Note that Y and Z are switched to translate from Miles's
00568 //               coordinate system.
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 //     Function: MilesAudioManager::update()
00649 //       Access: Public, Virtual
00650 //  Description: Must be called every frame.  Failure to call this
00651 //               every frame could cause problems for some audio
00652 //               managers.
00653 ////////////////////////////////////////////////////////////////////
00654 void MilesAudioManager::
00655 update() {
00656   {
00657     MutexHolder holder(_streams_lock);
00658     if (_stream_thread.is_null() && !_streams.empty()) {
00659       // If we don't have a sub-thread, we have to service the streams
00660       // in the main thread.
00661       do_service_streams();
00662     }
00663   }
00664 
00665   if (_sounds_finished) {
00666     _sounds_finished = false;
00667     
00668     // If the _sounds_finished flag was set, we should scan our list
00669     // of playing sounds and see if any of them have finished
00670     // recently.  We don't do this in the finished callback, because
00671     // that might have been called in a sub-thread (and we may not
00672     // have threading supported--and mutex protection--compiled in).
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 //     Function: MilesAudioManager::release_sound
00688 //       Access: Public
00689 //  Description:
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 //     Function: MilesAudioManager::cleanup
00706 //       Access: Public
00707 //  Description: Shuts down the audio manager and releases any
00708 //               resources associated with it.  Also cleans up all
00709 //               AudioSounds created via the manager.
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   // Be sure to cleanup associated sounds before cleaning up the manager:
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   // Now stop the thread, if it has been started.
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 //     Function: MilesAudioManager::output
00752 //       Access: Public, Virtual
00753 //  Description: 
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 //     Function: MilesAudioManager::write
00764 //       Access: Public, Virtual
00765 //  Description: 
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 //     Function: MilesAudioManager::do_is_valid
00809 //       Access: Private
00810 //  Description: Implementation of is_valid().  Assumes the lock is
00811 //               already held.
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 //     Function: MilesAudioManager::do_reduce_sounds_playing_to
00836 //       Access: Private
00837 //  Description: Assumes the lock is already held.
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 //     Function: MilesAudioManager::do_clear_cache
00851 //       Access: Private
00852 //  Description: Assumes the lock is already held.
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 //     Function: MilesAudioManager::start_service_stream
00864 //       Access: Private
00865 //  Description: Adds the indicated stream to the list of streams to
00866 //               be serviced by a Panda sub-thread.  This is in lieu
00867 //               of Miles' auto-service-stream mechanism.
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 //     Function: MilesAudioManager::stop_service_stream
00886 //       Access: Private
00887 //  Description: Removes the indicated stream from the list of streams
00888 //               to be serviced by a Panda sub-thread.
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 //     Function: MilesAudioManager::most_recently_used
00902 //       Access: Private
00903 //  Description: Assumes the lock is already held.
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   // At this point, path should not exist in the _lru:
00914   assert(find(_lru.begin(), _lru.end(), &path) == _lru.end());
00915   _lru.push_back(&path);
00916   nassertv(do_is_valid());
00917 }
00918 
00919 ////////////////////////////////////////////////////////////////////
00920 //     Function: MilesAudioManager::uncache_a_sound
00921 //       Access: Private
00922 //  Description: Assumes the lock is already held.
00923 ////////////////////////////////////////////////////////////////////
00924 void MilesAudioManager::
00925 uncache_a_sound() {
00926   audio_debug("MilesAudioManager::uncache_a_sound()");
00927   nassertv(do_is_valid());
00928   // uncache least recently used:
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 //     Function: MilesAudioManager::starting_sound
00944 //       Access: Private
00945 //  Description: Inform the manager that a sound is about to play.
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 //     Function: MilesAudioManager::stopping_sound
00958 //       Access: Private
00959 //  Description: Inform the manager that a sound is finished or 
00960 //               someone called stop on the sound (this should not
00961 //               be called if a sound is only paused).
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 //     Function: MilesAudioManager::load
00974 //       Access: Private
00975 //  Description: Reads a sound file and allocates a SoundData pointer
00976 //               for it.  Returns NULL if the sound file cannot be
00977 //               loaded.
00978 //
00979 //               Assumes the lock is already held.
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     // If the file is sufficiently small, we'll preload it into
01011     // memory.  MIDI files cannot be streamed, so we always preload
01012     // them, regardless of size.
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       // A standard MIDI file.  We have to convert this to XMIDI for
01025       // Miles.
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         // Copy the data to our own buffer and free the
01035         // Miles-allocated data.
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       // Now convert the file to WAV format in-memory.  This is useful
01060       // to work around seek and length problems associated with
01061       // variable bit-rate MP3 encoding.
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           // Now copy the memory into our own buffers, and free the
01072           // Miles-allocated memory.
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     // If the file is large, we'll stream it from disk instead of
01088     // preloading it.  This means we don't need to load any data at
01089     // this point.
01090   }
01091 
01092   return sd;
01093 }
01094 
01095 ////////////////////////////////////////////////////////////////////
01096 //     Function: MilesAudioManager::thread_main
01097 //       Access: Private
01098 //  Description: Called to service the streaming audio channels
01099 //               currently playing on the audio manager.
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       // If there are no streams to service, block on the condition
01108       // variable.
01109       _streams_cvar.wait();
01110     } else {
01111       do_service_streams();
01112     }
01113 
01114     // Now yield to be polite to the main application.
01115     _streams_lock.release();
01116     Thread::force_yield();
01117     _streams_lock.acquire();
01118   }
01119 }
01120 
01121 ////////////////////////////////////////////////////////////////////
01122 //     Function: MilesAudioManager::do_service_streams
01123 //       Access: Private
01124 //  Description: Internal function to service all the streams.
01125 //               Assumes _streams_lock is already held.
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     // We must release the lock while we are servicing stream i.
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 //     Function: MilesAudioManager::StreamThread::Constructor
01145 //       Access: Public
01146 //  Description: 
01147 ////////////////////////////////////////////////////////////////////
01148 MilesAudioManager::StreamThread::
01149 StreamThread(MilesAudioManager *mgr) : 
01150   Thread("StreamThread", "StreamThread"),
01151   _mgr(mgr) 
01152 {
01153   _keep_running = true;
01154 }
01155 
01156 ////////////////////////////////////////////////////////////////////
01157 //     Function: MilesAudioManager::StreamThread::thread_main
01158 //       Access: Public, Virtual
01159 //  Description: 
01160 ////////////////////////////////////////////////////////////////////
01161 void MilesAudioManager::StreamThread::
01162 thread_main() {
01163   _mgr->thread_main(_keep_running);
01164 }
01165 
01166 ////////////////////////////////////////////////////////////////////
01167 //     Function: MilesAudioManager::SoundData::Constructor
01168 //       Access: Public
01169 //  Description: 
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 //     Function: MilesAudioManager::SoundData::Destructor
01181 //       Access: Public
01182 //  Description: 
01183 ////////////////////////////////////////////////////////////////////
01184 MilesAudioManager::SoundData::
01185 ~SoundData() {
01186 }
01187 
01188 ////////////////////////////////////////////////////////////////////
01189 //     Function: MilesAudioManager::SoundData::get_length
01190 //       Access: Public
01191 //  Description: 
01192 ////////////////////////////////////////////////////////////////////
01193 PN_stdfloat MilesAudioManager::SoundData::
01194 get_length() {
01195   if (!_has_length) {
01196     // Time to determine the length of the file.
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       // If it's an mp3 file, we have to calculate its length by
01204       // walking through all of its frames.
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 //     Function: MilesAudioManager::SoundData::set_length
01236 //       Access: Public
01237 //  Description: Records the sample length, as determined externally.
01238 ////////////////////////////////////////////////////////////////////
01239 void MilesAudioManager::SoundData::
01240 set_length(PN_stdfloat length) {
01241   _length = length;
01242   _has_length = true;
01243 }
01244 
01245 #endif //]
 All Classes Functions Variables Enumerations