Panda3D
|
00001 // Filename: fmodAudioSound.cxx 00002 // Created by: cort (January 22, 2003) 00003 // Extended by: ben (October 22, 2003) 00004 // Prior system by: cary 00005 // Rewrite [for new Version of FMOD-EX] by: Stan Rosenbaum "Staque" - Spring 2006 00006 // 00007 // 00008 //////////////////////////////////////////////////////////////////// 00009 // 00010 // PANDA 3D SOFTWARE 00011 // Copyright (c) Carnegie Mellon University. All rights reserved. 00012 // 00013 // All use of this software is subject to the terms of the revised BSD 00014 // license. You should have received a copy of this license along 00015 // with this source code in a file named "LICENSE." 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "pandabase.h" 00020 #include "dcast.h" 00021 00022 #ifdef HAVE_FMODEX //[ 00023 00024 //Panda Headers 00025 #include "config_audio.h" 00026 #include "fmodAudioSound.h" 00027 #include "string_utils.h" 00028 #include "subfileInfo.h" 00029 #include "reMutexHolder.h" 00030 00031 TypeHandle FmodAudioSound::_type_handle; 00032 00033 //////////////////////////////////////////////////////////////////// 00034 // Function: FmodAudioSound::FmodAudioSound 00035 // Access: public 00036 // Description: Constructor 00037 // All sound will DEFAULT load as a 2D sound unless 00038 // otherwise specified. 00039 //////////////////////////////////////////////////////////////////// 00040 00041 FmodAudioSound:: 00042 FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) { 00043 ReMutexHolder holder(FmodAudioManager::_lock); 00044 audio_debug("FmodAudioSound::FmodAudioSound() Creating new sound, filename: " << file_name ); 00045 00046 _active = manager->get_active(); 00047 _paused = false; 00048 _start_time = 0.0; 00049 00050 //Local Variables that are needed. 00051 FMOD_RESULT result; 00052 00053 //Inits 3D Attributes 00054 _location.x = 0; 00055 _location.y = 0; 00056 _location.z = 0; 00057 00058 _velocity.x = 0; 00059 _velocity.y = 0; 00060 _velocity.z = 0; 00061 00062 //Play Rate Variable 00063 _playrate = 1; 00064 00065 // These set the Speaker Levels to a default if you are using a MultiChannel Setup. 00066 for (int i=0; i<AudioManager::SPK_COUNT; i++) { 00067 _mix[i] = 1.0; 00068 } 00069 00070 //Assign the values we need 00071 FmodAudioManager *fmanager; 00072 DCAST_INTO_V(fmanager, manager); 00073 _manager = fmanager; 00074 00075 _channel = 0; 00076 _file_name = file_name; 00077 _file_name.set_binary(); 00078 00079 //Get the Speaker Mode [Important for later on.] 00080 result = _manager->_system->getSpeakerMode( &_speakermode ); 00081 fmod_audio_errcheck("_system->getSpeakerMode()", result); 00082 00083 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00084 PT(VirtualFile) file = vfs->get_file(_file_name); 00085 if (file == (VirtualFile *)NULL) { 00086 // File not found. We will display the appropriate error message 00087 // below. 00088 result = FMOD_ERR_FILE_NOTFOUND; 00089 00090 } else { 00091 bool preload = (fmod_audio_preload_threshold < 0) || (file->get_file_size() < fmod_audio_preload_threshold); 00092 int flags = FMOD_SOFTWARE; 00093 flags |= positional ? FMOD_3D : FMOD_2D; 00094 00095 FMOD_CREATESOUNDEXINFO sound_info; 00096 memset(&sound_info, 0, sizeof(sound_info)); 00097 sound_info.cbsize = sizeof(sound_info); 00098 00099 string ext = downcase(_file_name.get_extension()); 00100 if (ext == "mid") { 00101 // Get the MIDI parameters. 00102 memcpy(&sound_info, &_manager->_midi_info, sizeof(sound_info)); 00103 if (sound_info.dlsname != NULL) { 00104 audio_debug("Using DLS file " << sound_info.dlsname); 00105 } 00106 } 00107 00108 const char *name_or_data = _file_name.c_str(); 00109 string os_filename; 00110 00111 pvector<unsigned char> mem_buffer; 00112 SubfileInfo info; 00113 if (preload) { 00114 // Pre-read the file right now, and pass it in as a memory 00115 // buffer. This avoids threading issues completely, because all 00116 // of the reading happens right here. 00117 file->read_file(mem_buffer, true); 00118 sound_info.length = mem_buffer.size(); 00119 if (mem_buffer.size() != 0) { 00120 name_or_data = (const char *)&mem_buffer[0]; 00121 } 00122 flags |= FMOD_OPENMEMORY; 00123 if (fmodAudio_cat.is_debug()) { 00124 fmodAudio_cat.debug() 00125 << "Reading " << _file_name << " into memory (" << sound_info.length 00126 << " bytes)\n"; 00127 } 00128 00129 } else if (file->get_system_info(info)) { 00130 // The file exists on disk (or it's part of a multifile that 00131 // exists on disk), so we can have FMod read the file directly. 00132 // This is also safe, because FMod uses its own I/O operations 00133 // that don't involve Panda, so this can safely happen in an 00134 // FMod thread. 00135 os_filename = info.get_filename().to_os_specific(); 00136 name_or_data = os_filename.c_str(); 00137 sound_info.fileoffset = (unsigned int)info.get_start(); 00138 sound_info.length = (unsigned int)info.get_size(); 00139 flags |= FMOD_CREATESTREAM; 00140 if (fmodAudio_cat.is_debug()) { 00141 fmodAudio_cat.debug() 00142 << "Streaming " << _file_name << " from disk (" << name_or_data 00143 << ", " << sound_info.fileoffset << ", " << sound_info.length << ")\n"; 00144 } 00145 00146 } else { 00147 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 00148 // Otherwise, if the Panda threading system is compiled in, we 00149 // can assign callbacks to read the file through the VFS. 00150 name_or_data = (const char *)file.p(); 00151 sound_info.length = (unsigned int)info.get_size(); 00152 sound_info.useropen = open_callback; 00153 sound_info.userclose = close_callback; 00154 sound_info.userread = read_callback; 00155 sound_info.userseek = seek_callback; 00156 flags |= FMOD_CREATESTREAM; 00157 if (fmodAudio_cat.is_debug()) { 00158 fmodAudio_cat.debug() 00159 << "Streaming " << _file_name << " from disk using callbacks\n"; 00160 } 00161 00162 #else // HAVE_THREADS && !SIMPLE_THREADS 00163 // Without threads, we can't safely read this file. 00164 name_or_data = ""; 00165 00166 fmodAudio_cat.warning() 00167 << "Cannot stream " << _file_name << "; file is not literally on disk.\n"; 00168 #endif 00169 } 00170 00171 result = 00172 _manager->_system->createSound(name_or_data, flags, &sound_info, &_sound); 00173 } 00174 00175 if (result != FMOD_OK) { 00176 audio_error("createSound(" << _file_name << "): " << FMOD_ErrorString(result)); 00177 00178 // We couldn't load the sound file. Create a blank sound record 00179 // instead. 00180 FMOD_CREATESOUNDEXINFO sound_info; 00181 memset(&sound_info, 0, sizeof(sound_info)); 00182 char blank_data[100]; 00183 memset(blank_data, 0, sizeof(blank_data)); 00184 sound_info.cbsize = sizeof(sound_info); 00185 sound_info.length = sizeof(blank_data); 00186 sound_info.numchannels = 1; 00187 sound_info.defaultfrequency = 8000; 00188 sound_info.format = FMOD_SOUND_FORMAT_PCM16; 00189 int flags = FMOD_SOFTWARE | FMOD_OPENMEMORY | FMOD_OPENRAW; 00190 00191 result = _manager->_system->createSound( blank_data, flags, &sound_info, &_sound); 00192 fmod_audio_errcheck("createSound (blank)", result); 00193 } 00194 00195 // Some WAV files contain a loop bit. This is not handled 00196 // consistently. Override it. 00197 _sound->setLoopCount(1); 00198 _sound->setMode(FMOD_LOOP_OFF); 00199 00200 //This is just to collect the defaults of the sound, so we don't 00201 //Have to query FMOD everytime for the info. 00202 //It is also important we get the '_sampleFrequency' variable here, for the 00203 //'set_play_rate()' and 'get_play_rate()' methods later; 00204 00205 result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority); 00206 fmod_audio_errcheck("_sound->getDefaults()", result); 00207 } 00208 00209 00210 //////////////////////////////////////////////////////////////////// 00211 // Function: FmodAudioSound::~FmodAudioSound 00212 // Access: public 00213 // Description: DESTRUCTOR!!! 00214 //////////////////////////////////////////////////////////////////// 00215 FmodAudioSound:: 00216 ~FmodAudioSound() { 00217 ReMutexHolder holder(FmodAudioManager::_lock); 00218 FMOD_RESULT result; 00219 00220 //Remove me from table of all sounds. 00221 _manager->_all_sounds.erase(this); 00222 00223 //The Release Sound 00224 result = _sound->release(); 00225 fmod_audio_errcheck("_sound->release()", result); 00226 } 00227 00228 00229 //////////////////////////////////////////////////////////////////// 00230 // Function: FmodAudioSound:: play 00231 // Access: public 00232 // Description: Plays a sound. 00233 //////////////////////////////////////////////////////////////////// 00234 void FmodAudioSound:: 00235 play() { 00236 start_playing(); 00237 } 00238 00239 //////////////////////////////////////////////////////////////////// 00240 // Function: FmodAudioSound::stop 00241 // Access: public 00242 // Description: Stop a sound 00243 //////////////////////////////////////////////////////////////////// 00244 void FmodAudioSound:: 00245 stop() { 00246 ReMutexHolder holder(FmodAudioManager::_lock); 00247 FMOD_RESULT result; 00248 00249 if (_channel != 0) { 00250 result =_channel->stop(); 00251 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) { 00252 _channel = 0; 00253 } else if (result == FMOD_OK) { 00254 _self_ref.clear(); 00255 } else { 00256 fmod_audio_errcheck("_channel->stop()", result); 00257 } 00258 } 00259 _start_time = 0.0; 00260 } 00261 00262 00263 //////////////////////////////////////////////////////////////////// 00264 // Function: FmodAudioSound::set_loop 00265 // Access: public 00266 // Description: Turns looping on and off 00267 //////////////////////////////////////////////////////////////////// 00268 void FmodAudioSound:: 00269 set_loop(bool loop) { 00270 if (loop) { 00271 set_loop_count(0); 00272 } else { 00273 set_loop_count(1); 00274 } 00275 } 00276 00277 //////////////////////////////////////////////////////////////////// 00278 // Function: FmodAudioSound::get_loop 00279 // Access: public 00280 // Description: Returns whether looping is on or off 00281 //////////////////////////////////////////////////////////////////// 00282 bool FmodAudioSound:: 00283 get_loop() const { 00284 if (get_loop_count() == 1) { 00285 return false; 00286 } else { 00287 return true; 00288 } 00289 } 00290 00291 //////////////////////////////////////////////////////////////////// 00292 // Function: FmodAudioSound::set_loop_count 00293 // Access: public 00294 // Description: 00295 // Panda uses 0 to mean loop forever. 00296 // Fmod uses negative numbers to mean loop forever. 00297 // (0 means don't loop, 1 means play twice, etc. 00298 // We must convert! 00299 //////////////////////////////////////////////////////////////////// 00300 void FmodAudioSound:: 00301 set_loop_count(unsigned long loop_count) { 00302 ReMutexHolder holder(FmodAudioManager::_lock); 00303 audio_debug("FmodAudioSound::set_loop_count() Setting the sound's loop count to: " << loop_count); 00304 00305 //LOCALS 00306 FMOD_RESULT result; 00307 00308 if (loop_count == 0) { 00309 result = _sound->setLoopCount( -1 ); 00310 fmod_audio_errcheck("_sound->setLoopCount()", result); 00311 result =_sound->setMode(FMOD_LOOP_NORMAL); 00312 fmod_audio_errcheck("_sound->setMode()", result); 00313 } else if (loop_count == 1) { 00314 result = _sound->setLoopCount( 1 ); 00315 fmod_audio_errcheck("_sound->setLoopCount()", result); 00316 result =_sound->setMode(FMOD_LOOP_OFF); 00317 fmod_audio_errcheck("_sound->setMode()", result); 00318 } else { 00319 result = _sound->setLoopCount( loop_count ); 00320 fmod_audio_errcheck("_sound->setLoopCount()", result); 00321 result =_sound->setMode(FMOD_LOOP_NORMAL); 00322 fmod_audio_errcheck("_sound->setMode()", result); 00323 } 00324 00325 audio_debug("FmodAudioSound::set_loop_count() Sound's loop count should be set to: " << loop_count); 00326 } 00327 00328 //////////////////////////////////////////////////////////////////// 00329 // Function: FmodAudioSound::get_loop_count 00330 // Access: public 00331 // Description: Return how many times a sound will loop. 00332 //////////////////////////////////////////////////////////////////// 00333 unsigned long FmodAudioSound:: 00334 get_loop_count() const { 00335 ReMutexHolder holder(FmodAudioManager::_lock); 00336 FMOD_RESULT result; 00337 int loop_count; 00338 00339 result = _sound->getLoopCount( &loop_count ); 00340 fmod_audio_errcheck("_sound->getLoopCount()", result); 00341 00342 if (loop_count <= 0) { 00343 return 0; 00344 } else { 00345 return (unsigned long)loop_count; 00346 } 00347 } 00348 00349 //////////////////////////////////////////////////////////////////// 00350 // Function: FmodAudioSound::set_time 00351 // Access: public 00352 // Description: Sets the time at which the next play() operation will 00353 // begin. If we are already playing, skips to that time 00354 // immediatey. 00355 //////////////////////////////////////////////////////////////////// 00356 void FmodAudioSound:: 00357 set_time(PN_stdfloat start_time) { 00358 ReMutexHolder holder(FmodAudioManager::_lock); 00359 _start_time = start_time; 00360 00361 if (status() == PLAYING) { 00362 // Already playing; skip to the indicated time. 00363 start_playing(); 00364 } 00365 } 00366 00367 //////////////////////////////////////////////////////////////////// 00368 // Function: FmodAudioSound::get_time 00369 // Access: public 00370 // Description: Gets the play position within the sound 00371 //////////////////////////////////////////////////////////////////// 00372 PN_stdfloat FmodAudioSound:: 00373 get_time() const { 00374 ReMutexHolder holder(FmodAudioManager::_lock); 00375 FMOD_RESULT result; 00376 unsigned int current_time; 00377 00378 if (_channel == 0) { 00379 return 0.0f; 00380 } 00381 00382 result = _channel->getPosition( ¤t_time , FMOD_TIMEUNIT_MS ); 00383 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) { 00384 return 0.0f; 00385 } 00386 fmod_audio_errcheck("_channel->getPosition()", result); 00387 00388 return ((double)current_time) / 1000.0; 00389 } 00390 00391 //////////////////////////////////////////////////////////////////// 00392 // Function: FmodAudioSound::set_volume(PN_stdfloat vol) 00393 // Access: public 00394 // Description: 0.0 to 1.0 scale of volume converted to Fmod's 00395 // internal 0.0 to 255.0 scale. 00396 //////////////////////////////////////////////////////////////////// 00397 void FmodAudioSound:: 00398 set_volume(PN_stdfloat vol) { 00399 ReMutexHolder holder(FmodAudioManager::_lock); 00400 _volume = vol; 00401 set_volume_on_channel(); 00402 } 00403 00404 //////////////////////////////////////////////////////////////////// 00405 // Function: FmodAudioSound::get_volume 00406 // Access: public 00407 // Description: Gets the current volume of a sound. 1 is Max. O is Min. 00408 //////////////////////////////////////////////////////////////////// 00409 PN_stdfloat FmodAudioSound:: 00410 get_volume() const { 00411 return _volume; 00412 } 00413 00414 //////////////////////////////////////////////////////////////////// 00415 // Function: FmodAudioSound::start_playing 00416 // Access: Private 00417 // Description: Starts the sound playing at _start_time. 00418 //////////////////////////////////////////////////////////////////// 00419 void FmodAudioSound:: 00420 start_playing() { 00421 ReMutexHolder holder(FmodAudioManager::_lock); 00422 FMOD_RESULT result; 00423 00424 if (!_active) { 00425 _paused = true; 00426 return; 00427 } 00428 00429 int startTime = (int)(_start_time * 1000); 00430 00431 if (_channel != 0) { 00432 // try backing up current sound. 00433 result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS ); 00434 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) { 00435 _channel = 0; 00436 00437 } else { 00438 fmod_audio_errcheck("_channel->setPosition()", result); 00439 00440 bool playing; 00441 result = _channel->isPlaying(&playing); 00442 fmod_audio_errcheck("_channel->isPlaying()", result); 00443 if (result != FMOD_OK || !playing) { 00444 _channel = 0; 00445 } 00446 } 00447 } 00448 00449 if (_channel == 0) { 00450 result = _manager->_system->playSound(FMOD_CHANNEL_FREE, _sound, true, &_channel); 00451 fmod_audio_errcheck("_system->playSound()", result); 00452 result = _channel->setChannelGroup(_manager->_channelgroup); 00453 fmod_audio_errcheck("_channel->setChannelGroup()", result); 00454 result = _channel->setUserData(this); 00455 fmod_audio_errcheck("_channel->setUserData()", result); 00456 result = _channel->setCallback(sound_end_callback); 00457 fmod_audio_errcheck("_channel->setCallback()", result); 00458 result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS ); 00459 fmod_audio_errcheck("_channel->setPosition()", result); 00460 00461 set_volume_on_channel(); 00462 set_play_rate_on_channel(); 00463 set_speaker_mix_or_balance_on_channel(); 00464 // add_dsp_on_channel(); 00465 set_3d_attributes_on_channel(); 00466 00467 result = _channel->setPaused(false); 00468 fmod_audio_errcheck("_channel->setPaused()", result); 00469 00470 _self_ref = this; 00471 } 00472 } 00473 00474 //////////////////////////////////////////////////////////////////// 00475 // Function: FmodAudioSound::set_volume_on_channel() 00476 // Access: Private 00477 // Description: Set the volume on a prepared Sound channel. 00478 //////////////////////////////////////////////////////////////////// 00479 void FmodAudioSound:: 00480 set_volume_on_channel() { 00481 ReMutexHolder holder(FmodAudioManager::_lock); 00482 FMOD_RESULT result; 00483 00484 if (_channel != 0) { 00485 result = _channel->setVolume( _volume ); 00486 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) { 00487 _channel = 0; 00488 } else { 00489 fmod_audio_errcheck("_channel->setVolume()", result); 00490 } 00491 } 00492 } 00493 00494 //////////////////////////////////////////////////////////////////// 00495 // Function: FmodAudioSound::set_balance(PN_stdfloat bal) 00496 // Access: public 00497 // Description: -1.0 to 1.0 scale 00498 //////////////////////////////////////////////////////////////////// 00499 void FmodAudioSound:: 00500 set_balance(PN_stdfloat bal) { 00501 ReMutexHolder holder(FmodAudioManager::_lock); 00502 _balance = bal; 00503 set_speaker_mix_or_balance_on_channel(); 00504 } 00505 00506 //////////////////////////////////////////////////////////////////// 00507 // Function: FmodAudioSound::get_balance 00508 // Access: public 00509 // Description: -1.0 to 1.0 scale 00510 // -1 should be all the way left. 00511 // 1 is all the way to the right. 00512 //////////////////////////////////////////////////////////////////// 00513 PN_stdfloat FmodAudioSound:: 00514 get_balance() const { 00515 return _balance; 00516 } 00517 00518 //////////////////////////////////////////////////////////////////// 00519 // Function: FmodAudioSound::set_play_rate(PN_stdfloat rate) 00520 // Access: public 00521 // Description: Sets the speed at which a sound plays back. 00522 // The rate is a multiple of the sound, normal playback speed. 00523 // IE 2 would play back 2 times fast, 3 would play 3 times, and so on. 00524 // This can also be set to a negative number so a sound plays backwards. 00525 // But rememeber if the sound is not playing, you must set the 00526 // sound's time to its end to hear a song play backwards. 00527 //////////////////////////////////////////////////////////////////// 00528 void FmodAudioSound:: 00529 set_play_rate(PN_stdfloat rate) { 00530 ReMutexHolder holder(FmodAudioManager::_lock); 00531 _playrate = rate; 00532 set_play_rate_on_channel(); 00533 } 00534 00535 //////////////////////////////////////////////////////////////////// 00536 // Function: FmodAudioSound::get_play_rate 00537 // Access: public 00538 // Description: 00539 //////////////////////////////////////////////////////////////////// 00540 PN_stdfloat FmodAudioSound:: 00541 get_play_rate() const { 00542 return _playrate; 00543 } 00544 00545 //////////////////////////////////////////////////////////////////// 00546 // Function: FmodAudioSound::set_play_rate_on_channel() 00547 // Access: public 00548 // Description: Set the play rate on a prepared Sound channel. 00549 //////////////////////////////////////////////////////////////////// 00550 void FmodAudioSound:: 00551 set_play_rate_on_channel() { 00552 ReMutexHolder holder(FmodAudioManager::_lock); 00553 FMOD_RESULT result; 00554 PN_stdfloat frequency = _sampleFrequency * _playrate; 00555 00556 if (_channel != 0) { 00557 result = _channel->setFrequency( frequency ); 00558 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) { 00559 _channel = 0; 00560 } else { 00561 fmod_audio_errcheck("_channel->setFrequency()", result); 00562 } 00563 } 00564 } 00565 00566 //////////////////////////////////////////////////////////////////// 00567 // Function: FmodAudioSound::get_name 00568 // Access: public 00569 // Description: Get name of sound file 00570 //////////////////////////////////////////////////////////////////// 00571 const string& FmodAudioSound:: 00572 get_name() const { 00573 return _file_name; 00574 } 00575 00576 //////////////////////////////////////////////////////////////////// 00577 // Function: FmodAudioSound::length 00578 // Access: public 00579 // Description: Get length 00580 // FMOD returns the time in MS so we have to convert to seconds. 00581 //////////////////////////////////////////////////////////////////// 00582 PN_stdfloat FmodAudioSound:: 00583 length() const { 00584 ReMutexHolder holder(FmodAudioManager::_lock); 00585 FMOD_RESULT result; 00586 unsigned int length; 00587 00588 result = _sound->getLength( &length, FMOD_TIMEUNIT_MS ); 00589 fmod_audio_errcheck("_sound->getLength()", result); 00590 00591 return ((double)length) / 1000.0; 00592 } 00593 00594 //////////////////////////////////////////////////////////////////// 00595 // Function: FmodAudioSound::set_3d_attributes 00596 // Access: public 00597 // Description: Set position and velocity of this sound 00598 // NOW LISTEN UP!!! THIS IS IMPORTANT! 00599 // Both Panda3D and FMOD use a left handed coordinate system. 00600 // But there is a major difference! 00601 // In Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up. 00602 // In FMOD the Y-Axis is going up and the Z-Axis is going into the screen. 00603 // The solution is simple, we just flip the Y and Z axis, as we move coordinates 00604 // from Panda to FMOD and back. 00605 // What does did mean to average Panda user? Nothing, they shouldn't notice anyway. 00606 // But if you decide to do any 3D audio work in here you have to keep it in mind. 00607 // I told you, so you can't say I didn't. 00608 //////////////////////////////////////////////////////////////////// 00609 void FmodAudioSound:: 00610 set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) { 00611 ReMutexHolder holder(FmodAudioManager::_lock); 00612 _location.x = px; 00613 _location.y = pz; 00614 _location.z = py; 00615 00616 _velocity.x = vx; 00617 _velocity.y = vz; 00618 _velocity.z = vy; 00619 00620 set_3d_attributes_on_channel(); 00621 } 00622 00623 //////////////////////////////////////////////////////////////////// 00624 // Function: FmodAudioSound::set_3d_attributes_on_channel 00625 // Access: public 00626 // Description: 00627 //////////////////////////////////////////////////////////////////// 00628 void FmodAudioSound:: 00629 set_3d_attributes_on_channel() { 00630 ReMutexHolder holder(FmodAudioManager::_lock); 00631 FMOD_RESULT result; 00632 FMOD_MODE soundMode; 00633 00634 result = _sound->getMode(&soundMode); 00635 fmod_audio_errcheck("_sound->getMode()", result); 00636 00637 if ((_channel != 0) && (soundMode & FMOD_3D)) { 00638 result = _channel->set3DAttributes( &_location, &_velocity ); 00639 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) { 00640 _channel = 0; 00641 } else { 00642 fmod_audio_errcheck("_channel->set3DAttributes()", result); 00643 } 00644 } 00645 } 00646 00647 //////////////////////////////////////////////////////////////////// 00648 // Function: FmodAudioSound::get_3d_attributes 00649 // Access: public 00650 // Description: Get position and velocity of this sound 00651 // Currently unimplemented. Get the attributes of the attached object. 00652 //////////////////////////////////////////////////////////////////// 00653 void FmodAudioSound:: 00654 get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) { 00655 audio_error("get3dAttributes: Currently unimplemented. Get the attributes of the attached object."); 00656 } 00657 00658 //////////////////////////////////////////////////////////////////// 00659 // Function: FmodAudioSound::set_3d_min_distance 00660 // Access: public 00661 // Description: Set the distance that this sound begins to fall off. Also 00662 // affects the rate it falls off. 00663 //////////////////////////////////////////////////////////////////// 00664 void FmodAudioSound:: 00665 set_3d_min_distance(PN_stdfloat dist) { 00666 ReMutexHolder holder(FmodAudioManager::_lock); 00667 FMOD_RESULT result; 00668 00669 _min_dist = dist; 00670 00671 result = _sound->set3DMinMaxDistance( dist, _max_dist ); 00672 fmod_audio_errcheck("_sound->set3DMinMaxDistance()", result); 00673 } 00674 00675 //////////////////////////////////////////////////////////////////// 00676 // Function: FmodAudioSound::get_3d_min_distance 00677 // Access: public 00678 // Description: Get the distance that this sound begins to fall off 00679 //////////////////////////////////////////////////////////////////// 00680 PN_stdfloat FmodAudioSound:: 00681 get_3d_min_distance() const { 00682 return _min_dist; 00683 } 00684 00685 //////////////////////////////////////////////////////////////////// 00686 // Function: FmodAudioSound::set_3d_max_distance 00687 // Access: public 00688 // Description: Set the distance that this sound stops falling off 00689 //////////////////////////////////////////////////////////////////// 00690 void FmodAudioSound:: 00691 set_3d_max_distance(PN_stdfloat dist) { 00692 ReMutexHolder holder(FmodAudioManager::_lock); 00693 FMOD_RESULT result; 00694 00695 _max_dist = dist; 00696 00697 result = _sound->set3DMinMaxDistance( _min_dist, dist ); 00698 fmod_audio_errcheck("_sound->set3DMinMaxDistance()", result); 00699 } 00700 00701 //////////////////////////////////////////////////////////////////// 00702 // Function: FmodAudioSound::get_3d_max_distance 00703 // Access: public 00704 // Description: Get the distance that this sound stops falling off 00705 //////////////////////////////////////////////////////////////////// 00706 PN_stdfloat FmodAudioSound:: 00707 get_3d_max_distance() const { 00708 return _max_dist; 00709 } 00710 00711 //////////////////////////////////////////////////////////////////// 00712 // Function: FmodAudioSound::get_speaker_mix 00713 // Access: Published 00714 // Description: In Multichannel Speaker systems [like Surround]. 00715 // 00716 // Speakers which don't exist in some systems will simply be ignored. 00717 // But I haven't been able to test this yet, so I am jsut letting you know. 00718 // 00719 // BTW This will also work in Stereo speaker systems, but since 00720 // PANDA/FMOD has a balance [pan] function what is the point? 00721 //////////////////////////////////////////////////////////////////// 00722 PN_stdfloat FmodAudioSound:: 00723 get_speaker_mix(AudioManager::SpeakerId speaker) { 00724 ReMutexHolder holder(FmodAudioManager::_lock); 00725 if (_channel == 0) { 00726 return 0.0; 00727 } 00728 00729 FMOD_RESULT result; 00730 float frontleft; 00731 float frontright; 00732 float center; 00733 float sub; 00734 float backleft; 00735 float backright; 00736 float sideleft; 00737 float sideright; 00738 00739 result = _channel->getSpeakerMix( &frontleft, &frontright, ¢er, &sub, &backleft, &backright, &sideleft, &sideright ); 00740 fmod_audio_errcheck("_channel->getSpeakerMix()", result); 00741 00742 switch(speaker) { 00743 case AudioManager::SPK_frontleft: return frontleft; 00744 case AudioManager::SPK_frontright: return frontright; 00745 case AudioManager::SPK_center: return center; 00746 case AudioManager::SPK_sub: return sub; 00747 case AudioManager::SPK_backleft: return backleft; 00748 case AudioManager::SPK_backright: return backright; 00749 case AudioManager::SPK_sideleft: return sideleft; 00750 case AudioManager::SPK_sideright: return sideright; 00751 default: return 0.0; 00752 } 00753 } 00754 00755 //////////////////////////////////////////////////////////////////// 00756 // Function: FmodAudioSound::set_speaker_mix 00757 // Access: Published 00758 // Description: This sets the speaker mix for Surround Sound sytems. 00759 // It required 8 parameters which match up to the following: 00760 // 00761 // * 1 = Front Left 00762 // * 2 = Front Right 00763 // * 3 = Center 00764 // * 4 = Subwoofer 00765 // * 5 = Back Left 00766 // * 6 = Back Right 00767 // * 7 = Side Left 00768 // * 8 = Side Right 00769 // 00770 //////////////////////////////////////////////////////////////////// 00771 void FmodAudioSound:: 00772 set_speaker_mix(PN_stdfloat frontleft, PN_stdfloat frontright, PN_stdfloat center, PN_stdfloat sub, PN_stdfloat backleft, PN_stdfloat backright, PN_stdfloat sideleft, PN_stdfloat sideright) { 00773 ReMutexHolder holder(FmodAudioManager::_lock); 00774 _mix[AudioManager::SPK_frontleft] = frontleft; 00775 _mix[AudioManager::SPK_frontright] = frontright; 00776 _mix[AudioManager::SPK_center] = center; 00777 _mix[AudioManager::SPK_sub] = sub; 00778 _mix[AudioManager::SPK_backleft] = backleft; 00779 _mix[AudioManager::SPK_backright] = backright; 00780 _mix[AudioManager::SPK_sideleft] = sideleft; 00781 _mix[AudioManager::SPK_sideright] = sideright; 00782 00783 set_speaker_mix_or_balance_on_channel(); 00784 } 00785 00786 //////////////////////////////////////////////////////////////////// 00787 // Function: FmodAudioSound::set_speaker_mix_or_balance_on_channel 00788 // Access: Private 00789 // Description: This is simply a safety catch. 00790 // If you are using a Stero speaker setup Panda will only pay attention 00791 // to 'set_balance()' command when setting speaker balances. 00792 // Other wise it will use 'set_speaker_mix'. 00793 // I put this in, because other wise you end up with a sitation, 00794 // where 'set_speaker_mix()' or 'set_balace()' will override any 00795 // previous speaker balance setups. It all depends on which was called last. 00796 //////////////////////////////////////////////////////////////////// 00797 void FmodAudioSound:: 00798 set_speaker_mix_or_balance_on_channel() { 00799 ReMutexHolder holder(FmodAudioManager::_lock); 00800 FMOD_RESULT result; 00801 FMOD_MODE soundMode; 00802 00803 result = _sound->getMode(&soundMode); 00804 fmod_audio_errcheck("_sound->getMode()", result); 00805 00806 if ((_channel != 0) && (( soundMode & FMOD_3D ) == 0)) { 00807 if ( _speakermode == FMOD_SPEAKERMODE_STEREO ) { 00808 result = _channel->setPan( _balance ); 00809 } else { 00810 result = _channel->setSpeakerMix( _mix[AudioManager::SPK_frontleft], 00811 _mix[AudioManager::SPK_frontright], 00812 _mix[AudioManager::SPK_center], 00813 _mix[AudioManager::SPK_sub], 00814 _mix[AudioManager::SPK_backleft], 00815 _mix[AudioManager::SPK_backright], 00816 _mix[AudioManager::SPK_sideleft], 00817 _mix[AudioManager::SPK_sideright] 00818 ); 00819 } 00820 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) { 00821 _channel = 0; 00822 } else { 00823 fmod_audio_errcheck("_channel->setSpeakerMix()/setPan()", result); 00824 } 00825 } 00826 } 00827 00828 //////////////////////////////////////////////////////////////////// 00829 // Function: FmodAudioSound::get_priority 00830 // Access: Published 00831 // Description: Sets the priority of a sound. 00832 // This is what FMOD uses to determine is a sound will 00833 // play if all the other real channels have been used up. 00834 //////////////////////////////////////////////////////////////////// 00835 int FmodAudioSound:: 00836 get_priority() { 00837 audio_debug("FmodAudioSound::get_priority()"); 00838 return _priority; 00839 } 00840 00841 //////////////////////////////////////////////////////////////////// 00842 // Function: FmodAudioSound::set_priority(int priority) 00843 // Access: Published 00844 // Description: Sets the Sound Priority [Whether is will be played 00845 // over other sound when real audio channels become short. 00846 //////////////////////////////////////////////////////////////////// 00847 void FmodAudioSound:: 00848 set_priority(int priority) { 00849 ReMutexHolder holder(FmodAudioManager::_lock); 00850 00851 audio_debug("FmodAudioSound::set_priority()"); 00852 00853 FMOD_RESULT result; 00854 00855 _priority = priority; 00856 00857 result = _sound->setDefaults( _sampleFrequency, _volume , _balance, _priority); 00858 fmod_audio_errcheck("_sound->setDefaults()", result); 00859 } 00860 00861 //////////////////////////////////////////////////////////////////// 00862 // Function: FmodAudioSound::status 00863 // Access: public 00864 // Description: Get status of the sound. 00865 //////////////////////////////////////////////////////////////////// 00866 AudioSound::SoundStatus FmodAudioSound:: 00867 status() const { 00868 ReMutexHolder holder(FmodAudioManager::_lock); 00869 FMOD_RESULT result; 00870 bool playingState; 00871 00872 if ( _channel == 0 ) { 00873 return READY; 00874 } 00875 00876 result = _channel->isPlaying( &playingState ); 00877 if ((result == FMOD_OK) && (playingState == true)) { 00878 return PLAYING; 00879 } else { 00880 return READY; 00881 } 00882 } 00883 00884 //////////////////////////////////////////////////////////////////// 00885 // Function: FmodAudioSound::set_active 00886 // Access: public 00887 // Description: Sets whether the sound is marked "active". By 00888 // default, the active flag true for all sounds. If the 00889 // active flag is set to false for any particular sound, 00890 // the sound will not be heard. 00891 //////////////////////////////////////////////////////////////////// 00892 void FmodAudioSound:: 00893 set_active(bool active) { 00894 ReMutexHolder holder(FmodAudioManager::_lock); 00895 if (_active != active) { 00896 _active = active; 00897 if (_active) { 00898 // ...activate the sound. 00899 if (_paused && get_loop_count()==0) { 00900 // ...this sound was looping when it was paused. 00901 _paused = false; 00902 play(); 00903 } 00904 00905 } else { 00906 // ...deactivate the sound. 00907 if (status() == PLAYING) { 00908 if (get_loop_count() == 0) { 00909 // ...we're pausing a looping sound. 00910 _paused = true; 00911 _start_time = get_time(); 00912 } 00913 stop(); 00914 } 00915 } 00916 } 00917 } 00918 00919 00920 //////////////////////////////////////////////////////////////////// 00921 // Function: FmodAudioSound::get_active 00922 // Access: public 00923 // Description: Returns whether the sound has been marked "active". 00924 //////////////////////////////////////////////////////////////////// 00925 bool FmodAudioSound:: 00926 get_active() const { 00927 return _active; 00928 } 00929 00930 //////////////////////////////////////////////////////////////////// 00931 // Function: FmodAudioSound::finished 00932 // Access: public 00933 // Description: Not implemented. 00934 //////////////////////////////////////////////////////////////////// 00935 void FmodAudioSound:: 00936 finished() { 00937 audio_error("finished: not implemented under FMOD-EX"); 00938 } 00939 00940 //////////////////////////////////////////////////////////////////// 00941 // Function: FmodAudioSound::set_finished_event 00942 // Access: public 00943 // Description: NOT USED ANYMORE!!! 00944 // Assign a string for the finished event to be referenced 00945 // by in python by an accept method 00946 // 00947 //////////////////////////////////////////////////////////////////// 00948 void FmodAudioSound:: 00949 set_finished_event(const string& event) { 00950 audio_error("set_finished_event: not implemented under FMOD-EX"); 00951 } 00952 00953 //////////////////////////////////////////////////////////////////// 00954 // Function: FmodAudioSound::get_finished_event 00955 // Access: public 00956 // Description:NOT USED ANYMORE!!! 00957 // Return the string the finished event is referenced by 00958 // 00959 // 00960 //////////////////////////////////////////////////////////////////// 00961 const string& FmodAudioSound:: 00962 get_finished_event() const { 00963 audio_error("get_finished_event: not implemented under FMOD-EX"); 00964 return _finished_event; 00965 } 00966 00967 //////////////////////////////////////////////////////////////////// 00968 // Function: FmodAudioSound::sound_end_callback 00969 // Access: Private, Static 00970 // Description: When fmod finishes playing a sound, decrements the 00971 // reference count of the associated FmodAudioSound. 00972 //////////////////////////////////////////////////////////////////// 00973 FMOD_RESULT F_CALLBACK FmodAudioSound:: 00974 sound_end_callback(FMOD_CHANNEL * channel, 00975 FMOD_CHANNEL_CALLBACKTYPE type, 00976 void *commanddata1, 00977 void *commanddata2) { 00978 // Fortunately, this callback is made synchronously rather than 00979 // asynchronously (it is triggered during System::update()), so we 00980 // don't have to worry about thread-related issues here. 00981 if (type == FMOD_CHANNEL_CALLBACKTYPE_END) { 00982 FMOD::Channel *fc = (FMOD::Channel *)channel; 00983 void *userdata = NULL; 00984 FMOD_RESULT result = fc->getUserData(&userdata); 00985 fmod_audio_errcheck("channel->getUserData()", result); 00986 FmodAudioSound *fsound = (FmodAudioSound*)userdata; 00987 fsound->_self_ref = fsound; 00988 } 00989 return FMOD_OK; 00990 } 00991 00992 //////////////////////////////////////////////////////////////////// 00993 // Function: FmodAudioSound::open_callback 00994 // Access: Private, Static 00995 // Description: A hook into Panda's virtual file system. 00996 //////////////////////////////////////////////////////////////////// 00997 FMOD_RESULT F_CALLBACK FmodAudioSound:: 00998 open_callback(const char *name, int, unsigned int *file_size, 00999 void **handle, void **user_data) { 01000 // We actually pass in the VirtualFile pointer as the "name". 01001 VirtualFile *file = (VirtualFile *)name; 01002 if (file == (VirtualFile *)NULL) { 01003 return FMOD_ERR_FILE_NOTFOUND; 01004 } 01005 if (fmodAudio_cat.is_spam()) { 01006 fmodAudio_cat.spam() 01007 << "open_callback(" << *file << ")\n"; 01008 } 01009 01010 istream *str = file->open_read_file(true); 01011 01012 (*file_size) = file->get_file_size(str); 01013 (*handle) = (void *)str; 01014 (*user_data) = (void *)file; 01015 01016 // Explicitly ref the VirtualFile since we're storing it in a void 01017 // pointer instead of a PT(VirtualFile). 01018 file->ref(); 01019 01020 return FMOD_OK; 01021 } 01022 01023 //////////////////////////////////////////////////////////////////// 01024 // Function: FmodAudioSound::close_callback 01025 // Access: Private, Static 01026 // Description: A hook into Panda's virtual file system. 01027 //////////////////////////////////////////////////////////////////// 01028 FMOD_RESULT F_CALLBACK FmodAudioSound:: 01029 close_callback(void *handle, void *user_data) { 01030 VirtualFile *file = (VirtualFile *)user_data; 01031 if (fmodAudio_cat.is_spam()) { 01032 fmodAudio_cat.spam() 01033 << "close_callback(" << *file << ")\n"; 01034 } 01035 01036 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 01037 01038 istream *str = (istream *)handle; 01039 vfs->close_read_file(str); 01040 01041 // Explicitly unref the VirtualFile pointer. 01042 unref_delete(file); 01043 01044 return FMOD_OK; 01045 } 01046 01047 //////////////////////////////////////////////////////////////////// 01048 // Function: FmodAudioSound::read_callback 01049 // Access: Private, Static 01050 // Description: A hook into Panda's virtual file system. 01051 //////////////////////////////////////////////////////////////////// 01052 FMOD_RESULT F_CALLBACK FmodAudioSound:: 01053 read_callback(void *handle, void *buffer, unsigned int size_bytes, 01054 unsigned int *bytes_read, void *user_data) { 01055 VirtualFile *file = (VirtualFile *)user_data; 01056 if (fmodAudio_cat.is_spam()) { 01057 fmodAudio_cat.spam() 01058 << "read_callback(" << *file << ", " << size_bytes << ")\n"; 01059 } 01060 01061 istream *str = (istream *)handle; 01062 str->read((char *)buffer, size_bytes); 01063 (*bytes_read) = str->gcount(); 01064 01065 // We can't yield here, since this callback is made within a 01066 // sub-thread--an OS-level sub-thread spawned by FMod, not a Panda 01067 // thread. But we will only execute this code in the true-threads 01068 // case anyway. 01069 //thread_consider_yield(); 01070 01071 if (str->eof()) { 01072 if ((*bytes_read) == 0) { 01073 return FMOD_ERR_FILE_EOF; 01074 } else { 01075 // Report the EOF next time. 01076 return FMOD_OK; 01077 } 01078 } if (str->fail()) { 01079 return FMOD_ERR_FILE_BAD; 01080 } else { 01081 return FMOD_OK; 01082 } 01083 } 01084 01085 //////////////////////////////////////////////////////////////////// 01086 // Function: FmodAudioSound::seek_callback 01087 // Access: Private, Static 01088 // Description: A hook into Panda's virtual file system. 01089 //////////////////////////////////////////////////////////////////// 01090 FMOD_RESULT F_CALLBACK FmodAudioSound:: 01091 seek_callback(void *handle, unsigned int pos, void *user_data) { 01092 VirtualFile *file = (VirtualFile *)user_data; 01093 if (fmodAudio_cat.is_spam()) { 01094 fmodAudio_cat.spam() 01095 << "seek_callback(" << *file << ", " << pos << ")\n"; 01096 } 01097 01098 istream *str = (istream *)handle; 01099 str->clear(); 01100 str->seekg(pos); 01101 01102 if (str->fail() && !str->eof()) { 01103 return FMOD_ERR_FILE_COULDNOTSEEK; 01104 } else { 01105 return FMOD_OK; 01106 } 01107 } 01108 01109 01110 #endif //]