Panda3D
|
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, ¤t_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 //]