Panda3D
|
00001 // Filename: milesAudioSequence.cxx 00002 // Created by: drose (31Jul07) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "milesAudioSequence.h" 00016 00017 #ifdef HAVE_RAD_MSS //[ 00018 00019 #include "milesAudioManager.h" 00020 00021 00022 TypeHandle MilesAudioSequence::_type_handle; 00023 00024 #undef miles_audio_debug 00025 00026 #ifndef NDEBUG //[ 00027 #define miles_audio_debug(x) \ 00028 audio_debug("MilesAudioSequence \""<<get_name()<<"\" "<< x ) 00029 #else //][ 00030 #define miles_audio_debug(x) ((void)0) 00031 #endif //] 00032 00033 //////////////////////////////////////////////////////////////////// 00034 // Function: MilesAudioSequence::Constructor 00035 // Access: Private 00036 // Description: This constructor is called only by the 00037 // MilesAudioManager. 00038 //////////////////////////////////////////////////////////////////// 00039 MilesAudioSequence:: 00040 MilesAudioSequence(MilesAudioManager *manager, MilesAudioManager::SoundData *sd, 00041 const string &file_name) : 00042 MilesAudioSound(manager, file_name), 00043 _sd(sd) 00044 { 00045 nassertv(sd != NULL); 00046 audio_debug("MilesAudioSequence(manager=0x"<<(void*)&manager 00047 <<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")"); 00048 00049 _sequence = 0; 00050 _sequence_index = 0; 00051 } 00052 00053 //////////////////////////////////////////////////////////////////// 00054 // Function: MilesAudioSequence::Destructor 00055 // Access: Public, Virtual 00056 // Description: 00057 //////////////////////////////////////////////////////////////////// 00058 MilesAudioSequence:: 00059 ~MilesAudioSequence() { 00060 miles_audio_debug("~MilesAudioSequence()"); 00061 cleanup(); 00062 _manager->release_sound(this); 00063 miles_audio_debug("~MilesAudioSequence() done"); 00064 } 00065 00066 //////////////////////////////////////////////////////////////////// 00067 // Function: MilesAudioSequence::play 00068 // Access: Public, Virtual 00069 // Description: 00070 //////////////////////////////////////////////////////////////////// 00071 void MilesAudioSequence:: 00072 play() { 00073 miles_audio_debug("play()"); 00074 if (_active) { 00075 stop(); 00076 00077 if (_sd->_raw_data.empty()) { 00078 milesAudio_cat.warning() 00079 << "Could not play " << _file_name << ": no data\n"; 00080 } else { 00081 _manager->starting_sound(this); 00082 nassertv(_sequence == 0); 00083 00084 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr(); 00085 if (!mgr->get_sequence(_sequence, _sequence_index, this)){ 00086 milesAudio_cat.warning() 00087 << "Could not play " << _file_name << ": too many open sequences\n"; 00088 _sequence = 0; 00089 } else { 00090 AIL_init_sequence(_sequence, &_sd->_raw_data[0], 0); 00091 AIL_set_sequence_user_data(_sequence, 0, (SINTa)this); 00092 AIL_register_sequence_callback(_sequence, finish_callback); 00093 00094 set_volume(_volume); 00095 set_play_rate(_play_rate); 00096 AIL_set_sequence_loop_count(_sequence, _loop_count); 00097 00098 if (_got_start_time) { 00099 do_set_time(_start_time); 00100 AIL_resume_sequence(_sequence); 00101 } else { 00102 AIL_start_sequence(_sequence); 00103 } 00104 } 00105 00106 _got_start_time = false; 00107 } 00108 } else { 00109 // In case _loop_count gets set to forever (zero): 00110 audio_debug(" paused "<<_file_name ); 00111 _paused = true; 00112 } 00113 } 00114 00115 //////////////////////////////////////////////////////////////////// 00116 // Function: MilesAudioSequence::stop 00117 // Access: Public, Virtual 00118 // Description: 00119 //////////////////////////////////////////////////////////////////// 00120 void MilesAudioSequence:: 00121 stop() { 00122 miles_audio_debug("stop()"); 00123 _manager->stopping_sound(this); 00124 // The _paused flag should not be cleared here. _paused is not like 00125 // the Pause button on a cd/dvd player. It is used as a flag to say 00126 // that it was looping when it was set inactive. There is no need to 00127 // make this symmetrical with play(). set_active() is the 'owner' of 00128 // _paused. play() accesses _paused to help in the situation where 00129 // someone calls play on an inactive sound(). 00130 00131 if (_sequence != 0) { 00132 AIL_end_sequence(_sequence); 00133 00134 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr(); 00135 mgr->release_sequence(_sequence_index, this); 00136 00137 _sequence = 0; 00138 _sequence_index = 0; 00139 } 00140 } 00141 00142 //////////////////////////////////////////////////////////////////// 00143 // Function: MilesAudioSequence::get_time 00144 // Access: Public, Virtual 00145 // Description: 00146 //////////////////////////////////////////////////////////////////// 00147 PN_stdfloat MilesAudioSequence:: 00148 get_time() const { 00149 if (_sequence == 0) { 00150 if (_got_start_time) { 00151 return _start_time; 00152 } 00153 return 0.0f; 00154 } 00155 00156 S32 current_ms; 00157 AIL_sequence_ms_position(_sequence, NULL, ¤t_ms); 00158 PN_stdfloat time = PN_stdfloat(current_ms * 0.001f); 00159 00160 return time; 00161 } 00162 00163 //////////////////////////////////////////////////////////////////// 00164 // Function: MilesAudioSequence::set_volume 00165 // Access: Public, Virtual 00166 // Description: 00167 //////////////////////////////////////////////////////////////////// 00168 void MilesAudioSequence:: 00169 set_volume(PN_stdfloat volume) { 00170 miles_audio_debug("set_volume(volume="<<volume<<")"); 00171 00172 // Set the volume even if our volume is not changing, because the 00173 // MilesAudioManager will call set_volume() when *its* volume 00174 // changes. 00175 00176 // Set the volume: 00177 _volume = volume; 00178 00179 if (_sequence != 0) { 00180 volume *= _manager->get_volume(); 00181 00182 // Change to Miles volume, range 0 to 127: 00183 S32 milesVolume = (S32)(volume * 127.0f); 00184 milesVolume = min(milesVolume, 127); 00185 milesVolume = max(milesVolume, 0); 00186 00187 AIL_set_sequence_volume(_sequence, milesVolume, 0); 00188 } 00189 } 00190 00191 //////////////////////////////////////////////////////////////////// 00192 // Function: MilesAudioSequence::set_balance 00193 // Access: Public, Virtual 00194 // Description: 00195 //////////////////////////////////////////////////////////////////// 00196 void MilesAudioSequence:: 00197 set_balance(PN_stdfloat balance_right) { 00198 miles_audio_debug("set_balance(balance_right="<<balance_right<<")"); 00199 _balance = balance_right; 00200 00201 // Balance has no effect on a MIDI file. 00202 } 00203 00204 //////////////////////////////////////////////////////////////////// 00205 // Function: MilesAudioSequence::set_play_rate 00206 // Access: Public, Virtual 00207 // Description: 00208 //////////////////////////////////////////////////////////////////// 00209 void MilesAudioSequence:: 00210 set_play_rate(PN_stdfloat play_rate) { 00211 miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")"); 00212 00213 // Set the play_rate: 00214 _play_rate = play_rate; 00215 00216 if (_sequence != 0) { 00217 play_rate *= _manager->get_play_rate(); 00218 00219 S32 percent = (S32)(play_rate * 100.0f); 00220 AIL_set_sequence_tempo(_sequence, percent, 0); 00221 } 00222 } 00223 00224 //////////////////////////////////////////////////////////////////// 00225 // Function: MilesAudioSequence::length 00226 // Access: Public, Virtual 00227 // Description: 00228 //////////////////////////////////////////////////////////////////// 00229 PN_stdfloat MilesAudioSequence:: 00230 length() const { 00231 if (_sequence == 0) { 00232 // The MIDI file hasn't been started yet. See if the length is 00233 // cached in the SoundData. 00234 if (!_sd->_has_length) { 00235 // It isn't cached, so load the sequence temporarily to 00236 // determine its length. 00237 ((MilesAudioSequence *)this)->determine_length(); 00238 } 00239 00240 return _sd->get_length(); 00241 } 00242 00243 // The MIDI file has already been started, so we can ask it 00244 // directly. 00245 S32 length_ms; 00246 AIL_sequence_ms_position(_sequence, &length_ms, NULL); 00247 PN_stdfloat time = (PN_stdfloat)length_ms * 0.001f; 00248 return time; 00249 } 00250 00251 //////////////////////////////////////////////////////////////////// 00252 // Function: MilesAudioSequence::status 00253 // Access: Public, Virtual 00254 // Description: 00255 //////////////////////////////////////////////////////////////////// 00256 AudioSound::SoundStatus MilesAudioSequence:: 00257 status() const { 00258 if (_sequence == 0) { 00259 return AudioSound::READY; 00260 } 00261 switch (AIL_sequence_status(_sequence)) { 00262 case SEQ_DONE: 00263 case SEQ_STOPPED: 00264 case SEQ_FREE: 00265 return AudioSound::READY; 00266 00267 case SEQ_PLAYING: 00268 case SEQ_PLAYINGBUTRELEASED: 00269 return AudioSound::PLAYING; 00270 00271 default: 00272 return AudioSound::BAD; 00273 } 00274 } 00275 00276 //////////////////////////////////////////////////////////////////// 00277 // Function: MilesAudioSequence::cleanup 00278 // Access: Public, Virtual 00279 // Description: Stops the sound from playing and releases any 00280 // associated resources, in preparation for releasing 00281 // the sound or shutting down the sound system. 00282 //////////////////////////////////////////////////////////////////// 00283 void MilesAudioSequence:: 00284 cleanup() { 00285 stop(); 00286 } 00287 00288 //////////////////////////////////////////////////////////////////// 00289 // Function: MilesAudioSequence::internal_stop 00290 // Access: Private 00291 // Description: Called by the GlobalMilesManager when it is detected 00292 // that this particular sound has already stopped, and 00293 // its sequence handle will be recycled. 00294 //////////////////////////////////////////////////////////////////// 00295 void MilesAudioSequence:: 00296 internal_stop() { 00297 _sequence = 0; 00298 _sequence_index = 0; 00299 } 00300 00301 //////////////////////////////////////////////////////////////////// 00302 // Function: MilesAudioSequence::finish_callback 00303 // Access: Private, Static 00304 // Description: This callback is made by Miles (possibly in a 00305 // sub-thread) when the sequence finishes. 00306 //////////////////////////////////////////////////////////////////// 00307 void AILCALLBACK MilesAudioSequence:: 00308 finish_callback(HSEQUENCE sequence) { 00309 MilesAudioSequence *self = (MilesAudioSequence *)AIL_sequence_user_data(sequence, 0); 00310 if (milesAudio_cat.is_debug()) { 00311 milesAudio_cat.debug() 00312 << "finished " << *self << "\n"; 00313 } 00314 self->_manager->_sounds_finished = true; 00315 } 00316 00317 //////////////////////////////////////////////////////////////////// 00318 // Function: MilesAudioSequence::do_set_time 00319 // Access: Private 00320 // Description: Sets the start time of an already allocated stream. 00321 //////////////////////////////////////////////////////////////////// 00322 void MilesAudioSequence:: 00323 do_set_time(PN_stdfloat time) { 00324 miles_audio_debug("do_set_time(time="<<time<<")"); 00325 00326 nassertv(_sequence != 0); 00327 00328 S32 time_ms = (S32)(1000.0f * time); 00329 00330 // Ensure we don't inadvertently run off the end of the sound. 00331 S32 length_ms; 00332 AIL_sequence_ms_position(_sequence, &length_ms, NULL); 00333 time_ms = min(time_ms, length_ms); 00334 00335 AIL_set_sequence_ms_position(_sequence, time_ms); 00336 } 00337 00338 00339 //////////////////////////////////////////////////////////////////// 00340 // Function: MilesAudioSequence::determine_length 00341 // Access: Private 00342 // Description: Temporarily loads the sequence to determine its 00343 // length. Stores the result on the _sd. 00344 //////////////////////////////////////////////////////////////////// 00345 void MilesAudioSequence:: 00346 determine_length() { 00347 nassertv(_sequence == 0); 00348 00349 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr(); 00350 if (!mgr->get_sequence(_sequence, _sequence_index, this)){ 00351 milesAudio_cat.warning() 00352 << "Could not determine length of " << _file_name << ": too many open sequences\n"; 00353 _sequence = 0; 00354 } else { 00355 AIL_init_sequence(_sequence, &_sd->_raw_data[0], 0); 00356 S32 length_ms; 00357 AIL_sequence_ms_position(_sequence, &length_ms, NULL); 00358 PN_stdfloat time = (PN_stdfloat)length_ms * 0.001f; 00359 mgr->release_sequence(_sequence_index, this); 00360 _sequence = 0; 00361 _sequence_index = 0; 00362 00363 _sd->set_length(time); 00364 } 00365 } 00366 00367 #endif //]