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