Panda3D
 All Classes Functions Variables Enumerations
fmodAudioSound.cxx
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( &current_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, &center, &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 //]
 All Classes Functions Variables Enumerations