Panda3D
fmodAudioSound.cxx
1 // Filename: fmodAudioSound.cxx
2 // Created by: cort (January 22, 2003)
3 // Extended by: ben (October 22, 2003)
4 // Prior system by: cary
5 // Rewrite [for new Version of FMOD-EX] by: Stan Rosenbaum "Staque" - Spring 2006
6 //
7 //
8 ////////////////////////////////////////////////////////////////////
9 //
10 // PANDA 3D SOFTWARE
11 // Copyright (c) Carnegie Mellon University. All rights reserved.
12 //
13 // All use of this software is subject to the terms of the revised BSD
14 // license. You should have received a copy of this license along
15 // with this source code in a file named "LICENSE."
16 //
17 ////////////////////////////////////////////////////////////////////
18 
19 #include "pandabase.h"
20 #include "dcast.h"
21 
22 //Panda Headers
23 #include "config_audio.h"
24 #include "config_fmodAudio.h"
25 #include "fmodAudioSound.h"
26 #include "string_utils.h"
27 #include "subfileInfo.h"
28 #include "reMutexHolder.h"
29 #include "virtualFileSystem.h"
30 
31 TypeHandle FmodAudioSound::_type_handle;
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: FmodAudioSound::FmodAudioSound
35 // Access: public
36 // Description: Constructor
37 // All sound will DEFAULT load as a 2D sound unless
38 // otherwise specified.
39 ////////////////////////////////////////////////////////////////////
40 
42 FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
43  ReMutexHolder holder(FmodAudioManager::_lock);
44  audio_debug("FmodAudioSound::FmodAudioSound() Creating new sound, filename: " << file_name );
45 
46  _active = manager->get_active();
47  _paused = false;
48  _start_time = 0.0;
49 
50  //Local Variables that are needed.
51  FMOD_RESULT result;
52 
53  //Inits 3D Attributes
54  _location.x = 0;
55  _location.y = 0;
56  _location.z = 0;
57 
58  _velocity.x = 0;
59  _velocity.y = 0;
60  _velocity.z = 0;
61 
62  //Play Rate Variable
63  _playrate = 1;
64 
65  // These set the Speaker Levels to a default if you are using a MultiChannel Setup.
66  for (int i=0; i<AudioManager::SPK_COUNT; i++) {
67  _mix[i] = 1.0;
68  }
69 
70  //Assign the values we need
71  FmodAudioManager *fmanager;
72  DCAST_INTO_V(fmanager, manager);
73  _manager = fmanager;
74 
75  _channel = 0;
76  _file_name = file_name;
77  _file_name.set_binary();
78 
79  //Get the Speaker Mode [Important for later on.]
80  result = _manager->_system->getSpeakerMode( &_speakermode );
81  fmod_audio_errcheck("_system->getSpeakerMode()", result);
82 
84  PT(VirtualFile) file = vfs->get_file(_file_name);
85  if (file == (VirtualFile *)NULL) {
86  // File not found. We will display the appropriate error message
87  // below.
88  result = FMOD_ERR_FILE_NOTFOUND;
89 
90  } else {
91  bool preload = (fmod_audio_preload_threshold < 0) || (file->get_file_size() < fmod_audio_preload_threshold);
92  int flags = FMOD_SOFTWARE;
93  flags |= positional ? FMOD_3D : FMOD_2D;
94 
95  FMOD_CREATESOUNDEXINFO sound_info;
96  memset(&sound_info, 0, sizeof(sound_info));
97  sound_info.cbsize = sizeof(sound_info);
98 
99  string ext = downcase(_file_name.get_extension());
100  if (ext == "mid") {
101  // Get the MIDI parameters.
102  memcpy(&sound_info, &_manager->_midi_info, sizeof(sound_info));
103  if (sound_info.dlsname != NULL) {
104  audio_debug("Using DLS file " << sound_info.dlsname);
105  }
106  }
107 
108  const char *name_or_data = _file_name.c_str();
109  string os_filename;
110 
111  pvector<unsigned char> mem_buffer;
112  SubfileInfo info;
113  if (preload) {
114  // Pre-read the file right now, and pass it in as a memory
115  // buffer. This avoids threading issues completely, because all
116  // of the reading happens right here.
117  file->read_file(mem_buffer, true);
118  sound_info.length = mem_buffer.size();
119  if (mem_buffer.size() != 0) {
120  name_or_data = (const char *)&mem_buffer[0];
121  }
122  flags |= FMOD_OPENMEMORY;
123  if (fmodAudio_cat.is_debug()) {
124  fmodAudio_cat.debug()
125  << "Reading " << _file_name << " into memory (" << sound_info.length
126  << " bytes)\n";
127  }
128 
129  } else if (file->get_system_info(info)) {
130  // The file exists on disk (or it's part of a multifile that
131  // exists on disk), so we can have FMod read the file directly.
132  // This is also safe, because FMod uses its own I/O operations
133  // that don't involve Panda, so this can safely happen in an
134  // FMod thread.
135  os_filename = info.get_filename().to_os_specific();
136  name_or_data = os_filename.c_str();
137  sound_info.fileoffset = (unsigned int)info.get_start();
138  sound_info.length = (unsigned int)info.get_size();
139  flags |= FMOD_CREATESTREAM;
140  if (fmodAudio_cat.is_debug()) {
141  fmodAudio_cat.debug()
142  << "Streaming " << _file_name << " from disk (" << name_or_data
143  << ", " << sound_info.fileoffset << ", " << sound_info.length << ")\n";
144  }
145 
146  } else {
147 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
148  // Otherwise, if the Panda threading system is compiled in, we
149  // can assign callbacks to read the file through the VFS.
150  name_or_data = (const char *)file.p();
151  sound_info.length = (unsigned int)info.get_size();
152  sound_info.useropen = open_callback;
153  sound_info.userclose = close_callback;
154  sound_info.userread = read_callback;
155  sound_info.userseek = seek_callback;
156  flags |= FMOD_CREATESTREAM;
157  if (fmodAudio_cat.is_debug()) {
158  fmodAudio_cat.debug()
159  << "Streaming " << _file_name << " from disk using callbacks\n";
160  }
161 
162 #else // HAVE_THREADS && !SIMPLE_THREADS
163  // Without threads, we can't safely read this file.
164  name_or_data = "";
165 
166  fmodAudio_cat.warning()
167  << "Cannot stream " << _file_name << "; file is not literally on disk.\n";
168 #endif
169  }
170 
171  result =
172  _manager->_system->createSound(name_or_data, flags, &sound_info, &_sound);
173  }
174 
175  if (result != FMOD_OK) {
176  audio_error("createSound(" << _file_name << "): " << FMOD_ErrorString(result));
177 
178  // We couldn't load the sound file. Create a blank sound record
179  // instead.
180  FMOD_CREATESOUNDEXINFO sound_info;
181  memset(&sound_info, 0, sizeof(sound_info));
182  char blank_data[100];
183  memset(blank_data, 0, sizeof(blank_data));
184  sound_info.cbsize = sizeof(sound_info);
185  sound_info.length = sizeof(blank_data);
186  sound_info.numchannels = 1;
187  sound_info.defaultfrequency = 8000;
188  sound_info.format = FMOD_SOUND_FORMAT_PCM16;
189  int flags = FMOD_SOFTWARE | FMOD_OPENMEMORY | FMOD_OPENRAW;
190 
191  result = _manager->_system->createSound( blank_data, flags, &sound_info, &_sound);
192  fmod_audio_errcheck("createSound (blank)", result);
193  }
194 
195  // Some WAV files contain a loop bit. This is not handled
196  // consistently. Override it.
197  _sound->setLoopCount(1);
198  _sound->setMode(FMOD_LOOP_OFF);
199 
200  //This is just to collect the defaults of the sound, so we don't
201  //Have to query FMOD everytime for the info.
202  //It is also important we get the '_sampleFrequency' variable here, for the
203  //'set_play_rate()' and 'get_play_rate()' methods later;
204 
205  result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority);
206  fmod_audio_errcheck("_sound->getDefaults()", result);
207 }
208 
209 
210 ////////////////////////////////////////////////////////////////////
211 // Function: FmodAudioSound::~FmodAudioSound
212 // Access: public
213 // Description: DESTRUCTOR!!!
214 ////////////////////////////////////////////////////////////////////
217  ReMutexHolder holder(FmodAudioManager::_lock);
218  FMOD_RESULT result;
219 
220  //Remove me from table of all sounds.
221  _manager->_all_sounds.erase(this);
222 
223  //The Release Sound
224  result = _sound->release();
225  fmod_audio_errcheck("_sound->release()", result);
226 }
227 
228 
229 ////////////////////////////////////////////////////////////////////
230 // Function: FmodAudioSound:: play
231 // Access: public
232 // Description: Plays a sound.
233 ////////////////////////////////////////////////////////////////////
234 void FmodAudioSound::
235 play() {
236  start_playing();
237 }
238 
239 ////////////////////////////////////////////////////////////////////
240 // Function: FmodAudioSound::stop
241 // Access: public
242 // Description: Stop a sound
243 ////////////////////////////////////////////////////////////////////
244 void FmodAudioSound::
245 stop() {
246  ReMutexHolder holder(FmodAudioManager::_lock);
247  FMOD_RESULT result;
248 
249  if (_channel != 0) {
250  result =_channel->stop();
251  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
252  _channel = 0;
253  } else if (result == FMOD_OK) {
254  _self_ref.clear();
255  } else {
256  fmod_audio_errcheck("_channel->stop()", result);
257  }
258  }
259  _start_time = 0.0;
260 }
261 
262 
263 ////////////////////////////////////////////////////////////////////
264 // Function: FmodAudioSound::set_loop
265 // Access: public
266 // Description: Turns looping on and off
267 ////////////////////////////////////////////////////////////////////
268 void FmodAudioSound::
269 set_loop(bool loop) {
270  if (loop) {
271  set_loop_count(0);
272  } else {
273  set_loop_count(1);
274  }
275 }
276 
277 ////////////////////////////////////////////////////////////////////
278 // Function: FmodAudioSound::get_loop
279 // Access: public
280 // Description: Returns whether looping is on or off
281 ////////////////////////////////////////////////////////////////////
282 bool FmodAudioSound::
283 get_loop() const {
284  if (get_loop_count() == 1) {
285  return false;
286  } else {
287  return true;
288  }
289 }
290 
291 ////////////////////////////////////////////////////////////////////
292 // Function: FmodAudioSound::set_loop_count
293 // Access: public
294 // Description:
295 // Panda uses 0 to mean loop forever.
296 // Fmod uses negative numbers to mean loop forever.
297 // (0 means don't loop, 1 means play twice, etc.
298 // We must convert!
299 ////////////////////////////////////////////////////////////////////
300 void FmodAudioSound::
301 set_loop_count(unsigned long loop_count) {
302  ReMutexHolder holder(FmodAudioManager::_lock);
303  audio_debug("FmodAudioSound::set_loop_count() Setting the sound's loop count to: " << loop_count);
304 
305  //LOCALS
306  FMOD_RESULT result;
307 
308  if (loop_count == 0) {
309  result = _sound->setLoopCount( -1 );
310  fmod_audio_errcheck("_sound->setLoopCount()", result);
311  result =_sound->setMode(FMOD_LOOP_NORMAL);
312  fmod_audio_errcheck("_sound->setMode()", result);
313  } else if (loop_count == 1) {
314  result = _sound->setLoopCount( 1 );
315  fmod_audio_errcheck("_sound->setLoopCount()", result);
316  result =_sound->setMode(FMOD_LOOP_OFF);
317  fmod_audio_errcheck("_sound->setMode()", result);
318  } else {
319  result = _sound->setLoopCount( loop_count );
320  fmod_audio_errcheck("_sound->setLoopCount()", result);
321  result =_sound->setMode(FMOD_LOOP_NORMAL);
322  fmod_audio_errcheck("_sound->setMode()", result);
323  }
324 
325  audio_debug("FmodAudioSound::set_loop_count() Sound's loop count should be set to: " << loop_count);
326 }
327 
328 ////////////////////////////////////////////////////////////////////
329 // Function: FmodAudioSound::get_loop_count
330 // Access: public
331 // Description: Return how many times a sound will loop.
332 ////////////////////////////////////////////////////////////////////
333 unsigned long FmodAudioSound::
334 get_loop_count() const {
335  ReMutexHolder holder(FmodAudioManager::_lock);
336  FMOD_RESULT result;
337  int loop_count;
338 
339  result = _sound->getLoopCount( &loop_count );
340  fmod_audio_errcheck("_sound->getLoopCount()", result);
341 
342  if (loop_count <= 0) {
343  return 0;
344  } else {
345  return (unsigned long)loop_count;
346  }
347 }
348 
349 ////////////////////////////////////////////////////////////////////
350 // Function: FmodAudioSound::set_time
351 // Access: public
352 // Description: Sets the time at which the next play() operation will
353 // begin. If we are already playing, skips to that time
354 // immediatey.
355 ////////////////////////////////////////////////////////////////////
356 void FmodAudioSound::
357 set_time(PN_stdfloat start_time) {
358  ReMutexHolder holder(FmodAudioManager::_lock);
359  _start_time = start_time;
360 
361  if (status() == PLAYING) {
362  // Already playing; skip to the indicated time.
363  start_playing();
364  }
365 }
366 
367 ////////////////////////////////////////////////////////////////////
368 // Function: FmodAudioSound::get_time
369 // Access: public
370 // Description: Gets the play position within the sound
371 ////////////////////////////////////////////////////////////////////
372 PN_stdfloat FmodAudioSound::
373 get_time() const {
374  ReMutexHolder holder(FmodAudioManager::_lock);
375  FMOD_RESULT result;
376  unsigned int current_time;
377 
378  if (_channel == 0) {
379  return 0.0f;
380  }
381 
382  result = _channel->getPosition( &current_time , FMOD_TIMEUNIT_MS );
383  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
384  return 0.0f;
385  }
386  fmod_audio_errcheck("_channel->getPosition()", result);
387 
388  return ((double)current_time) / 1000.0;
389 }
390 
391 ////////////////////////////////////////////////////////////////////
392 // Function: FmodAudioSound::set_volume(PN_stdfloat vol)
393 // Access: public
394 // Description: 0.0 to 1.0 scale of volume converted to Fmod's
395 // internal 0.0 to 255.0 scale.
396 ////////////////////////////////////////////////////////////////////
397 void FmodAudioSound::
398 set_volume(PN_stdfloat vol) {
399  ReMutexHolder holder(FmodAudioManager::_lock);
400  _volume = vol;
401  set_volume_on_channel();
402 }
403 
404 ////////////////////////////////////////////////////////////////////
405 // Function: FmodAudioSound::get_volume
406 // Access: public
407 // Description: Gets the current volume of a sound. 1 is Max. O is Min.
408 ////////////////////////////////////////////////////////////////////
409 PN_stdfloat FmodAudioSound::
410 get_volume() const {
411  return _volume;
412 }
413 
414 ////////////////////////////////////////////////////////////////////
415 // Function: FmodAudioSound::start_playing
416 // Access: Private
417 // Description: Starts the sound playing at _start_time.
418 ////////////////////////////////////////////////////////////////////
419 void FmodAudioSound::
420 start_playing() {
421  ReMutexHolder holder(FmodAudioManager::_lock);
422  FMOD_RESULT result;
423 
424  if (!_active) {
425  _paused = true;
426  return;
427  }
428 
429  int startTime = (int)(_start_time * 1000);
430 
431  if (_channel != 0) {
432  // try backing up current sound.
433  result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
434  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
435  _channel = 0;
436 
437  } else {
438  fmod_audio_errcheck("_channel->setPosition()", result);
439 
440  bool playing;
441  result = _channel->isPlaying(&playing);
442  fmod_audio_errcheck("_channel->isPlaying()", result);
443  if (result != FMOD_OK || !playing) {
444  _channel = 0;
445  }
446  }
447  }
448 
449  if (_channel == 0) {
450  result = _manager->_system->playSound(FMOD_CHANNEL_FREE, _sound, true, &_channel);
451  fmod_audio_errcheck("_system->playSound()", result);
452  result = _channel->setChannelGroup(_manager->_channelgroup);
453  fmod_audio_errcheck("_channel->setChannelGroup()", result);
454  result = _channel->setUserData(this);
455  fmod_audio_errcheck("_channel->setUserData()", result);
456  result = _channel->setCallback(sound_end_callback);
457  fmod_audio_errcheck("_channel->setCallback()", result);
458  result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
459  fmod_audio_errcheck("_channel->setPosition()", result);
460 
461  set_volume_on_channel();
462  set_play_rate_on_channel();
463  set_speaker_mix_or_balance_on_channel();
464  // add_dsp_on_channel();
465  set_3d_attributes_on_channel();
466 
467  result = _channel->setPaused(false);
468  fmod_audio_errcheck("_channel->setPaused()", result);
469 
470  _self_ref = this;
471  }
472 }
473 
474 ////////////////////////////////////////////////////////////////////
475 // Function: FmodAudioSound::set_volume_on_channel()
476 // Access: Private
477 // Description: Set the volume on a prepared Sound channel.
478 ////////////////////////////////////////////////////////////////////
479 void FmodAudioSound::
480 set_volume_on_channel() {
481  ReMutexHolder holder(FmodAudioManager::_lock);
482  FMOD_RESULT result;
483 
484  if (_channel != 0) {
485  result = _channel->setVolume( _volume );
486  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
487  _channel = 0;
488  } else {
489  fmod_audio_errcheck("_channel->setVolume()", result);
490  }
491  }
492 }
493 
494 ////////////////////////////////////////////////////////////////////
495 // Function: FmodAudioSound::set_balance(PN_stdfloat bal)
496 // Access: public
497 // Description: -1.0 to 1.0 scale
498 ////////////////////////////////////////////////////////////////////
499 void FmodAudioSound::
500 set_balance(PN_stdfloat bal) {
501  ReMutexHolder holder(FmodAudioManager::_lock);
502  _balance = bal;
503  set_speaker_mix_or_balance_on_channel();
504 }
505 
506 ////////////////////////////////////////////////////////////////////
507 // Function: FmodAudioSound::get_balance
508 // Access: public
509 // Description: -1.0 to 1.0 scale
510 // -1 should be all the way left.
511 // 1 is all the way to the right.
512 ////////////////////////////////////////////////////////////////////
513 PN_stdfloat FmodAudioSound::
514 get_balance() const {
515  return _balance;
516 }
517 
518 ////////////////////////////////////////////////////////////////////
519 // Function: FmodAudioSound::set_play_rate(PN_stdfloat rate)
520 // Access: public
521 // Description: Sets the speed at which a sound plays back.
522 // The rate is a multiple of the sound, normal playback speed.
523 // IE 2 would play back 2 times fast, 3 would play 3 times, and so on.
524 // This can also be set to a negative number so a sound plays backwards.
525 // But rememeber if the sound is not playing, you must set the
526 // sound's time to its end to hear a song play backwards.
527 ////////////////////////////////////////////////////////////////////
528 void FmodAudioSound::
529 set_play_rate(PN_stdfloat rate) {
530  ReMutexHolder holder(FmodAudioManager::_lock);
531  _playrate = rate;
532  set_play_rate_on_channel();
533 }
534 
535 ////////////////////////////////////////////////////////////////////
536 // Function: FmodAudioSound::get_play_rate
537 // Access: public
538 // Description:
539 ////////////////////////////////////////////////////////////////////
540 PN_stdfloat FmodAudioSound::
541 get_play_rate() const {
542  return _playrate;
543 }
544 
545 ////////////////////////////////////////////////////////////////////
546 // Function: FmodAudioSound::set_play_rate_on_channel()
547 // Access: public
548 // Description: Set the play rate on a prepared Sound channel.
549 ////////////////////////////////////////////////////////////////////
550 void FmodAudioSound::
551 set_play_rate_on_channel() {
552  ReMutexHolder holder(FmodAudioManager::_lock);
553  FMOD_RESULT result;
554  PN_stdfloat frequency = _sampleFrequency * _playrate;
555 
556  if (_channel != 0) {
557  result = _channel->setFrequency( frequency );
558  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
559  _channel = 0;
560  } else {
561  fmod_audio_errcheck("_channel->setFrequency()", result);
562  }
563  }
564 }
565 
566 ////////////////////////////////////////////////////////////////////
567 // Function: FmodAudioSound::get_name
568 // Access: public
569 // Description: Get name of sound file
570 ////////////////////////////////////////////////////////////////////
571 const string& FmodAudioSound::
572 get_name() const {
573  return _file_name;
574 }
575 
576 ////////////////////////////////////////////////////////////////////
577 // Function: FmodAudioSound::length
578 // Access: public
579 // Description: Get length
580 // FMOD returns the time in MS so we have to convert to seconds.
581 ////////////////////////////////////////////////////////////////////
582 PN_stdfloat FmodAudioSound::
583 length() const {
584  ReMutexHolder holder(FmodAudioManager::_lock);
585  FMOD_RESULT result;
586  unsigned int length;
587 
588  result = _sound->getLength( &length, FMOD_TIMEUNIT_MS );
589  fmod_audio_errcheck("_sound->getLength()", result);
590 
591  return ((double)length) / 1000.0;
592 }
593 
594 ////////////////////////////////////////////////////////////////////
595 // Function: FmodAudioSound::set_3d_attributes
596 // Access: public
597 // Description: Set position and velocity of this sound
598 // NOW LISTEN UP!!! THIS IS IMPORTANT!
599 // Both Panda3D and FMOD use a left handed coordinate system.
600 // But there is a major difference!
601 // In Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up.
602 // In FMOD the Y-Axis is going up and the Z-Axis is going into the screen.
603 // The solution is simple, we just flip the Y and Z axis, as we move coordinates
604 // from Panda to FMOD and back.
605 // What does did mean to average Panda user? Nothing, they shouldn't notice anyway.
606 // But if you decide to do any 3D audio work in here you have to keep it in mind.
607 // I told you, so you can't say I didn't.
608 ////////////////////////////////////////////////////////////////////
609 void FmodAudioSound::
610 set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) {
611  ReMutexHolder holder(FmodAudioManager::_lock);
612  _location.x = px;
613  _location.y = pz;
614  _location.z = py;
615 
616  _velocity.x = vx;
617  _velocity.y = vz;
618  _velocity.z = vy;
619 
620  set_3d_attributes_on_channel();
621 }
622 
623 ////////////////////////////////////////////////////////////////////
624 // Function: FmodAudioSound::set_3d_attributes_on_channel
625 // Access: public
626 // Description:
627 ////////////////////////////////////////////////////////////////////
628 void FmodAudioSound::
629 set_3d_attributes_on_channel() {
630  ReMutexHolder holder(FmodAudioManager::_lock);
631  FMOD_RESULT result;
632  FMOD_MODE soundMode;
633 
634  result = _sound->getMode(&soundMode);
635  fmod_audio_errcheck("_sound->getMode()", result);
636 
637  if ((_channel != 0) && (soundMode & FMOD_3D)) {
638  result = _channel->set3DAttributes( &_location, &_velocity );
639  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
640  _channel = 0;
641  } else {
642  fmod_audio_errcheck("_channel->set3DAttributes()", result);
643  }
644  }
645 }
646 
647 ////////////////////////////////////////////////////////////////////
648 // Function: FmodAudioSound::get_3d_attributes
649 // Access: public
650 // Description: Get position and velocity of this sound
651 // Currently unimplemented. Get the attributes of the attached object.
652 ////////////////////////////////////////////////////////////////////
653 void FmodAudioSound::
654 get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) {
655  audio_error("get3dAttributes: Currently unimplemented. Get the attributes of the attached object.");
656 }
657 
658 ////////////////////////////////////////////////////////////////////
659 // Function: FmodAudioSound::set_3d_min_distance
660 // Access: public
661 // Description: Set the distance that this sound begins to fall off. Also
662 // affects the rate it falls off.
663 ////////////////////////////////////////////////////////////////////
664 void FmodAudioSound::
665 set_3d_min_distance(PN_stdfloat dist) {
666  ReMutexHolder holder(FmodAudioManager::_lock);
667  FMOD_RESULT result;
668 
669  _min_dist = dist;
670 
671  result = _sound->set3DMinMaxDistance( dist, _max_dist );
672  fmod_audio_errcheck("_sound->set3DMinMaxDistance()", result);
673 }
674 
675 ////////////////////////////////////////////////////////////////////
676 // Function: FmodAudioSound::get_3d_min_distance
677 // Access: public
678 // Description: Get the distance that this sound begins to fall off
679 ////////////////////////////////////////////////////////////////////
680 PN_stdfloat FmodAudioSound::
682  return _min_dist;
683 }
684 
685 ////////////////////////////////////////////////////////////////////
686 // Function: FmodAudioSound::set_3d_max_distance
687 // Access: public
688 // Description: Set the distance that this sound stops falling off
689 ////////////////////////////////////////////////////////////////////
690 void FmodAudioSound::
691 set_3d_max_distance(PN_stdfloat dist) {
692  ReMutexHolder holder(FmodAudioManager::_lock);
693  FMOD_RESULT result;
694 
695  _max_dist = dist;
696 
697  result = _sound->set3DMinMaxDistance( _min_dist, dist );
698  fmod_audio_errcheck("_sound->set3DMinMaxDistance()", result);
699 }
700 
701 ////////////////////////////////////////////////////////////////////
702 // Function: FmodAudioSound::get_3d_max_distance
703 // Access: public
704 // Description: Get the distance that this sound stops falling off
705 ////////////////////////////////////////////////////////////////////
706 PN_stdfloat FmodAudioSound::
708  return _max_dist;
709 }
710 
711 ////////////////////////////////////////////////////////////////////
712 // Function: FmodAudioSound::get_speaker_mix
713 // Access: Published
714 // Description: In Multichannel Speaker systems [like Surround].
715 //
716 // Speakers which don't exist in some systems will simply be ignored.
717 // But I haven't been able to test this yet, so I am jsut letting you know.
718 //
719 // BTW This will also work in Stereo speaker systems, but since
720 // PANDA/FMOD has a balance [pan] function what is the point?
721 ////////////////////////////////////////////////////////////////////
722 PN_stdfloat FmodAudioSound::
723 get_speaker_mix(AudioManager::SpeakerId speaker) {
724  ReMutexHolder holder(FmodAudioManager::_lock);
725  if (_channel == 0) {
726  return 0.0;
727  }
728 
729  FMOD_RESULT result;
730  float frontleft;
731  float frontright;
732  float center;
733  float sub;
734  float backleft;
735  float backright;
736  float sideleft;
737  float sideright;
738 
739  result = _channel->getSpeakerMix( &frontleft, &frontright, &center, &sub, &backleft, &backright, &sideleft, &sideright );
740  fmod_audio_errcheck("_channel->getSpeakerMix()", result);
741 
742  switch(speaker) {
743  case AudioManager::SPK_frontleft: return frontleft;
744  case AudioManager::SPK_frontright: return frontright;
745  case AudioManager::SPK_center: return center;
746  case AudioManager::SPK_sub: return sub;
747  case AudioManager::SPK_backleft: return backleft;
748  case AudioManager::SPK_backright: return backright;
749  case AudioManager::SPK_sideleft: return sideleft;
750  case AudioManager::SPK_sideright: return sideright;
751  default: return 0.0;
752  }
753 }
754 
755 ////////////////////////////////////////////////////////////////////
756 // Function: FmodAudioSound::set_speaker_mix
757 // Access: Published
758 // Description: This sets the speaker mix for Surround Sound sytems.
759 // It required 8 parameters which match up to the following:
760 //
761 // * 1 = Front Left
762 // * 2 = Front Right
763 // * 3 = Center
764 // * 4 = Subwoofer
765 // * 5 = Back Left
766 // * 6 = Back Right
767 // * 7 = Side Left
768 // * 8 = Side Right
769 //
770 ////////////////////////////////////////////////////////////////////
771 void FmodAudioSound::
772 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) {
773  ReMutexHolder holder(FmodAudioManager::_lock);
774  _mix[AudioManager::SPK_frontleft] = frontleft;
775  _mix[AudioManager::SPK_frontright] = frontright;
776  _mix[AudioManager::SPK_center] = center;
777  _mix[AudioManager::SPK_sub] = sub;
778  _mix[AudioManager::SPK_backleft] = backleft;
779  _mix[AudioManager::SPK_backright] = backright;
780  _mix[AudioManager::SPK_sideleft] = sideleft;
781  _mix[AudioManager::SPK_sideright] = sideright;
782 
783  set_speaker_mix_or_balance_on_channel();
784 }
785 
786 ////////////////////////////////////////////////////////////////////
787 // Function: FmodAudioSound::set_speaker_mix_or_balance_on_channel
788 // Access: Private
789 // Description: This is simply a safety catch.
790 // If you are using a Stero speaker setup Panda will only pay attention
791 // to 'set_balance()' command when setting speaker balances.
792 // Other wise it will use 'set_speaker_mix'.
793 // I put this in, because other wise you end up with a sitation,
794 // where 'set_speaker_mix()' or 'set_balace()' will override any
795 // previous speaker balance setups. It all depends on which was called last.
796 ////////////////////////////////////////////////////////////////////
797 void FmodAudioSound::
798 set_speaker_mix_or_balance_on_channel() {
799  ReMutexHolder holder(FmodAudioManager::_lock);
800  FMOD_RESULT result;
801  FMOD_MODE soundMode;
802 
803  result = _sound->getMode(&soundMode);
804  fmod_audio_errcheck("_sound->getMode()", result);
805 
806  if ((_channel != 0) && (( soundMode & FMOD_3D ) == 0)) {
807  if ( _speakermode == FMOD_SPEAKERMODE_STEREO ) {
808  result = _channel->setPan( _balance );
809  } else {
810  result = _channel->setSpeakerMix( _mix[AudioManager::SPK_frontleft],
811  _mix[AudioManager::SPK_frontright],
812  _mix[AudioManager::SPK_center],
813  _mix[AudioManager::SPK_sub],
814  _mix[AudioManager::SPK_backleft],
815  _mix[AudioManager::SPK_backright],
816  _mix[AudioManager::SPK_sideleft],
817  _mix[AudioManager::SPK_sideright]
818  );
819  }
820  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
821  _channel = 0;
822  } else {
823  fmod_audio_errcheck("_channel->setSpeakerMix()/setPan()", result);
824  }
825  }
826 }
827 
828 ////////////////////////////////////////////////////////////////////
829 // Function: FmodAudioSound::get_priority
830 // Access: Published
831 // Description: Sets the priority of a sound.
832 // This is what FMOD uses to determine is a sound will
833 // play if all the other real channels have been used up.
834 ////////////////////////////////////////////////////////////////////
835 int FmodAudioSound::
836 get_priority() {
837  audio_debug("FmodAudioSound::get_priority()");
838  return _priority;
839 }
840 
841 ////////////////////////////////////////////////////////////////////
842 // Function: FmodAudioSound::set_priority(int priority)
843 // Access: Published
844 // Description: Sets the Sound Priority [Whether is will be played
845 // over other sound when real audio channels become short.
846 ////////////////////////////////////////////////////////////////////
847 void FmodAudioSound::
848 set_priority(int priority) {
849  ReMutexHolder holder(FmodAudioManager::_lock);
850 
851  audio_debug("FmodAudioSound::set_priority()");
852 
853  FMOD_RESULT result;
854 
855  _priority = priority;
856 
857  result = _sound->setDefaults( _sampleFrequency, _volume , _balance, _priority);
858  fmod_audio_errcheck("_sound->setDefaults()", result);
859 }
860 
861 ////////////////////////////////////////////////////////////////////
862 // Function: FmodAudioSound::status
863 // Access: public
864 // Description: Get status of the sound.
865 ////////////////////////////////////////////////////////////////////
866 AudioSound::SoundStatus FmodAudioSound::
867 status() const {
868  ReMutexHolder holder(FmodAudioManager::_lock);
869  FMOD_RESULT result;
870  bool playingState;
871 
872  if ( _channel == 0 ) {
873  return READY;
874  }
875 
876  result = _channel->isPlaying( &playingState );
877  if ((result == FMOD_OK) && (playingState == true)) {
878  return PLAYING;
879  } else {
880  return READY;
881  }
882 }
883 
884 ////////////////////////////////////////////////////////////////////
885 // Function: FmodAudioSound::set_active
886 // Access: public
887 // Description: Sets whether the sound is marked "active". By
888 // default, the active flag true for all sounds. If the
889 // active flag is set to false for any particular sound,
890 // the sound will not be heard.
891 ////////////////////////////////////////////////////////////////////
892 void FmodAudioSound::
893 set_active(bool active) {
894  ReMutexHolder holder(FmodAudioManager::_lock);
895  if (_active != active) {
896  _active = active;
897  if (_active) {
898  // ...activate the sound.
899  if (_paused && get_loop_count()==0) {
900  // ...this sound was looping when it was paused.
901  _paused = false;
902  play();
903  }
904 
905  } else {
906  // ...deactivate the sound.
907  if (status() == PLAYING) {
908  if (get_loop_count() == 0) {
909  // ...we're pausing a looping sound.
910  _paused = true;
911  _start_time = get_time();
912  }
913  stop();
914  }
915  }
916  }
917 }
918 
919 
920 ////////////////////////////////////////////////////////////////////
921 // Function: FmodAudioSound::get_active
922 // Access: public
923 // Description: Returns whether the sound has been marked "active".
924 ////////////////////////////////////////////////////////////////////
925 bool FmodAudioSound::
926 get_active() const {
927  return _active;
928 }
929 
930 ////////////////////////////////////////////////////////////////////
931 // Function: FmodAudioSound::finished
932 // Access: public
933 // Description: Not implemented.
934 ////////////////////////////////////////////////////////////////////
935 void FmodAudioSound::
937  audio_error("finished: not implemented under FMOD-EX");
938 }
939 
940 ////////////////////////////////////////////////////////////////////
941 // Function: FmodAudioSound::set_finished_event
942 // Access: public
943 // Description: NOT USED ANYMORE!!!
944 // Assign a string for the finished event to be referenced
945 // by in python by an accept method
946 //
947 ////////////////////////////////////////////////////////////////////
948 void FmodAudioSound::
949 set_finished_event(const string& event) {
950  audio_error("set_finished_event: not implemented under FMOD-EX");
951 }
952 
953 ////////////////////////////////////////////////////////////////////
954 // Function: FmodAudioSound::get_finished_event
955 // Access: public
956 // Description:NOT USED ANYMORE!!!
957 // Return the string the finished event is referenced by
958 //
959 //
960 ////////////////////////////////////////////////////////////////////
961 const string& FmodAudioSound::
963  audio_error("get_finished_event: not implemented under FMOD-EX");
964  return _finished_event;
965 }
966 
967 ////////////////////////////////////////////////////////////////////
968 // Function: FmodAudioSound::sound_end_callback
969 // Access: Private, Static
970 // Description: When fmod finishes playing a sound, decrements the
971 // reference count of the associated FmodAudioSound.
972 ////////////////////////////////////////////////////////////////////
973 FMOD_RESULT F_CALLBACK FmodAudioSound::
974 sound_end_callback(FMOD_CHANNEL * channel,
975  FMOD_CHANNEL_CALLBACKTYPE type,
976  void *commanddata1,
977  void *commanddata2) {
978  // Fortunately, this callback is made synchronously rather than
979  // asynchronously (it is triggered during System::update()), so we
980  // don't have to worry about thread-related issues here.
981  if (type == FMOD_CHANNEL_CALLBACKTYPE_END) {
982  FMOD::Channel *fc = (FMOD::Channel *)channel;
983  void *userdata = NULL;
984  FMOD_RESULT result = fc->getUserData(&userdata);
985  fmod_audio_errcheck("channel->getUserData()", result);
986  FmodAudioSound *fsound = (FmodAudioSound*)userdata;
987  fsound->_self_ref = fsound;
988  }
989  return FMOD_OK;
990 }
991 
992 ////////////////////////////////////////////////////////////////////
993 // Function: FmodAudioSound::open_callback
994 // Access: Private, Static
995 // Description: A hook into Panda's virtual file system.
996 ////////////////////////////////////////////////////////////////////
997 FMOD_RESULT F_CALLBACK FmodAudioSound::
998 open_callback(const char *name, int, unsigned int *file_size,
999  void **handle, void **user_data) {
1000  // We actually pass in the VirtualFile pointer as the "name".
1001  VirtualFile *file = (VirtualFile *)name;
1002  if (file == (VirtualFile *)NULL) {
1003  return FMOD_ERR_FILE_NOTFOUND;
1004  }
1005  if (fmodAudio_cat.is_spam()) {
1006  fmodAudio_cat.spam()
1007  << "open_callback(" << *file << ")\n";
1008  }
1009 
1010  istream *str = file->open_read_file(true);
1011 
1012  (*file_size) = file->get_file_size(str);
1013  (*handle) = (void *)str;
1014  (*user_data) = (void *)file;
1015 
1016  // Explicitly ref the VirtualFile since we're storing it in a void
1017  // pointer instead of a PT(VirtualFile).
1018  file->ref();
1019 
1020  return FMOD_OK;
1021 }
1022 
1023 ////////////////////////////////////////////////////////////////////
1024 // Function: FmodAudioSound::close_callback
1025 // Access: Private, Static
1026 // Description: A hook into Panda's virtual file system.
1027 ////////////////////////////////////////////////////////////////////
1028 FMOD_RESULT F_CALLBACK FmodAudioSound::
1029 close_callback(void *handle, void *user_data) {
1030  VirtualFile *file = (VirtualFile *)user_data;
1031  if (fmodAudio_cat.is_spam()) {
1032  fmodAudio_cat.spam()
1033  << "close_callback(" << *file << ")\n";
1034  }
1035 
1037 
1038  istream *str = (istream *)handle;
1039  vfs->close_read_file(str);
1040 
1041  // Explicitly unref the VirtualFile pointer.
1042  unref_delete(file);
1043 
1044  return FMOD_OK;
1045 }
1046 
1047 ////////////////////////////////////////////////////////////////////
1048 // Function: FmodAudioSound::read_callback
1049 // Access: Private, Static
1050 // Description: A hook into Panda's virtual file system.
1051 ////////////////////////////////////////////////////////////////////
1052 FMOD_RESULT F_CALLBACK FmodAudioSound::
1053 read_callback(void *handle, void *buffer, unsigned int size_bytes,
1054  unsigned int *bytes_read, void *user_data) {
1055  VirtualFile *file = (VirtualFile *)user_data;
1056  if (fmodAudio_cat.is_spam()) {
1057  fmodAudio_cat.spam()
1058  << "read_callback(" << *file << ", " << size_bytes << ")\n";
1059  }
1060 
1061  istream *str = (istream *)handle;
1062  str->read((char *)buffer, size_bytes);
1063  (*bytes_read) = str->gcount();
1064 
1065  // We can't yield here, since this callback is made within a
1066  // sub-thread--an OS-level sub-thread spawned by FMod, not a Panda
1067  // thread. But we will only execute this code in the true-threads
1068  // case anyway.
1069  //thread_consider_yield();
1070 
1071  if (str->eof()) {
1072  if ((*bytes_read) == 0) {
1073  return FMOD_ERR_FILE_EOF;
1074  } else {
1075  // Report the EOF next time.
1076  return FMOD_OK;
1077  }
1078  } if (str->fail()) {
1079  return FMOD_ERR_FILE_BAD;
1080  } else {
1081  return FMOD_OK;
1082  }
1083 }
1084 
1085 ////////////////////////////////////////////////////////////////////
1086 // Function: FmodAudioSound::seek_callback
1087 // Access: Private, Static
1088 // Description: A hook into Panda's virtual file system.
1089 ////////////////////////////////////////////////////////////////////
1090 FMOD_RESULT F_CALLBACK FmodAudioSound::
1091 seek_callback(void *handle, unsigned int pos, void *user_data) {
1092  VirtualFile *file = (VirtualFile *)user_data;
1093  if (fmodAudio_cat.is_spam()) {
1094  fmodAudio_cat.spam()
1095  << "seek_callback(" << *file << ", " << pos << ")\n";
1096  }
1097 
1098  istream *str = (istream *)handle;
1099  str->clear();
1100  str->seekg(pos);
1101 
1102  if (str->fail() && !str->eof()) {
1103  return FMOD_ERR_FILE_COULDNOTSEEK;
1104  } else {
1105  return FMOD_OK;
1106  }
1107 }
AudioSound::SoundStatus status() const
Get status of the sound.
virtual void 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)
This sets the speaker mix for Surround Sound sytems.
PN_stdfloat get_balance() const
-1.0 to 1.0 scale -1 should be all the way left.
void play()
Plays a sound.
PN_stdfloat get_3d_min_distance() const
Get the distance that this sound begins to fall off.
void finished()
Not implemented.
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
void set_3d_max_distance(PN_stdfloat dist)
Set the distance that this sound stops falling off.
FmodAudioSound(AudioManager *manager, Filename fn, bool positional)
Constructor All sound will DEFAULT load as a 2D sound unless otherwise specified. ...
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:494
void set_volume(PN_stdfloat volume=1.0)
0.0 to 1.0 scale of volume converted to Fmod&#39;s internal 0.0 to 255.0 scale.
PN_stdfloat length() const
Get length FMOD returns the time in MS so we have to convert to seconds.
const string & get_name() const
Get name of sound file.
bool get_active() const
Returns whether the sound has been marked "active".
void set_balance(PN_stdfloat balance_right=0.0)
-1.0 to 1.0 scale
void set_loop_count(unsigned long loop_count=1)
Panda uses 0 to mean loop forever.
void set_time(PN_stdfloat start_time=0.0)
Sets the time at which the next play() operation will begin.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:37
string get_extension() const
Returns the file extension.
Definition: filename.I:477
PN_stdfloat get_3d_max_distance() const
Get the distance that this sound stops falling off.
void stop()
Stop a sound.
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
virtual streamsize get_file_size(istream *stream) const
Returns the current size on disk (or wherever it is) of the already-open file.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
void set_loop(bool loop=true)
Turns looping on and off.
void set_3d_min_distance(PN_stdfloat dist)
Set the distance that this sound begins to fall off.
void set_play_rate(PN_stdfloat play_rate=1.0f)
Sets the speed at which a sound plays back.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
unsigned long get_loop_count() const
Return how many times a sound will loop.
virtual PN_stdfloat get_speaker_mix(AudioManager::SpeakerId speaker)
In Multichannel Speaker systems [like Surround].
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
Similar to MutexHolder, but for a reentrant mutex.
Definition: reMutexHolder.h:27
void set_active(bool active=true)
Sets whether the sound is marked "active".
void ref() const
Explicitly increments the reference count.
const Filename & get_filename() const
A shortcut to the filename.
Definition: subfileInfo.I:106
bool get_loop() const
Returns whether looping is on or off.
PN_stdfloat get_time() const
Gets the play position within the sound.
virtual istream * open_read_file(bool auto_unwrap) const
Opens the file for reading.
const string & get_finished_event() const
NOT USED ANYMORE!!! Return the string the finished event is referenced by.
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:29
void set_finished_event(const string &event)
NOT USED ANYMORE!!! Assign a string for the finished event to be referenced by in python by an accept...
streampos get_start() const
Returns the offset within the file at which this file data begins.
Definition: subfileInfo.I:121
void set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz)
Set position and velocity of this sound NOW LISTEN UP!!! THIS IS IMPORTANT! Both Panda3D and FMOD use...
void get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz)
Get position and velocity of this sound Currently unimplemented.
~FmodAudioSound()
DESTRUCTOR!!!
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
streamsize get_size() const
Returns the number of consecutive bytes, beginning at get_start(), that correspond to this file data...
Definition: subfileInfo.I:132
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
Definition: filename.cxx:1196
PN_stdfloat get_volume() const
Gets the current volume of a sound.