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 }
263 
264 
265 /**
266  * Turns looping on and off
267  */
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  * Returns whether looping is on or off
279  */
281 get_loop() const {
282  if (get_loop_count() == 1) {
283  return false;
284  } else {
285  return true;
286  }
287 }
288 
289 /**
290  *
291  * Panda uses 0 to mean loop forever. Fmod uses negative numbers to mean loop
292  * forever. (0 means don't loop, 1 means play twice, etc. We must convert!
293  */
295 set_loop_count(unsigned long loop_count) {
296  ReMutexHolder holder(FmodAudioManager::_lock);
297  audio_debug("FmodAudioSound::set_loop_count() Setting the sound's loop count to: " << loop_count);
298 
299  // LOCALS
300  FMOD_RESULT result;
301 
302  if (loop_count == 0) {
303  result = _sound->setLoopCount( -1 );
304  fmod_audio_errcheck("_sound->setLoopCount()", result);
305  result =_sound->setMode(FMOD_LOOP_NORMAL);
306  fmod_audio_errcheck("_sound->setMode()", result);
307  } else if (loop_count == 1) {
308  result = _sound->setLoopCount( 1 );
309  fmod_audio_errcheck("_sound->setLoopCount()", result);
310  result =_sound->setMode(FMOD_LOOP_OFF);
311  fmod_audio_errcheck("_sound->setMode()", result);
312  } else {
313  result = _sound->setLoopCount( loop_count );
314  fmod_audio_errcheck("_sound->setLoopCount()", result);
315  result =_sound->setMode(FMOD_LOOP_NORMAL);
316  fmod_audio_errcheck("_sound->setMode()", result);
317  }
318 
319  audio_debug("FmodAudioSound::set_loop_count() Sound's loop count should be set to: " << loop_count);
320 }
321 
322 /**
323  * Return how many times a sound will loop.
324  */
325 unsigned long FmodAudioSound::
326 get_loop_count() const {
327  ReMutexHolder holder(FmodAudioManager::_lock);
328  FMOD_RESULT result;
329  int loop_count;
330 
331  result = _sound->getLoopCount( &loop_count );
332  fmod_audio_errcheck("_sound->getLoopCount()", result);
333 
334  if (loop_count <= 0) {
335  return 0;
336  } else {
337  return (unsigned long)loop_count;
338  }
339 }
340 
341 /**
342  * Sets the time at which the next play() operation will begin. If we are
343  * already playing, skips to that time immediatey.
344  */
346 set_time(PN_stdfloat start_time) {
347  ReMutexHolder holder(FmodAudioManager::_lock);
348  _start_time = start_time;
349 
350  if (status() == PLAYING) {
351  // Already playing; skip to the indicated time.
352  start_playing();
353  }
354 }
355 
356 /**
357  * Gets the play position within the sound
358  */
359 PN_stdfloat FmodAudioSound::
360 get_time() const {
361  ReMutexHolder holder(FmodAudioManager::_lock);
362  FMOD_RESULT result;
363  unsigned int current_time;
364 
365  if (_channel == 0) {
366  return 0.0f;
367  }
368 
369  result = _channel->getPosition( &current_time , FMOD_TIMEUNIT_MS );
370  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
371  return 0.0f;
372  }
373  fmod_audio_errcheck("_channel->getPosition()", result);
374 
375  return ((double)current_time) / 1000.0;
376 }
377 
378 /**
379  * 0.0 to 1.0 scale of volume converted to Fmod's internal 0.0 to 255.0 scale.
380  */
382 set_volume(PN_stdfloat vol) {
383  ReMutexHolder holder(FmodAudioManager::_lock);
384  _volume = vol;
385  set_volume_on_channel();
386 }
387 
388 /**
389  * Gets the current volume of a sound. 1 is Max. O is Min.
390  */
391 PN_stdfloat FmodAudioSound::
392 get_volume() const {
393  return _volume;
394 }
395 
396 /**
397  * Starts the sound playing at _start_time.
398  */
399 void FmodAudioSound::
400 start_playing() {
401  ReMutexHolder holder(FmodAudioManager::_lock);
402  FMOD_RESULT result;
403 
404  if (!_active) {
405  _paused = true;
406  return;
407  }
408 
409  int startTime = (int)(_start_time * 1000);
410 
411  if (_channel != 0) {
412  // try backing up current sound.
413  result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
414  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
415  _channel = 0;
416 
417  } else {
418  fmod_audio_errcheck("_channel->setPosition()", result);
419 
420  bool playing;
421  result = _channel->isPlaying(&playing);
422  fmod_audio_errcheck("_channel->isPlaying()", result);
423  if (result != FMOD_OK || !playing) {
424  _channel = 0;
425  }
426  }
427  }
428 
429  if (_channel == 0) {
430  result = _manager->_system->playSound(FMOD_CHANNEL_FREE, _sound, true, &_channel);
431  fmod_audio_errcheck("_system->playSound()", result);
432  result = _channel->setChannelGroup(_manager->_channelgroup);
433  fmod_audio_errcheck("_channel->setChannelGroup()", result);
434  result = _channel->setUserData(this);
435  fmod_audio_errcheck("_channel->setUserData()", result);
436  result = _channel->setCallback(sound_end_callback);
437  fmod_audio_errcheck("_channel->setCallback()", result);
438  result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
439  fmod_audio_errcheck("_channel->setPosition()", result);
440 
441  set_volume_on_channel();
442  set_play_rate_on_channel();
443  set_speaker_mix_or_balance_on_channel();
444  // add_dsp_on_channel();
445  set_3d_attributes_on_channel();
446 
447  result = _channel->setPaused(false);
448  fmod_audio_errcheck("_channel->setPaused()", result);
449 
450  _self_ref = this;
451  }
452 }
453 
454 /**
455  * Set the volume on a prepared Sound channel.
456  */
457 void FmodAudioSound::
458 set_volume_on_channel() {
459  ReMutexHolder holder(FmodAudioManager::_lock);
460  FMOD_RESULT result;
461 
462  if (_channel != 0) {
463  result = _channel->setVolume( _volume );
464  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
465  _channel = 0;
466  } else {
467  fmod_audio_errcheck("_channel->setVolume()", result);
468  }
469  }
470 }
471 
472 /**
473  * -1.0 to 1.0 scale
474  */
476 set_balance(PN_stdfloat bal) {
477  ReMutexHolder holder(FmodAudioManager::_lock);
478  _balance = bal;
479  set_speaker_mix_or_balance_on_channel();
480 }
481 
482 /**
483  * -1.0 to 1.0 scale -1 should be all the way left. 1 is all the way to the
484  * right.
485  */
486 PN_stdfloat FmodAudioSound::
487 get_balance() const {
488  return _balance;
489 }
490 
491 /**
492  * Sets the speed at which a sound plays back. The rate is a multiple of the
493  * sound, normal playback speed. IE 2 would play back 2 times fast, 3 would
494  * play 3 times, and so on. This can also be set to a negative number so a
495  * sound plays backwards. But rememeber if the sound is not playing, you must
496  * set the sound's time to its end to hear a song play backwards.
497  */
499 set_play_rate(PN_stdfloat rate) {
500  ReMutexHolder holder(FmodAudioManager::_lock);
501  _playrate = rate;
502  set_play_rate_on_channel();
503 }
504 
505 /**
506  *
507  */
508 PN_stdfloat FmodAudioSound::
509 get_play_rate() const {
510  return _playrate;
511 }
512 
513 /**
514  * Set the play rate on a prepared Sound channel.
515  */
516 void FmodAudioSound::
517 set_play_rate_on_channel() {
518  ReMutexHolder holder(FmodAudioManager::_lock);
519  FMOD_RESULT result;
520  PN_stdfloat frequency = _sampleFrequency * _playrate;
521 
522  if (_channel != 0) {
523  result = _channel->setFrequency( frequency );
524  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
525  _channel = 0;
526  } else {
527  fmod_audio_errcheck("_channel->setFrequency()", result);
528  }
529  }
530 }
531 
532 /**
533  * Get name of sound file
534  */
535 const string& FmodAudioSound::
536 get_name() const {
537  return _file_name;
538 }
539 
540 /**
541  * Get length FMOD returns the time in MS so we have to convert to seconds.
542  */
543 PN_stdfloat FmodAudioSound::
544 length() const {
545  ReMutexHolder holder(FmodAudioManager::_lock);
546  FMOD_RESULT result;
547  unsigned int length;
548 
549  result = _sound->getLength( &length, FMOD_TIMEUNIT_MS );
550  fmod_audio_errcheck("_sound->getLength()", result);
551 
552  return ((double)length) / 1000.0;
553 }
554 
555 /**
556  * Set position and velocity of this sound NOW LISTEN UP!!! THIS IS IMPORTANT!
557  * Both Panda3D and FMOD use a left handed coordinate system. But there is a
558  * major difference! In Panda3D the Y-Axis is going into the Screen and the
559  * Z-Axis is going up. In FMOD the Y-Axis is going up and the Z-Axis is going
560  * into the screen. The solution is simple, we just flip the Y and Z axis, as
561  * we move coordinates from Panda to FMOD and back. What does did mean to
562  * average Panda user? Nothing, they shouldn't notice anyway. But if you
563  * decide to do any 3D audio work in here you have to keep it in mind. I told
564  * you, so you can't say I didn't.
565  */
567 set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) {
568  ReMutexHolder holder(FmodAudioManager::_lock);
569  _location.x = px;
570  _location.y = pz;
571  _location.z = py;
572 
573  _velocity.x = vx;
574  _velocity.y = vz;
575  _velocity.z = vy;
576 
577  set_3d_attributes_on_channel();
578 }
579 
580 /**
581  *
582  */
583 void FmodAudioSound::
584 set_3d_attributes_on_channel() {
585  ReMutexHolder holder(FmodAudioManager::_lock);
586  FMOD_RESULT result;
587  FMOD_MODE soundMode;
588 
589  result = _sound->getMode(&soundMode);
590  fmod_audio_errcheck("_sound->getMode()", result);
591 
592  if ((_channel != 0) && (soundMode & FMOD_3D)) {
593  result = _channel->set3DAttributes( &_location, &_velocity );
594  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
595  _channel = 0;
596  } else {
597  fmod_audio_errcheck("_channel->set3DAttributes()", result);
598  }
599  }
600 }
601 
602 /**
603  * Get position and velocity of this sound Currently unimplemented. Get the
604  * attributes of the attached object.
605  */
607 get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) {
608  audio_error("get3dAttributes: Currently unimplemented. Get the attributes of the attached object.");
609 }
610 
611 /**
612  * Set the distance that this sound begins to fall off. Also affects the rate
613  * it falls off.
614  */
616 set_3d_min_distance(PN_stdfloat dist) {
617  ReMutexHolder holder(FmodAudioManager::_lock);
618  FMOD_RESULT result;
619 
620  _min_dist = dist;
621 
622  result = _sound->set3DMinMaxDistance( dist, _max_dist );
623  fmod_audio_errcheck("_sound->set3DMinMaxDistance()", result);
624 }
625 
626 /**
627  * Get the distance that this sound begins to fall off
628  */
629 PN_stdfloat FmodAudioSound::
630 get_3d_min_distance() const {
631  return _min_dist;
632 }
633 
634 /**
635  * Set the distance that this sound stops falling off
636  */
638 set_3d_max_distance(PN_stdfloat dist) {
639  ReMutexHolder holder(FmodAudioManager::_lock);
640  FMOD_RESULT result;
641 
642  _max_dist = dist;
643 
644  result = _sound->set3DMinMaxDistance( _min_dist, dist );
645  fmod_audio_errcheck("_sound->set3DMinMaxDistance()", result);
646 }
647 
648 /**
649  * Get the distance that this sound stops falling off
650  */
651 PN_stdfloat FmodAudioSound::
652 get_3d_max_distance() const {
653  return _max_dist;
654 }
655 
656 /**
657  * In Multichannel Speaker systems [like Surround].
658  *
659  * Speakers which don't exist in some systems will simply be ignored. But I
660  * haven't been able to test this yet, so I am jsut letting you know.
661  *
662  * BTW This will also work in Stereo speaker systems, but since PANDA/FMOD has
663  * a balance [pan] function what is the point?
664  */
665 PN_stdfloat FmodAudioSound::
666 get_speaker_mix(int speaker) {
667  ReMutexHolder holder(FmodAudioManager::_lock);
668  if (_channel == 0) {
669  return 0.0;
670  }
671 
672  FMOD_RESULT result;
673  float frontleft;
674  float frontright;
675  float center;
676  float sub;
677  float backleft;
678  float backright;
679  float sideleft;
680  float sideright;
681 
682  result = _channel->getSpeakerMix( &frontleft, &frontright, &center, &sub, &backleft, &backright, &sideleft, &sideright );
683  fmod_audio_errcheck("_channel->getSpeakerMix()", result);
684 
685  switch(speaker) {
686  case AudioManager::SPK_frontleft: return frontleft;
687  case AudioManager::SPK_frontright: return frontright;
688  case AudioManager::SPK_center: return center;
689  case AudioManager::SPK_sub: return sub;
690  case AudioManager::SPK_backleft: return backleft;
691  case AudioManager::SPK_backright: return backright;
692  case AudioManager::SPK_sideleft: return sideleft;
693  case AudioManager::SPK_sideright: return sideright;
694  default: return 0.0;
695  }
696 }
697 
698 /**
699  * This sets the speaker mix for Surround Sound sytems. It required 8
700  * parameters which match up to the following:
701  *
702  * * 1 = Front Left * 2 = Front Right * 3 = Center * 4 = Subwoofer * 5 = Back
703  * Left * 6 = Back Right * 7 = Side Left * 8 = Side Right
704  *
705  */
707 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) {
708  ReMutexHolder holder(FmodAudioManager::_lock);
709  _mix[AudioManager::SPK_frontleft] = frontleft;
710  _mix[AudioManager::SPK_frontright] = frontright;
711  _mix[AudioManager::SPK_center] = center;
712  _mix[AudioManager::SPK_sub] = sub;
713  _mix[AudioManager::SPK_backleft] = backleft;
714  _mix[AudioManager::SPK_backright] = backright;
715  _mix[AudioManager::SPK_sideleft] = sideleft;
716  _mix[AudioManager::SPK_sideright] = sideright;
717 
718  set_speaker_mix_or_balance_on_channel();
719 }
720 
721 /**
722  * This is simply a safety catch. If you are using a Stero speaker setup
723  * Panda will only pay attention to 'set_balance()' command when setting
724  * speaker balances. Other wise it will use 'set_speaker_mix'. I put this in,
725  * because other wise you end up with a sitation, where 'set_speaker_mix()' or
726  * 'set_balace()' will override any previous speaker balance setups. It all
727  * depends on which was called last.
728  */
729 void FmodAudioSound::
730 set_speaker_mix_or_balance_on_channel() {
731  ReMutexHolder holder(FmodAudioManager::_lock);
732  FMOD_RESULT result;
733  FMOD_MODE soundMode;
734 
735  result = _sound->getMode(&soundMode);
736  fmod_audio_errcheck("_sound->getMode()", result);
737 
738  if ((_channel != 0) && (( soundMode & FMOD_3D ) == 0)) {
739  if ( _speakermode == FMOD_SPEAKERMODE_STEREO ) {
740  result = _channel->setPan( _balance );
741  } else {
742  result = _channel->setSpeakerMix( _mix[AudioManager::SPK_frontleft],
743  _mix[AudioManager::SPK_frontright],
744  _mix[AudioManager::SPK_center],
745  _mix[AudioManager::SPK_sub],
746  _mix[AudioManager::SPK_backleft],
747  _mix[AudioManager::SPK_backright],
748  _mix[AudioManager::SPK_sideleft],
749  _mix[AudioManager::SPK_sideright]
750  );
751  }
752  if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN) {
753  _channel = 0;
754  } else {
755  fmod_audio_errcheck("_channel->setSpeakerMix()/setPan()", result);
756  }
757  }
758 }
759 
760 /**
761  * Sets the priority of a sound. This is what FMOD uses to determine is a
762  * sound will play if all the other real channels have been used up.
763  */
764 int FmodAudioSound::
765 get_priority() {
766  audio_debug("FmodAudioSound::get_priority()");
767  return _priority;
768 }
769 
770 /**
771  * Sets the Sound Priority [Whether is will be played over other sound when
772  * real audio channels become short.
773  */
774 void FmodAudioSound::
775 set_priority(int priority) {
776  ReMutexHolder holder(FmodAudioManager::_lock);
777 
778  audio_debug("FmodAudioSound::set_priority()");
779 
780  FMOD_RESULT result;
781 
782  _priority = priority;
783 
784  result = _sound->setDefaults( _sampleFrequency, _volume , _balance, _priority);
785  fmod_audio_errcheck("_sound->setDefaults()", result);
786 }
787 
788 /**
789  * Get status of the sound.
790  */
791 AudioSound::SoundStatus FmodAudioSound::
792 status() const {
793  ReMutexHolder holder(FmodAudioManager::_lock);
794  FMOD_RESULT result;
795  bool playingState;
796 
797  if ( _channel == 0 ) {
798  return READY;
799  }
800 
801  result = _channel->isPlaying( &playingState );
802  if ((result == FMOD_OK) && (playingState == true)) {
803  return PLAYING;
804  } else {
805  return READY;
806  }
807 }
808 
809 /**
810  * Sets whether the sound is marked "active". By default, the active flag
811  * true for all sounds. If the active flag is set to false for any particular
812  * sound, the sound will not be heard.
813  */
815 set_active(bool active) {
816  ReMutexHolder holder(FmodAudioManager::_lock);
817  if (_active != active) {
818  _active = active;
819  if (_active) {
820  // ...activate the sound.
821  if (_paused && get_loop_count()==0) {
822  // ...this sound was looping when it was paused.
823  _paused = false;
824  play();
825  }
826 
827  } else {
828  // ...deactivate the sound.
829  if (status() == PLAYING) {
830  if (get_loop_count() == 0) {
831  // ...we're pausing a looping sound.
832  _paused = true;
833  _start_time = get_time();
834  }
835  stop();
836  }
837  }
838  }
839 }
840 
841 
842 /**
843  * Returns whether the sound has been marked "active".
844  */
846 get_active() const {
847  return _active;
848 }
849 
850 /**
851  * Not implemented.
852  */
854 finished() {
855  audio_error("finished: not implemented under FMOD-EX");
856 }
857 
858 /**
859  * NOT USED ANYMORE!!! Assign a string for the finished event to be referenced
860  * by in python by an accept method
861  *
862  */
864 set_finished_event(const string& event) {
865  audio_error("set_finished_event: not implemented under FMOD-EX");
866 }
867 
868 /**
869  * NOT USED ANYMORE!!! Return the string the finished event is referenced by
870  *
871 
872  *
873  */
874 const string& FmodAudioSound::
875 get_finished_event() const {
876  audio_error("get_finished_event: not implemented under FMOD-EX");
877  return _finished_event;
878 }
879 
880 /**
881  * When fmod finishes playing a sound, decrements the reference count of the
882  * associated FmodAudioSound.
883  */
884 FMOD_RESULT F_CALLBACK FmodAudioSound::
885 sound_end_callback(FMOD_CHANNEL * channel,
886  FMOD_CHANNEL_CALLBACKTYPE type,
887  void *commanddata1,
888  void *commanddata2) {
889  // Fortunately, this callback is made synchronously rather than
890  // asynchronously (it is triggered during System::update()), so we don't
891  // have to worry about thread-related issues here.
892  if (type == FMOD_CHANNEL_CALLBACKTYPE_END) {
893  FMOD::Channel *fc = (FMOD::Channel *)channel;
894  void *userdata = nullptr;
895  FMOD_RESULT result = fc->getUserData(&userdata);
896  fmod_audio_errcheck("channel->getUserData()", result);
897  FmodAudioSound *fsound = (FmodAudioSound*)userdata;
898  fsound->_self_ref = fsound;
899  }
900  return FMOD_OK;
901 }
902 
903 /**
904  * A hook into Panda's virtual file system.
905  */
906 FMOD_RESULT F_CALLBACK FmodAudioSound::
907 open_callback(const char *name, int, unsigned int *file_size,
908  void **handle, void **user_data) {
909  // We actually pass in the VirtualFile pointer as the "name".
910  VirtualFile *file = (VirtualFile *)name;
911  if (file == nullptr) {
912  return FMOD_ERR_FILE_NOTFOUND;
913  }
914  if (fmodAudio_cat.is_spam()) {
915  fmodAudio_cat.spam()
916  << "open_callback(" << *file << ")\n";
917  }
918 
919  istream *str = file->open_read_file(true);
920 
921  (*file_size) = file->get_file_size(str);
922  (*handle) = (void *)str;
923  (*user_data) = (void *)file;
924 
925  // Explicitly ref the VirtualFile since we're storing it in a void pointer
926  // instead of a PT(VirtualFile).
927  file->ref();
928 
929  return FMOD_OK;
930 }
931 
932 /**
933  * A hook into Panda's virtual file system.
934  */
935 FMOD_RESULT F_CALLBACK FmodAudioSound::
936 close_callback(void *handle, void *user_data) {
937  VirtualFile *file = (VirtualFile *)user_data;
938  if (fmodAudio_cat.is_spam()) {
939  fmodAudio_cat.spam()
940  << "close_callback(" << *file << ")\n";
941  }
942 
944 
945  istream *str = (istream *)handle;
946  vfs->close_read_file(str);
947 
948  // Explicitly unref the VirtualFile pointer.
949  unref_delete(file);
950 
951  return FMOD_OK;
952 }
953 
954 /**
955  * A hook into Panda's virtual file system.
956  */
957 FMOD_RESULT F_CALLBACK FmodAudioSound::
958 read_callback(void *handle, void *buffer, unsigned int size_bytes,
959  unsigned int *bytes_read, void *user_data) {
960  VirtualFile *file = (VirtualFile *)user_data;
961  if (fmodAudio_cat.is_spam()) {
962  fmodAudio_cat.spam()
963  << "read_callback(" << *file << ", " << size_bytes << ")\n";
964  }
965 
966  istream *str = (istream *)handle;
967  str->read((char *)buffer, size_bytes);
968  (*bytes_read) = str->gcount();
969 
970  // We can't yield here, since this callback is made within a sub-thread--an
971  // OS-level sub-thread spawned by FMod, not a Panda thread. But we will
972  // only execute this code in the true-threads case anyway.
973  // thread_consider_yield();
974 
975  if (str->eof()) {
976  if ((*bytes_read) == 0) {
977  return FMOD_ERR_FILE_EOF;
978  } else {
979  // Report the EOF next time.
980  return FMOD_OK;
981  }
982  } if (str->fail()) {
983  return FMOD_ERR_FILE_BAD;
984  } else {
985  return FMOD_OK;
986  }
987 }
988 
989 /**
990  * A hook into Panda's virtual file system.
991  */
992 FMOD_RESULT F_CALLBACK FmodAudioSound::
993 seek_callback(void *handle, unsigned int pos, void *user_data) {
994  VirtualFile *file = (VirtualFile *)user_data;
995  if (fmodAudio_cat.is_spam()) {
996  fmodAudio_cat.spam()
997  << "seek_callback(" << *file << ", " << pos << ")\n";
998  }
999 
1000  istream *str = (istream *)handle;
1001  str->clear();
1002  str->seekg(pos);
1003 
1004  if (str->fail() && !str->eof()) {
1005  return FMOD_ERR_FILE_COULDNOTSEEK;
1006  } else {
1007  return FMOD_OK;
1008  }
1009 }
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:616
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:544
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:567
FmodAudioSound::get_loop
bool get_loop() const
Returns whether looping is on or off.
Definition: fmodAudioSound.cxx:281
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:792
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:360
FmodAudioSound::set_loop
void set_loop(bool loop=true)
Turns looping on and off.
Definition: fmodAudioSound.cxx:269
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:499
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:487
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:707
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:864
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:846
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:326
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:346
FmodAudioSound::set_loop_count
void set_loop_count(unsigned long loop_count=1)
Panda uses 0 to mean loop forever.
Definition: fmodAudioSound.cxx:295
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:875
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:815
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:666
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:536
FmodAudioSound::set_balance
void set_balance(PN_stdfloat balance_right=0.0)
-1.0 to 1.0 scale
Definition: fmodAudioSound.cxx:476
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:638
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:382
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:630
FmodAudioSound::get_3d_max_distance
PN_stdfloat get_3d_max_distance() const
Get the distance that this sound stops falling off.
Definition: fmodAudioSound.cxx:652
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:607
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:392
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:854