Panda3D

milesAudioSequence.cxx

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, &current_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 //]
 All Classes Functions Variables Enumerations