Panda3D

milesAudioStream.cxx

00001 // Filename: milesAudioStream.cxx
00002 // Created by:  drose (26Jul07)
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 "milesAudioStream.h"
00016 #ifdef HAVE_RAD_MSS //[
00017 
00018 #include "milesAudioManager.h"
00019 #include "pnotify.h"
00020 
00021 TypeHandle MilesAudioStream::_type_handle;
00022 
00023 #undef miles_audio_debug
00024 
00025 #ifndef NDEBUG //[
00026 #define miles_audio_debug(x) \
00027     audio_debug("MilesAudioStream \""<<get_name()<<"\" "<< x )
00028 #else //][
00029 #define miles_audio_debug(x) ((void)0)
00030 #endif //]
00031 
00032 ////////////////////////////////////////////////////////////////////
00033 //     Function: MilesAudioStream::Constructor
00034 //       Access: Private
00035 //  Description: 
00036 ////////////////////////////////////////////////////////////////////
00037 MilesAudioStream::
00038 MilesAudioStream(MilesAudioManager *manager, const string &file_name,
00039                  const Filename &path) :
00040   MilesAudioSound(manager, file_name),
00041   _path(path)
00042 {
00043   _stream = 0;
00044   _got_length = false;
00045 }
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: MilesAudioStream::Destructor
00049 //       Access: Public, Virtual
00050 //  Description: 
00051 ////////////////////////////////////////////////////////////////////
00052 MilesAudioStream::
00053 ~MilesAudioStream() {
00054   miles_audio_debug("~MilesAudioStream()");
00055   cleanup();
00056 
00057   miles_audio_debug("~MilesAudioStream() done");
00058 }
00059 
00060 ////////////////////////////////////////////////////////////////////
00061 //     Function: MilesAudioStream::play
00062 //       Access: Public, Virtual
00063 //  Description: 
00064 ////////////////////////////////////////////////////////////////////
00065 void MilesAudioStream::
00066 play() {
00067   miles_audio_debug("play()");
00068   if (_active) {
00069 
00070     _manager->starting_sound(this);
00071 
00072     if (_stream == 0) {
00073       GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00074       _stream = AIL_open_stream(mgr->_digital_driver, _path.c_str(), 0);
00075       if (_stream == 0) {
00076         milesAudio_cat.warning()
00077           << "Could not play " << _file_name << ": too many open streams\n";
00078         return;
00079       }
00080       AIL_set_stream_user_data(_stream, 0, (SINTa)this);
00081       AIL_register_stream_callback(_stream, finish_callback);
00082 
00083     } else {
00084       // We already had the stream open.  Keep it open; just restart
00085       // it.
00086       AIL_pause_stream(_stream, 1);
00087       _manager->stop_service_stream(_stream);
00088     }
00089 
00090     // Start playing:
00091     nassertv(_stream != 0);
00092     HSAMPLE sample = AIL_stream_sample_handle(_stream);
00093     nassertv(sample != 0);
00094     
00095     _original_playback_rate = AIL_sample_playback_rate(sample);
00096     set_volume(_volume);
00097     set_play_rate(_play_rate);
00098     
00099     AIL_set_stream_loop_count(_stream, _loop_count);
00100 
00101     AIL_start_stream(_stream);
00102     if (_got_start_time) {
00103       // There's no AIL_resume_stream(), so we start in the middle by
00104       // starting normally, then immediately skipping to the middle.
00105       do_set_time(_start_time);
00106     }
00107     
00108     if (miles_audio_panda_threads) {
00109       AIL_auto_service_stream(_stream, 0);
00110       _manager->start_service_stream(_stream);
00111     } else {
00112       AIL_auto_service_stream(_stream, 1);
00113     }
00114 
00115     _got_start_time = false;
00116 
00117   } else {
00118     // In case _loop_count gets set to forever (zero):
00119     audio_debug("  paused "<<_file_name );
00120     _paused = true;
00121   }
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: MilesAudioStream::stop
00126 //       Access: Public, Virtual
00127 //  Description: 
00128 ////////////////////////////////////////////////////////////////////
00129 void MilesAudioStream::
00130 stop() {
00131   if (_manager == (MilesAudioManager *)NULL) {
00132     return;
00133   }
00134   miles_audio_debug("stop()");
00135   _manager->stopping_sound(this);
00136 
00137   // The _paused flag should not be cleared here.  _paused is not like
00138   // the Pause button on a cd/dvd player.  It is used as a flag to say
00139   // that it was looping when it was set inactive.  There is no need to
00140   // make this symmetrical with play().  set_active() is the 'owner' of
00141   // _paused.  play() accesses _paused to help in the situation where
00142   // someone calls play on an inactive sound().
00143   if (_stream != 0) {
00144     _manager->stop_service_stream(_stream);
00145 
00146     AIL_pause_stream(_stream, 1);
00147     AIL_close_stream(_stream);
00148     _stream = 0;
00149   }
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: MilesAudioStream::
00154 //       Access: Public, Virtual
00155 //  Description: 
00156 ////////////////////////////////////////////////////////////////////
00157 PN_stdfloat MilesAudioStream::
00158 get_time() const {
00159   if (_stream == 0) {
00160     if (_got_start_time) {
00161       return _start_time;
00162     }
00163     return 0.0f;
00164   }
00165 
00166   S32 current_ms;
00167   AIL_stream_ms_position(_stream, NULL, &current_ms);
00168   PN_stdfloat time = PN_stdfloat(current_ms * 0.001f);
00169 
00170   return time;
00171 }
00172 
00173 ////////////////////////////////////////////////////////////////////
00174 //     Function: MilesAudioStream::
00175 //       Access: Public, Virtual
00176 //  Description: 
00177 ////////////////////////////////////////////////////////////////////
00178 void MilesAudioStream::
00179 set_volume(PN_stdfloat volume) {
00180   _volume = volume;
00181 
00182   if (_stream != 0) {
00183     HSAMPLE sample = AIL_stream_sample_handle(_stream);
00184     nassertv(sample != 0);
00185 
00186     volume *= _manager->get_volume();
00187     
00188     // Change to Miles volume, range 0 to 1.0:
00189     F32 milesVolume = volume;
00190     milesVolume = min(milesVolume, 1.0f);
00191     milesVolume = max(milesVolume, 0.0f);
00192     
00193     // Convert balance of -1.0..1.0 to 0-1.0:
00194     F32 milesBalance = (F32)((_balance + 1.0f) * 0.5f);
00195     
00196     AIL_set_sample_volume_pan(sample, milesVolume, milesBalance);
00197   }
00198 }
00199 
00200 ////////////////////////////////////////////////////////////////////
00201 //     Function: MilesAudioStream::set_balance
00202 //       Access: Public, Virtual
00203 //  Description: 
00204 ////////////////////////////////////////////////////////////////////
00205 void MilesAudioStream::
00206 set_balance(PN_stdfloat balance_right) {
00207   _balance = balance_right;
00208 
00209   // Call set_volume to effect the change:
00210   set_volume(_volume);
00211 }
00212 
00213 ////////////////////////////////////////////////////////////////////
00214 //     Function: MilesAudioStream::set_play_rate
00215 //       Access: Public, Virtual
00216 //  Description: 
00217 ////////////////////////////////////////////////////////////////////
00218 void MilesAudioStream::
00219 set_play_rate(PN_stdfloat play_rate) {
00220   _play_rate = play_rate;
00221 
00222   if (_stream != 0) {
00223     HSAMPLE sample = AIL_stream_sample_handle(_stream);
00224     nassertv(sample != 0);
00225 
00226     play_rate *= _manager->get_play_rate();
00227 
00228     // wave and mp3 use sample rate (e.g. 44100)
00229     S32 speed = (S32)(play_rate * (PN_stdfloat)_original_playback_rate);
00230     AIL_set_sample_playback_rate(sample, speed);
00231     audio_debug("  play_rate for this wav or mp3 is now " << speed);
00232   }
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 //     Function: MilesAudioStream::length
00237 //       Access: Public, Virtual
00238 //  Description: 
00239 ////////////////////////////////////////////////////////////////////
00240 PN_stdfloat MilesAudioStream::
00241 length() const {
00242   if (!_got_length) {
00243     if (_stream == 0) {
00244       GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
00245       ((MilesAudioStream *)this)->_stream = AIL_open_stream(mgr->_digital_driver, _path.c_str(), 0);
00246     }
00247     
00248     S32 length_ms;
00249     AIL_stream_ms_position(_stream, &length_ms, NULL);
00250     _length = (PN_stdfloat)length_ms * 0.001f;
00251     _got_length = true;
00252   }
00253     
00254   return _length;
00255 }
00256 
00257 ////////////////////////////////////////////////////////////////////
00258 //     Function: MilesAudioStream::status
00259 //       Access: Public, Virtual
00260 //  Description: 
00261 ////////////////////////////////////////////////////////////////////
00262 AudioSound::SoundStatus MilesAudioStream::
00263 status() const {
00264   if (!_stream) {
00265     return AudioSound::READY;
00266   }
00267 
00268   switch (AIL_stream_status(_stream)) {
00269   case SMP_STOPPED:
00270   case SMP_DONE:
00271     return AudioSound::READY;
00272   case SMP_PLAYING:
00273   case SMP_PLAYINGBUTRELEASED:
00274     return AudioSound::PLAYING;
00275   default:
00276     return AudioSound::BAD;
00277   }
00278 }
00279 
00280 ////////////////////////////////////////////////////////////////////
00281 //     Function: MilesAudioStream::cleanup
00282 //       Access: Public, Virtual
00283 //  Description: Called to release any resources associated with the
00284 //               sound.
00285 ////////////////////////////////////////////////////////////////////
00286 void MilesAudioStream::
00287 cleanup() {
00288   if (_stream) {
00289     stop();
00290   }
00291   set_active(false);
00292   nassertv(_stream == 0);
00293 
00294   if (_manager != (MilesAudioManager *)NULL) {
00295     _manager->release_sound(this);
00296     _manager = NULL;
00297   }
00298 }
00299 
00300 ////////////////////////////////////////////////////////////////////
00301 //     Function: MilesAudioStream::finish_callback
00302 //       Access: Private, Static
00303 //  Description: This callback is made by Miles (possibly in a
00304 //               sub-thread) when the stream finishes.
00305 ////////////////////////////////////////////////////////////////////
00306 void AILCALLBACK MilesAudioStream::
00307 finish_callback(HSTREAM stream) {
00308   MilesAudioStream *self = (MilesAudioStream *)AIL_stream_user_data(stream, 0);
00309   if (milesAudio_cat.is_debug()) {
00310     milesAudio_cat.debug()
00311       << "finished " << *self << "\n";
00312   }
00313   if (self->_manager == (MilesAudioManager *)NULL) {
00314     return;
00315   }
00316   self->_manager->_sounds_finished = true;
00317 }
00318 
00319 ////////////////////////////////////////////////////////////////////
00320 //     Function: MilesAudioStream::do_set_time
00321 //       Access: Private
00322 //  Description: Sets the start time of an already allocated stream.
00323 ////////////////////////////////////////////////////////////////////
00324 void MilesAudioStream::
00325 do_set_time(PN_stdfloat time) {
00326   nassertv(_stream != 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_stream_ms_position(_stream, &length_ms, NULL);
00333   time_ms = min(time_ms, length_ms);
00334   
00335   AIL_set_stream_ms_position(_stream, time_ms);
00336 }
00337 
00338 
00339 #endif //]
 All Classes Functions Variables Enumerations