Panda3D
|
00001 // Filename: milesAudioSample.cxx 00002 // Created by: skyler (June 6, 2001) 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 "milesAudioSample.h" 00016 00017 #ifdef HAVE_RAD_MSS //[ 00018 00019 #include "milesAudioManager.h" 00020 00021 00022 TypeHandle MilesAudioSample::_type_handle; 00023 00024 #undef miles_audio_debug 00025 00026 #ifndef NDEBUG //[ 00027 #define miles_audio_debug(x) \ 00028 audio_debug("MilesAudioSample \""<<get_name()<<"\" "<< x ) 00029 #else //][ 00030 #define miles_audio_debug(x) ((void)0) 00031 #endif //] 00032 00033 //////////////////////////////////////////////////////////////////// 00034 // Function: MilesAudioSample::Constructor 00035 // Access: Private 00036 // Description: This constructor is called only by the 00037 // MilesAudioManager. 00038 //////////////////////////////////////////////////////////////////// 00039 MilesAudioSample:: 00040 MilesAudioSample(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("MilesAudioSample(manager=0x"<<(void*)&manager 00047 <<", sd=0x"<<(void*)sd<<", file_name="<<file_name<<")"); 00048 00049 _sample = 0; 00050 _sample_index = 0; 00051 _original_playback_rate = 1.0f; 00052 } 00053 00054 //////////////////////////////////////////////////////////////////// 00055 // Function: MilesAudioSample::Destructor 00056 // Access: Public, Virtual 00057 // Description: 00058 //////////////////////////////////////////////////////////////////// 00059 MilesAudioSample:: 00060 ~MilesAudioSample() { 00061 miles_audio_debug("~MilesAudioSample()"); 00062 cleanup(); 00063 miles_audio_debug("~MilesAudioSample() done"); 00064 } 00065 00066 //////////////////////////////////////////////////////////////////// 00067 // Function: MilesAudioSample::play 00068 // Access: Public, Virtual 00069 // Description: 00070 //////////////////////////////////////////////////////////////////// 00071 void MilesAudioSample:: 00072 play() { 00073 miles_audio_debug("play()"); 00074 if (_active) { 00075 if (_sd->_raw_data.empty()) { 00076 milesAudio_cat.warning() 00077 << "Could not play " << _file_name << ": no data\n"; 00078 } else { 00079 stop(); 00080 _manager->starting_sound(this); 00081 00082 nassertv(_sample == 0); 00083 00084 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr(); 00085 if (!mgr->get_sample(_sample, _sample_index, this)){ 00086 milesAudio_cat.warning() 00087 << "Could not play " << _file_name << ": too many open samples\n"; 00088 _sample = 0; 00089 } else { 00090 AIL_set_named_sample_file(_sample, _sd->_basename.c_str(), 00091 &_sd->_raw_data[0], _sd->_raw_data.size(), 00092 0); 00093 _original_playback_rate = AIL_sample_playback_rate(_sample); 00094 AIL_set_sample_user_data(_sample, 0, (SINTa)this); 00095 AIL_register_EOS_callback(_sample, finish_callback); 00096 00097 set_volume(_volume); 00098 set_play_rate(_play_rate); 00099 AIL_set_sample_loop_count(_sample, _loop_count); 00100 00101 if (_got_start_time) { 00102 do_set_time(_start_time); 00103 AIL_resume_sample(_sample); 00104 } else { 00105 AIL_start_sample(_sample); 00106 } 00107 } 00108 00109 _got_start_time = false; 00110 } 00111 } else { 00112 // In case _loop_count gets set to forever (zero): 00113 audio_debug(" paused "<<_file_name ); 00114 _paused = true; 00115 } 00116 } 00117 00118 //////////////////////////////////////////////////////////////////// 00119 // Function: MilesAudioSample::stop 00120 // Access: Public, Virtual 00121 // Description: 00122 //////////////////////////////////////////////////////////////////// 00123 void MilesAudioSample:: 00124 stop() { 00125 if (_manager == (MilesAudioManager *)NULL) { 00126 return; 00127 } 00128 00129 miles_audio_debug("stop()"); 00130 _manager->stopping_sound(this); 00131 // The _paused flag should not be cleared here. _paused is not like 00132 // the Pause button on a cd/dvd player. It is used as a flag to say 00133 // that it was looping when it was set inactive. There is no need to 00134 // make this symmetrical with play(). set_active() is the 'owner' of 00135 // _paused. play() accesses _paused to help in the situation where 00136 // someone calls play on an inactive sound(). 00137 00138 // it fixes audio bug, I don't understand the reasoning of the above comment 00139 _paused = false; 00140 00141 if (_sample != 0) { 00142 AIL_end_sample(_sample); 00143 00144 GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr(); 00145 mgr->release_sample(_sample_index, this); 00146 00147 _sample = 0; 00148 _sample_index = 0; 00149 } 00150 } 00151 00152 //////////////////////////////////////////////////////////////////// 00153 // Function: MilesAudioSample::get_time 00154 // Access: Public, Virtual 00155 // Description: 00156 //////////////////////////////////////////////////////////////////// 00157 PN_stdfloat MilesAudioSample:: 00158 get_time() const { 00159 if (_sample == 0) { 00160 if (_got_start_time) { 00161 return _start_time; 00162 } 00163 return 0.0f; 00164 } 00165 00166 S32 current_ms; 00167 AIL_sample_ms_position(_sample, NULL, ¤t_ms); 00168 PN_stdfloat time = PN_stdfloat(current_ms * 0.001f); 00169 00170 return time; 00171 } 00172 00173 //////////////////////////////////////////////////////////////////// 00174 // Function: MilesAudioSample::set_volume 00175 // Access: Public, Virtual 00176 // Description: 00177 //////////////////////////////////////////////////////////////////// 00178 void MilesAudioSample:: 00179 set_volume(PN_stdfloat volume) { 00180 miles_audio_debug("set_volume(volume="<<volume<<")"); 00181 00182 // Set the volume even if our volume is not changing, because the 00183 // MilesAudioManager will call set_volume() when *its* volume 00184 // changes. 00185 00186 // Set the volume: 00187 _volume = volume; 00188 00189 if (_sample != 0) { 00190 volume *= _manager->get_volume(); 00191 00192 // Change to Miles volume, range 0 to 1.0: 00193 F32 milesVolume = volume; 00194 milesVolume = min(milesVolume, 1.0f); 00195 milesVolume = max(milesVolume, 0.0f); 00196 00197 // Convert balance of -1.0..1.0 to 0-1.0: 00198 F32 milesBalance = (F32)((_balance + 1.0f) * 0.5f); 00199 00200 AIL_set_sample_volume_pan(_sample, milesVolume, milesBalance); 00201 } 00202 } 00203 00204 //////////////////////////////////////////////////////////////////// 00205 // Function: MilesAudioSample::set_balance 00206 // Access: Public, Virtual 00207 // Description: 00208 //////////////////////////////////////////////////////////////////// 00209 void MilesAudioSample:: 00210 set_balance(PN_stdfloat balance_right) { 00211 miles_audio_debug("set_balance(balance_right="<<balance_right<<")"); 00212 _balance = balance_right; 00213 00214 // Call set_volume to effect the change: 00215 set_volume(_volume); 00216 } 00217 00218 //////////////////////////////////////////////////////////////////// 00219 // Function: MilesAudioSample::set_play_rate 00220 // Access: Public, Virtual 00221 // Description: 00222 //////////////////////////////////////////////////////////////////// 00223 void MilesAudioSample:: 00224 set_play_rate(PN_stdfloat play_rate) { 00225 miles_audio_debug("set_play_rate(play_rate="<<play_rate<<")"); 00226 00227 // Set the play_rate: 00228 _play_rate = play_rate; 00229 00230 if (_sample != 0) { 00231 play_rate *= _manager->get_play_rate(); 00232 00233 // wave and mp3 use sample rate (e.g. 44100) 00234 S32 speed = (S32)(play_rate * (PN_stdfloat)_original_playback_rate); 00235 AIL_set_sample_playback_rate(_sample, speed); 00236 audio_debug(" play_rate for this wav or mp3 is now " << speed); 00237 } 00238 } 00239 00240 //////////////////////////////////////////////////////////////////// 00241 // Function: MilesAudioSample::length 00242 // Access: Public, Virtual 00243 // Description: 00244 //////////////////////////////////////////////////////////////////// 00245 PN_stdfloat MilesAudioSample:: 00246 length() const { 00247 return _sd->get_length(); 00248 } 00249 00250 //////////////////////////////////////////////////////////////////// 00251 // Function: MilesAudioSample::status 00252 // Access: Public, Virtual 00253 // Description: 00254 //////////////////////////////////////////////////////////////////// 00255 AudioSound::SoundStatus MilesAudioSample:: 00256 status() const { 00257 if (_sample == 0) { 00258 return AudioSound::READY; 00259 } 00260 switch (AIL_sample_status(_sample)) { 00261 case SMP_DONE: 00262 case SMP_STOPPED: 00263 case SMP_FREE: 00264 return AudioSound::READY; 00265 00266 case SMP_PLAYING: 00267 case SMP_PLAYINGBUTRELEASED: 00268 return AudioSound::PLAYING; 00269 00270 default: 00271 return AudioSound::BAD; 00272 } 00273 } 00274 00275 //////////////////////////////////////////////////////////////////// 00276 // Function: MilesAudioSample::cleanup 00277 // Access: Public, Virtual 00278 // Description: Stops the sound from playing and releases any 00279 // associated resources, in preparation for releasing 00280 // the sound or shutting down the sound system. 00281 //////////////////////////////////////////////////////////////////// 00282 void MilesAudioSample:: 00283 cleanup() { 00284 stop(); 00285 set_active(false); 00286 nassertv(_sample == 0); 00287 00288 if (_manager != (MilesAudioManager *)NULL) { 00289 _manager->release_sound(this); 00290 _manager = NULL; 00291 } 00292 } 00293 00294 //////////////////////////////////////////////////////////////////// 00295 // Function: MilesAudioSample::output 00296 // Access: Published, Virtual 00297 // Description: 00298 //////////////////////////////////////////////////////////////////// 00299 void MilesAudioSample:: 00300 output(ostream &out) const { 00301 out << get_type() << " " << get_name() << " " << status(); 00302 if (!_sd.is_null()) { 00303 out << " " << (_sd->_raw_data.size() + 1023) / 1024 << "K"; 00304 } 00305 } 00306 00307 //////////////////////////////////////////////////////////////////// 00308 // Function: MilesAudioSample::set_3d_attributes 00309 // Access: public 00310 // Description: Set position and velocity of this sound. Note that 00311 // Y and Z are switched to translate from Miles's 00312 // coordinate system. 00313 //////////////////////////////////////////////////////////////////// 00314 void MilesAudioSample::set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) { 00315 audio_debug("MilesAudioSample::set_3d_attributes() Setting a sound's 3D Coordinates."); 00316 00317 if(_sample != 0) { 00318 AIL_set_sample_3D_position(_sample, px, pz, py); 00319 AIL_set_sample_3D_velocity_vector(_sample, vx, vz, vy); 00320 } else { 00321 audio_warning("_sample == 0 in MilesAudioSample::set_3d_attributes()."); 00322 } 00323 } 00324 00325 //////////////////////////////////////////////////////////////////// 00326 // Function: MilesAudioSample::get_3d_attributes 00327 // Access: public 00328 // Description: Get position and velocity of this sound. 00329 //////////////////////////////////////////////////////////////////// 00330 void MilesAudioSample::get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) { 00331 audio_debug("MilesAudioSample::get_3d_attributes()."); 00332 00333 if(_sample != 0) { 00334 float lpx, lpy, lpz, lvx, lvy, lvz; 00335 AIL_sample_3D_position(_sample, &lpx, &lpz, &lpy); 00336 AIL_sample_3D_velocity(_sample, &lvx, &lvz, &lvy); 00337 *px = lpx; 00338 *py = lpy; 00339 *pz = lpz; 00340 *vx = lvx; 00341 *vy = lvy; 00342 *vz = lvz; 00343 } else { 00344 audio_warning("_sample == 0 in MilesAudioSample::get_3d_attributes()."); 00345 } 00346 } 00347 00348 //////////////////////////////////////////////////////////////////// 00349 // Function: MilesAudioSample::set_3d_min_distance 00350 // Access: public 00351 // Description: Set the distance that this sound begins to fall 00352 // off. With Miles's default falloff behavior, when 00353 // the distance between the sound and the listener is 00354 // doubled, the volume is halved, and vice versa. 00355 //////////////////////////////////////////////////////////////////// 00356 void MilesAudioSample::set_3d_min_distance(PN_stdfloat dist) { 00357 audio_debug("MilesAudioSample::set_3d_min_distance() Setting the sound's 3D min distance ( min= " << dist << " ) "); 00358 00359 if(_sample != 0) { 00360 // Implementation is awkward, since Miles gets and sets min and max distances 00361 // in a single operation. 00362 float max_dist; 00363 int auto_3D_wet_atten; 00364 AIL_sample_3D_distances(_sample, &max_dist, NULL, &auto_3D_wet_atten); 00365 00366 AIL_set_sample_3D_distances(_sample, max_dist, dist, auto_3D_wet_atten); 00367 } else { 00368 audio_warning("_sample == 0 in MilesAudioSample::set_3d_min_distance()."); 00369 } 00370 } 00371 00372 //////////////////////////////////////////////////////////////////// 00373 // Function: MilesAudioSample::get_3d_min_distance 00374 // Access: public 00375 // Description: Get the distance that this sound begins to fall off. 00376 //////////////////////////////////////////////////////////////////// 00377 PN_stdfloat MilesAudioSample::get_3d_min_distance() const { 00378 audio_debug("MilesAudioSample::get_3d_min_distance() "); 00379 00380 if(_sample != 0) { 00381 float min_dist; 00382 AIL_sample_3D_distances(_sample, NULL, &min_dist, NULL); 00383 return (PN_stdfloat)min_dist; 00384 } else { 00385 audio_warning("_sample == 0 in MilesAudioSample::get_3d_min_distance()."); 00386 return -1.0; 00387 } 00388 } 00389 00390 //////////////////////////////////////////////////////////////////// 00391 // Function: MilesAudioSample::set_3d_max_distance 00392 // Access: public 00393 // Description: Set the distance at which this sound is clipped to 00394 // silence. Note that this value does not affect 00395 // the rate at which the sound falls off, but only 00396 // the distance at which it gets clipped. 00397 //////////////////////////////////////////////////////////////////// 00398 void MilesAudioSample::set_3d_max_distance(PN_stdfloat dist) { 00399 audio_debug("MilesAudioSample::set_3d_max_distance() Setting the sound's 3D max distance ( max= " << dist << " ) "); 00400 00401 if(_sample != 0) { 00402 // Implementation is awkward, since Miles gets and sets min and max distances 00403 // in a single operation. 00404 float min_dist; 00405 int auto_3D_wet_atten; 00406 AIL_sample_3D_distances(_sample, NULL, &min_dist, &auto_3D_wet_atten); 00407 00408 AIL_set_sample_3D_distances(_sample, dist, min_dist, auto_3D_wet_atten); 00409 } else { 00410 audio_warning("_sample == 0 in MilesAudioSample::set_3d_max_distance()."); 00411 } 00412 } 00413 00414 //////////////////////////////////////////////////////////////////// 00415 // Function: MilesAudioSample::get_3d_max_distance 00416 // Access: public 00417 // Description: Get the distance at which this sound is clipped to 00418 // silence. 00419 //////////////////////////////////////////////////////////////////// 00420 PN_stdfloat MilesAudioSample::get_3d_max_distance() const { 00421 audio_debug("MilesAudioSample::get_3d_max_distance() "); 00422 00423 if(_sample != 0) { 00424 float max_dist; 00425 AIL_sample_3D_distances(_sample, &max_dist, NULL, NULL); 00426 return (PN_stdfloat)max_dist; 00427 } else { 00428 audio_warning("_sample == 0 in MilesAudioSample::get_3d_max_distance()."); 00429 return -1.0; 00430 } 00431 } 00432 00433 //////////////////////////////////////////////////////////////////// 00434 // Function: MilesAudioSample::get_speaker_level 00435 // Access: Published 00436 // Description: Get the level of a particular logical channel (speaker). 00437 // "index" specifies which speaker in an array of all the 00438 // logical channels currently in use to retrieve the level 00439 // of. 00440 // 00441 // For instance, in a standard 4.0 channel setup, speakers 00442 // are setup as [frontLeft, frontRight, backLeft, backRight]. 00443 // Thus, get_speaker_level(2) will retrieve the level of the 00444 // backLeft speaker. 00445 // 00446 // The order in which speakers appear in the array for 00447 // standard speaker setups is defined to be: 00448 // 00449 // FRONT_LEFT 00450 // FRONT_RIGHT 00451 // FRONT_CENTER 00452 // LOW_FREQUENCY (sub woofer) 00453 // BACK_LEFT 00454 // BACK_RIGHT 00455 // FRONT_LEFT_OF_CENTER 00456 // FRONT_RIGHT_OF_CENTER 00457 // BACK_CENTER 00458 // SIDE_LEFT 00459 // SIDE_RIGHT 00460 // TOP_CENTER 00461 // TOP_FRONT_LEFT 00462 // TOP_FRONT_CENTER 00463 // TOP_FRONT_RIGHT 00464 // TOP_BACK_LEFT 00465 // TOP_BACK_CENTER 00466 // TOP_BACK_RIGHT 00467 // 00468 //////////////////////////////////////////////////////////////////// 00469 PN_stdfloat MilesAudioSample:: 00470 get_speaker_level(int index) { 00471 audio_debug("MilesAudioSample::get_speaker_level(" << index << ")"); 00472 00473 if(_sample != 0) { 00474 int numLevels; 00475 float *levels = AIL_sample_channel_levels(_sample, &numLevels); 00476 00477 if(index < numLevels) { 00478 return (PN_stdfloat)levels[index]; 00479 } else { 00480 audio_error("index out of range in MilesAudioSample::get_speaker_level. numLevels: " << numLevels); 00481 return -1.0; 00482 } 00483 } else { 00484 audio_warning("Warning: MilesAudioSample::get_speaker_level only works for sounds that are currently playing"); 00485 return -1.0; 00486 } 00487 } 00488 00489 //////////////////////////////////////////////////////////////////// 00490 // Function: MilesAudioSample::set_speaker_levels 00491 // Access: Published 00492 // Description: Set the output levels on the logical channels (speakers) 00493 // for this sound. Values should be in the range 0.0 to 1.0. 00494 // Levels for up to nine channels may be specified. As soon 00495 // as a level is reached that falls outside the range 0.0 to 00496 // 1.0, the levels specified up to that point will be sent 00497 // and all other levels will be ignored. 00498 // 00499 // The user must know what the current speaker setup is in order 00500 // to know which level corresponds to which speaker. 00501 // 00502 // This method will have no effect if 3D attributes have been 00503 // set for this sound. 00504 // 00505 // The order in which speakers appear in the array for 00506 // standard speaker setups is defined to be: 00507 // 00508 // FRONT_LEFT 00509 // FRONT_RIGHT 00510 // FRONT_CENTER 00511 // LOW_FREQUENCY (sub woofer) 00512 // BACK_LEFT 00513 // BACK_RIGHT 00514 // FRONT_LEFT_OF_CENTER 00515 // FRONT_RIGHT_OF_CENTER 00516 // BACK_CENTER 00517 // SIDE_LEFT 00518 // SIDE_RIGHT 00519 // TOP_CENTER 00520 // TOP_FRONT_LEFT 00521 // TOP_FRONT_CENTER 00522 // TOP_FRONT_RIGHT 00523 // TOP_BACK_LEFT 00524 // TOP_BACK_CENTER 00525 // TOP_BACK_RIGHT 00526 // 00527 //////////////////////////////////////////////////////////////////// 00528 void MilesAudioSample:: 00529 set_speaker_levels(PN_stdfloat level1, PN_stdfloat level2, PN_stdfloat level3, PN_stdfloat level4, PN_stdfloat level5, PN_stdfloat level6, PN_stdfloat level7, PN_stdfloat level8, PN_stdfloat level9) { 00530 audio_debug("MilesAudioSample::set_speaker_levels()"); 00531 00532 if(_sample != 0) { 00533 float levels[9] = {level1, level2, level3, level4, level5, level6, level7, level8, level9}; 00534 00535 if((level1 < 0.0) || (level1 > 1.0)) { 00536 audio_error("No valid levels specified in MilesAudioSample::set_speaker_levels()."); 00537 } else if((level2 < 0.0) || (level2 > 1.0)) { 00538 AIL_set_sample_channel_levels(_sample, levels, 1); 00539 } else if((level3 < 0.0) || (level3 > 1.0)) { 00540 AIL_set_sample_channel_levels(_sample, levels, 2); 00541 } else if((level4 < 0.0) || (level4 > 1.0)) { 00542 AIL_set_sample_channel_levels(_sample, levels, 3); 00543 } else if((level5 < 0.0) || (level5 > 1.0)) { 00544 AIL_set_sample_channel_levels(_sample, levels, 4); 00545 } else if((level6 < 0.0) || (level6 > 1.0)) { 00546 AIL_set_sample_channel_levels(_sample, levels, 5); 00547 } else if((level7 < 0.0) || (level7 > 1.0)) { 00548 AIL_set_sample_channel_levels(_sample, levels, 6); 00549 } else if((level8 < 0.0) || (level8 > 1.0)) { 00550 AIL_set_sample_channel_levels(_sample, levels, 7); 00551 } else if((level9 < 0.0) || (level9 > 1.0)) { 00552 AIL_set_sample_channel_levels(_sample, levels, 8); 00553 } else { 00554 AIL_set_sample_channel_levels(_sample, levels, 9); 00555 } 00556 } else { 00557 audio_warning("Warning: MilesAudioSample::set_speaker_levels only works for sounds that are currently playing"); 00558 } 00559 } 00560 00561 //////////////////////////////////////////////////////////////////// 00562 // Function: MilesAudioSample::internal_stop 00563 // Access: Private 00564 // Description: Called by the GlobalMilesManager when it is detected 00565 // that this particular sound has already stopped, and 00566 // its sample handle will be recycled. 00567 //////////////////////////////////////////////////////////////////// 00568 void MilesAudioSample:: 00569 internal_stop() { 00570 _sample = 0; 00571 _sample_index = 0; 00572 } 00573 00574 //////////////////////////////////////////////////////////////////// 00575 // Function: MilesAudioSample::finish_callback 00576 // Access: Private, Static 00577 // Description: This callback is made by Miles (possibly in a 00578 // sub-thread) when the sample finishes. 00579 //////////////////////////////////////////////////////////////////// 00580 void AILCALLBACK MilesAudioSample:: 00581 finish_callback(HSAMPLE sample) { 00582 MilesAudioSample *self = (MilesAudioSample *)AIL_sample_user_data(sample, 0); 00583 if (milesAudio_cat.is_debug()) { 00584 milesAudio_cat.debug() 00585 << "finished " << *self << "\n"; 00586 } 00587 if (self->_manager == (MilesAudioManager *)NULL) { 00588 return; 00589 } 00590 self->_manager->_sounds_finished = true; 00591 } 00592 00593 //////////////////////////////////////////////////////////////////// 00594 // Function: MilesAudioSample::do_set_time 00595 // Access: Private 00596 // Description: Sets the start time of an already allocated sample. 00597 //////////////////////////////////////////////////////////////////// 00598 void MilesAudioSample:: 00599 do_set_time(PN_stdfloat time) { 00600 miles_audio_debug("do_set_time(time="<<time<<")"); 00601 nassertv(_sample != 0); 00602 00603 // Ensure we don't inadvertently run off the end of the sound. 00604 PN_stdfloat max_time = length(); 00605 if (time > max_time) { 00606 milesAudio_cat.warning() 00607 << "set_time(" << time << ") requested for sound of length " 00608 << max_time << "\n"; 00609 time = max_time; 00610 } 00611 00612 S32 time_ms = (S32)(1000.0f * time); 00613 AIL_set_sample_ms_position(_sample, time_ms); 00614 } 00615 00616 #endif //]