Panda3D
openalAudioSound.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 openalAudioSound.cxx
10  * @author Ben Buchwald <bb2@alumni.cmu.edu>
11  */
12 
13 #include "pandabase.h"
14 
15 // Panda Headers
16 #include "throw_event.h"
17 #include "openalAudioSound.h"
18 #include "openalAudioManager.h"
19 
20 TypeHandle OpenALAudioSound::_type_handle;
21 
22 
23 #ifndef NDEBUG //[
24  #define openal_audio_debug(x) \
25  audio_debug("OpenALAudioSound \""<<get_name() \
26  <<"\" "<< x )
27 #else //][
28 #define openal_audio_debug(x) ((void)0)
29 #endif //]
30 
31 /**
32  *
33  */
34 
35 OpenALAudioSound::
36 OpenALAudioSound(OpenALAudioManager* manager,
37  MovieAudio *movie,
38  bool positional,
39  int mode) :
40  _movie(movie),
41  _sd(nullptr),
42  _playing_loops(0),
43  _playing_rate(0.0),
44  _loops_completed(0),
45  _source(0),
46  _manager(manager),
47  _volume(1.0f),
48  _balance(0),
49  _play_rate(1.0),
50  _positional(positional),
51  _min_dist(1.0f),
52  _max_dist(1000000000.0f),
53  _drop_off_factor(1.0f),
54  _length(0.0),
55  _loop_count(1),
56  _desired_mode(mode),
57  _start_time(0.0),
58  _current_time(0.0),
59  _basename(movie->get_filename().get_basename()),
60  _active(manager->get_active()),
61  _paused(false)
62 {
63  _location[0] = 0.0f;
64  _location[1] = 0.0f;
65  _location[2] = 0.0f;
66  _velocity[0] = 0.0f;
67  _velocity[1] = 0.0f;
68  _velocity[2] = 0.0f;
69 
70  ReMutexHolder holder(OpenALAudioManager::_lock);
71 
72  if (!require_sound_data()) {
73  cleanup();
74  return;
75  }
76 
77  _length = _sd->_length;
78  if (positional) {
79  if (_sd->_channels != 1) {
80  audio_warning("stereo sound " << movie->get_filename() << " will not be spatialized");
81  }
82  }
83  release_sound_data(false);
84 }
85 
86 
87 /**
88  *
89  */
90 OpenALAudioSound::
91 ~OpenALAudioSound() {
92  cleanup();
93 }
94 
95 /**
96  * Disables the sound forever. Releases resources and detaches the sound from
97  * its audio manager.
98  */
99 void OpenALAudioSound::
100 cleanup() {
101  ReMutexHolder holder(OpenALAudioManager::_lock);
102  if (!is_valid()) {
103  return;
104  }
105  if (is_playing()) {
106  stop();
107  }
108  if (has_sound_data()) {
109  release_sound_data(true);
110  }
111  _manager->release_sound(this);
112  _manager = nullptr;
113 }
114 
115 /**
116  * Plays a sound.
117  */
119 play() {
120  ReMutexHolder holder(OpenALAudioManager::_lock);
121 
122  if (!is_valid()) return;
123 
124  PN_stdfloat px,py,pz,vx,vy,vz;
125 
126  if (!_active) {
127  _paused = true;
128  return;
129  }
130 
131  stop();
132 
133  if (!require_sound_data()) {
134  cleanup();
135  return;
136  }
137 
138  _manager->starting_sound(this);
139  if (!is_playing()) {
140  return;
141  }
142 
143  _manager->make_current();
144 
145  alGetError(); // clear errors
146 
147  // nonpositional sources are made relative to the listener so they don't
148  // move
149  alSourcei(_source,AL_SOURCE_RELATIVE,_positional?AL_FALSE:AL_TRUE);
150  al_audio_errcheck("alSourcei(_source,AL_SOURCE_RELATIVE)");
151 
152  // set source properties that we have stored
153  set_volume(_volume);
154  // set_balance(_balance);
155 
156  set_3d_min_distance(_min_dist);
157  set_3d_max_distance(_max_dist);
158  set_3d_drop_off_factor(_drop_off_factor);
159  get_3d_attributes(&px,&py,&pz,&vx,&vy,&vz);
160  set_3d_attributes(px, py, pz, vx, vy, vz);
161 
162  _playing_loops = _loop_count;
163  if (_playing_loops == 0) {
164  _playing_loops = 1000000000;
165  }
166  _loops_completed = 0;
167 
168  double play_rate = _play_rate * _manager->get_play_rate();
169  audio_debug("playing. Rate=" << play_rate);
170  alSourcef(_source, AL_PITCH, play_rate);
171  _playing_rate = play_rate;
172 
173  if (_sd->_sample) {
174  push_fresh_buffers();
175  alSourcef(_source, AL_SEC_OFFSET, _start_time);
176  _stream_queued[0]._time_offset = _start_time;
177  restart_stalled_audio();
178  } else {
179  audio_debug("Play: stream tell = " << _sd->_stream->tell() << " seeking " << _start_time);
180  if (_sd->_stream->tell() != _start_time) {
181  _sd->_stream->seek(_start_time);
182  }
183  push_fresh_buffers();
184  restart_stalled_audio();
185  }
186  double rtc = TrueClock::get_global_ptr()->get_short_time();
187  set_calibrated_clock(rtc, _start_time, 1.0);
188  _current_time = _start_time;
189  _start_time = 0.0;
190 }
191 
192 /**
193  * Stop a sound
194  */
196 stop() {
197  ReMutexHolder holder(OpenALAudioManager::_lock);
198 
199  if (!is_valid()) return;
200 
201  if (is_playing()) {
202  _manager->make_current();
203 
204  nassertv(has_sound_data());
205 
206  alGetError(); // clear errors
207  alSourceStop(_source);
208  al_audio_errcheck("stopping a source");
209  alSourcei(_source, AL_BUFFER, 0);
210  al_audio_errcheck("clear source buffers");
211  for (int i=0; i<((int)(_stream_queued.size())); i++) {
212  ALuint buffer = _stream_queued[i]._buffer;
213  if (buffer != _sd->_sample) {
214  _manager->delete_buffer(buffer);
215  }
216  }
217  _stream_queued.resize(0);
218  }
219 
220  _manager->stopping_sound(this);
221  release_sound_data(false);
222 }
223 
224 /**
225  *
226  */
227 void OpenALAudioSound::
228 finished() {
229  ReMutexHolder holder(OpenALAudioManager::_lock);
230 
231  if (!is_valid()) return;
232 
233  stop();
234  _current_time = _length;
235  if (!_finished_event.empty()) {
236  throw_event(_finished_event);
237  }
238 }
239 
240 /**
241  * Turns looping on and off
242  */
244 set_loop(bool loop) {
245  ReMutexHolder holder(OpenALAudioManager::_lock);
246  set_loop_count((loop)?0:1);
247 }
248 
249 /**
250  * Returns whether looping is on or off
251  */
253 get_loop() const {
254  return (_loop_count == 0);
255 }
256 
257 /**
258  *
259  */
260 void OpenALAudioSound::
261 set_loop_count(unsigned long loop_count) {
262  ReMutexHolder holder(OpenALAudioManager::_lock);
263 
264  if (!is_valid()) return;
265 
266  if (loop_count >= 1000000000) {
267  loop_count = 0;
268  }
269  _loop_count=loop_count;
270 }
271 
272 /**
273  * Return how many times a sound will loop.
274  */
275 unsigned long OpenALAudioSound::
276 get_loop_count() const {
277  return _loop_count;
278 }
279 
280 /**
281  * When streaming audio, the computer is supposed to keep OpenAL's queue full.
282  * However, there are times when the computer is running slow and the queue
283  * empties prematurely. In that case, OpenAL will stop. When the computer
284  * finally gets around to refilling the queue, it is necessary to tell OpenAL
285  * to resume playing.
286  */
287 void OpenALAudioSound::
288 restart_stalled_audio() {
289  ReMutexHolder holder(OpenALAudioManager::_lock);
290  ALenum status;
291 
292  if (!is_valid()) return;
293  nassertv(is_playing());
294 
295  if (_stream_queued.size() == 0) {
296  return;
297  }
298 
299  alGetError();
300  alGetSourcei(_source, AL_SOURCE_STATE, &status);
301  if (status != AL_PLAYING) {
302  alSourcePlay(_source);
303  }
304 }
305 
306 /**
307  * Pushes a buffer into the source queue.
308  */
309 void OpenALAudioSound::
310 queue_buffer(ALuint buffer, int samples, int loop_index, double time_offset) {
311  ReMutexHolder holder(OpenALAudioManager::_lock);
312 
313  nassertv(is_playing());
314 
315  // Now push the buffer into the stream queue.
316  alGetError();
317  alSourceQueueBuffers(_source,1,&buffer);
318  ALenum err = alGetError();
319  if (err != AL_NO_ERROR) {
320  audio_error("could not load sample buffer into the queue");
321  cleanup();
322  return;
323  }
324  QueuedBuffer buf;
325  buf._buffer = buffer;
326  buf._samples = samples;
327  buf._loop_index = loop_index;
328  buf._time_offset = time_offset;
329  _stream_queued.push_back(buf);
330 }
331 
332 /**
333  * Creates an OpenAL buffer object.
334  */
335 ALuint OpenALAudioSound::
336 make_buffer(int samples, int channels, int rate, unsigned char *data) {
337  ReMutexHolder holder(OpenALAudioManager::_lock);
338 
339  nassertr(is_playing(), 0);
340 
341  // Allocate a buffer to hold the data.
342  alGetError();
343  ALuint buffer;
344  alGenBuffers(1, &buffer);
345  if (alGetError() != AL_NO_ERROR) {
346  audio_error("could not allocate an OpenAL buffer object");
347  cleanup();
348  return 0;
349  }
350 
351  // Now fill the buffer with the data provided.
352  alBufferData(buffer,
353  (channels>1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
354  data, samples * channels * 2, rate);
355  int err = alGetError();
356  if (err != AL_NO_ERROR) {
357  audio_error("could not fill OpenAL buffer object with data");
358  cleanup();
359  return 0;
360  }
361 
362  return buffer;
363 }
364 
365 /**
366  * Fills a buffer with data from the stream. Returns the number of samples
367  * stored in the buffer.
368  */
369 int OpenALAudioSound::
370 read_stream_data(int bytelen, unsigned char *buffer) {
371  ReMutexHolder holder(OpenALAudioManager::_lock);
372 
373  nassertr(has_sound_data(), 0);
374 
375  MovieAudioCursor *cursor = _sd->_stream;
376  double length = cursor->length();
377  int channels = cursor->audio_channels();
378  int rate = cursor->audio_rate();
379  int space = bytelen / (channels * 2);
380  int fill = 0;
381 
382  while (space && (_loops_completed < _playing_loops)) {
383  double t = cursor->tell();
384  double remain = length - t;
385  if (remain > 60.0) {
386  remain = 60.0;
387  }
388  int samples = (int)(remain * rate);
389  if (samples <= 0) {
390  _loops_completed += 1;
391  cursor->seek(0.0);
392  continue;
393  }
394  if (_sd->_stream->ready() == 0) {
395  if (_sd->_stream->aborted()) {
396  _loops_completed = _playing_loops;
397  }
398  return fill;
399  }
400  if (samples > space) {
401  samples = space;
402  }
403  if (samples > _sd->_stream->ready()) {
404  samples = _sd->_stream->ready();
405  }
406  cursor->read_samples(samples, (int16_t *)buffer);
407  size_t hval = AddHash::add_hash(0, (uint8_t*)buffer, samples*channels*2);
408  audio_debug("Streaming " << cursor->get_source()->get_name() << " at " << t << " hash " << hval);
409  fill += samples;
410  space -= samples;
411  buffer += (samples * channels * 2);
412  }
413  return fill;
414 }
415 
416 /**
417  * Compares the specified time to the value of the calibrated clock, and
418  * adjusts the calibrated clock speed to make it closer to the target value.
419  * This routine is quite careful to make sure that the calibrated clock moves
420  * in a smooth, monotonic way.
421  */
422 void OpenALAudioSound::
423 correct_calibrated_clock(double rtc, double t) {
424  ReMutexHolder holder(OpenALAudioManager::_lock);
425 
426  nassertv(is_playing());
427 
428  double cc = (rtc - _calibrated_clock_base) * _calibrated_clock_scale;
429  double diff = cc-t;
430  _calibrated_clock_decavg = (_calibrated_clock_decavg * 0.95) + (diff * 0.05);
431  if (diff > 0.5) {
432  set_calibrated_clock(rtc, t, 1.0);
433  _calibrated_clock_decavg = 0.0;
434  } else {
435  double scale = 1.0;
436  if ((_calibrated_clock_decavg > 0.01) && (diff > 0.01)) {
437  scale = 0.98;
438  }
439  if ((_calibrated_clock_decavg < -0.01) && (diff < -0.01)) {
440  scale = 1.03;
441  }
442  if ((_calibrated_clock_decavg < -0.05) && (diff < -0.05)) {
443  scale = 1.2;
444  }
445  if ((_calibrated_clock_decavg < -0.15) && (diff < -0.15)) {
446  scale = 1.5;
447  }
448  set_calibrated_clock(rtc, cc, scale);
449  }
450  cc = (rtc - _calibrated_clock_base) * _calibrated_clock_scale;
451 }
452 
453 /**
454  * Pulls any used buffers out of OpenAL's queue.
455  */
456 void OpenALAudioSound::
457 pull_used_buffers() {
458  ReMutexHolder holder(OpenALAudioManager::_lock);
459 
460  if (!is_valid()) return;
461  nassertv(is_playing());
462  nassertv(has_sound_data());
463 
464  while (_stream_queued.size()) {
465  ALuint buffer = 0;
466  ALint num_buffers = 0;
467  alGetSourcei(_source, AL_BUFFERS_PROCESSED, &num_buffers);
468  if (num_buffers <= 0) {
469  break;
470  }
471  alSourceUnqueueBuffers(_source, 1, &buffer);
472  int err = alGetError();
473  if (err == AL_NO_ERROR) {
474  if (_stream_queued[0]._buffer != buffer) {
475  // This is certainly atypical: most implementations of OpenAL unqueue
476  // buffers in FIFO order. However, some (e.g. Apple's) can unqueue
477  // buffers out-of-order if playback is interrupted. So, we don't freak
478  // out unless `buffer` isn't in _stream_queued at all.
479  bool found_culprit = false;
480  for (auto it = _stream_queued.begin(); it != _stream_queued.end(); ++it) {
481  if (it->_buffer == buffer) {
482  // Phew. Found it. Just remove that.
483  _stream_queued.erase(it);
484  found_culprit = true;
485  break;
486  }
487  }
488  if (!found_culprit) {
489  audio_error("corruption in stream queue");
490  cleanup();
491  return;
492  }
493  } else {
494  _stream_queued.pop_front();
495  if (_stream_queued.size()) {
496  double al = _stream_queued[0]._time_offset + _stream_queued[0]._loop_index * _length;
497  double rtc = TrueClock::get_global_ptr()->get_short_time();
498  correct_calibrated_clock(rtc, al);
499  }
500  if (buffer != _sd->_sample) {
501  _manager->delete_buffer(buffer);
502  }
503  }
504  } else {
505  break;
506  }
507  }
508 }
509 
510 /**
511  * Pushes fresh buffers into OpenAL's queue until the queue is "full" (ie, has
512  * plenty of data).
513  */
514 void OpenALAudioSound::
515 push_fresh_buffers() {
516  ReMutexHolder holder(OpenALAudioManager::_lock);
517  static unsigned char data[65536];
518 
519  if (!is_valid()) return;
520  nassertv(is_playing());
521  nassertv(has_sound_data());
522 
523  if (_sd->_sample) {
524  while ((_loops_completed < _playing_loops) &&
525  (_stream_queued.size() < 100)) {
526  queue_buffer(_sd->_sample, 0,_loops_completed, 0.0);
527  _loops_completed += 1;
528  }
529  } else {
530  MovieAudioCursor *cursor = _sd->_stream;
531  int channels = cursor->audio_channels();
532  int rate = cursor->audio_rate();
533 
534  int fill = 0;
535  for (size_t i = 0; i < _stream_queued.size(); i++) {
536  fill += _stream_queued[i]._samples;
537  }
538 
539  while ((_loops_completed < _playing_loops) &&
540  (fill < (int)(audio_buffering_seconds * rate * channels))) {
541  int loop_index = _loops_completed;
542  double time_offset = cursor->tell();
543  int samples = read_stream_data(65536, data);
544  if (samples == 0) {
545  break;
546  }
547  ALuint buffer = make_buffer(samples, channels, rate, data);
548  if (!is_valid() || !buffer) return;
549  queue_buffer(buffer, samples, loop_index, time_offset);
550  if (!is_valid()) return;
551  fill += samples;
552  }
553  }
554 }
555 
556 /**
557  * The next time you call play, the sound will start from the specified
558  * offset.
559  */
561 set_time(PN_stdfloat time) {
562  ReMutexHolder holder(OpenALAudioManager::_lock);
563  _start_time = time;
564 }
565 
566 /**
567  * Gets the play position within the sound
568  */
569 PN_stdfloat OpenALAudioSound::
570 get_time() const {
571  ReMutexHolder holder(OpenALAudioManager::_lock);
572  if (!is_valid()) {
573  return 0.0;
574  }
575  return _current_time;
576 }
577 
578 /**
579  * Updates the current_time field of a playing sound.
580  */
581 void OpenALAudioSound::
582 cache_time(double rtc) {
583  ReMutexHolder holder(OpenALAudioManager::_lock);
584 
585  nassertv(is_playing());
586 
587  double t=get_calibrated_clock(rtc);
588  double max = _length * _playing_loops;
589  if (t >= max) {
590  _current_time = _length;
591  } else {
592  _current_time = fmod(t, _length);
593  }
594 }
595 
596 /**
597  * 0.0 to 1.0 scale of volume converted to Fmod's internal 0.0 to 255.0 scale.
598  */
600 set_volume(PN_stdfloat volume) {
601  ReMutexHolder holder(OpenALAudioManager::_lock);
602  _volume=volume;
603 
604  if (is_playing()) {
605  volume*=_manager->get_volume();
606  _manager->make_current();
607  alGetError(); // clear errors
608  alSourcef(_source,AL_GAIN,volume);
609  al_audio_errcheck("alSourcef(_source,AL_GAIN)");
610  }
611 }
612 
613 /**
614  * Gets the current volume of a sound. 1 is Max. O is Min.
615  */
616 PN_stdfloat OpenALAudioSound::
617 get_volume() const {
618  return _volume;
619 }
620 
621 /**
622  * -1.0 to 1.0 scale
623  */
625 set_balance(PN_stdfloat balance_right) {
626  audio_debug("OpenALAudioSound::set_balance() not implemented");
627 }
628 
629 /**
630  * -1.0 to 1.0 scale -1 should be all the way left. 1 is all the way to the
631  * right.
632  */
633 PN_stdfloat OpenALAudioSound::
634 get_balance() const {
635  audio_debug("OpenALAudioSound::get_balance() not implemented");
636  return 0;
637 }
638 
639 /**
640  * Sets the speed at which a sound plays back. The rate is a multiple of the
641  * sound, normal playback speed. IE 2 would play back 2 times fast, 3 would
642  * play 3 times, and so on.
643  */
645 set_play_rate(PN_stdfloat play_rate) {
646  ReMutexHolder holder(OpenALAudioManager::_lock);
647  _play_rate = play_rate;
648  if (is_playing()) {
649  alSourcef(_source, AL_PITCH, play_rate);
650  }
651 }
652 
653 /**
654  *
655  */
656 PN_stdfloat OpenALAudioSound::
657 get_play_rate() const {
658  return _play_rate;
659 }
660 
661 /**
662  * Get length
663  */
664 PN_stdfloat OpenALAudioSound::
665 length() const {
666  return _length;
667 }
668 
669 /**
670  * Set position and velocity of this sound
671  *
672  * Both Panda3D and OpenAL use a right handed coordinate system. However, in
673  * Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up. In
674  * OpenAL the Y-Axis is going up and the Z-Axis is coming out of the screen.
675  *
676  * The solution is simple, we just flip the Y and Z axis and negate the Z, as
677  * we move coordinates from Panda to OpenAL and back.
678  */
680 set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) {
681  ReMutexHolder holder(OpenALAudioManager::_lock);
682  _location[0] = px;
683  _location[1] = pz;
684  _location[2] = -py;
685 
686  _velocity[0] = vx;
687  _velocity[1] = vz;
688  _velocity[2] = -vy;
689 
690  if (is_playing()) {
691  _manager->make_current();
692 
693  alGetError(); // clear errors
694  alSourcefv(_source,AL_POSITION,_location);
695  al_audio_errcheck("alSourcefv(_source,AL_POSITION)");
696  alSourcefv(_source,AL_VELOCITY,_velocity);
697  al_audio_errcheck("alSourcefv(_source,AL_VELOCITY)");
698  }
699 }
700 
701 /**
702  * Get position and velocity of this sound Currently unimplemented. Get the
703  * attributes of the attached object.
704  */
706 get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) {
707  ReMutexHolder holder(OpenALAudioManager::_lock);
708  *px = _location[0];
709  *py = -_location[2];
710  *pz = _location[1];
711 
712  *vx = _velocity[0];
713  *vy = -_velocity[2];
714  *vz = _velocity[1];
715 }
716 
717 /**
718  * Set the distance that this sound begins to fall off. Also affects the rate
719  * it falls off.
720  */
722 set_3d_min_distance(PN_stdfloat dist) {
723  ReMutexHolder holder(OpenALAudioManager::_lock);
724  _min_dist = dist;
725 
726  if (is_playing()) {
727  _manager->make_current();
728 
729  alGetError(); // clear errors
730  alSourcef(_source,AL_REFERENCE_DISTANCE,_min_dist);
731  al_audio_errcheck("alSourcefv(_source,AL_REFERENCE_DISTANCE)");
732  }
733 }
734 
735 /**
736  * Get the distance that this sound begins to fall off
737  */
738 PN_stdfloat OpenALAudioSound::
740  return _min_dist;
741 }
742 
743 /**
744  * Set the distance that this sound stops falling off
745  */
747 set_3d_max_distance(PN_stdfloat dist) {
748  ReMutexHolder holder(OpenALAudioManager::_lock);
749  _max_dist = dist;
750 
751  if (is_playing()) {
752  _manager->make_current();
753 
754  alGetError(); // clear errors
755  alSourcef(_source,AL_MAX_DISTANCE,_max_dist);
756  al_audio_errcheck("alSourcefv(_source,AL_MAX_DISTANCE)");
757  }
758 }
759 
760 /**
761  * Get the distance that this sound stops falling off
762  */
763 PN_stdfloat OpenALAudioSound::
765  return _max_dist;
766 }
767 
768 /**
769  * Control the effect distance has on audability. Defaults to 1.0
770  */
772 set_3d_drop_off_factor(PN_stdfloat factor) {
773  ReMutexHolder holder(OpenALAudioManager::_lock);
774  _drop_off_factor = factor;
775 
776  if (is_playing()) {
777  _manager->make_current();
778 
779  alGetError(); // clear errors
780  alSourcef(_source,AL_ROLLOFF_FACTOR,_drop_off_factor*_manager->audio_3d_get_drop_off_factor());
781  al_audio_errcheck("alSourcefv(_source,AL_ROLLOFF_FACTOR)");
782  }
783 }
784 
785 /**
786  * Control the effect distance has on audability. Defaults to 1.0
787  */
788 PN_stdfloat OpenALAudioSound::
790  return _drop_off_factor;
791 }
792 
793 /**
794  * Sets whether the sound is marked "active". By default, the active flag is
795  * true for all sounds. If the active flag is set to false for any particular
796  * sound, the sound will not be heard.
797  */
799 set_active(bool active) {
800  ReMutexHolder holder(OpenALAudioManager::_lock);
801 
802  if (!is_valid()) return;
803 
804  if (_active!=active) {
805  _active=active;
806  if (_active) {
807  // ...activate the sound.
808  if (_paused && _loop_count==0) {
809  // ...this sound was looping when it was paused.
810  _paused=false;
811  play();
812  }
813  } else {
814  // ...deactivate the sound.
815  if (status()==PLAYING) {
816  if (_loop_count==0) {
817  // ...we're pausing a looping sound.
818  _paused=true;
819  }
820  stop();
821  }
822  }
823  }
824 }
825 
826 
827 /**
828  * Returns whether the sound has been marked "active".
829  */
831 get_active() const {
832  return _active;
833 }
834 
835 /**
836  *
837  */
838 void OpenALAudioSound::
839 set_finished_event(const std::string& event) {
840  _finished_event = event;
841 }
842 
843 /**
844  *
845  */
846 const std::string& OpenALAudioSound::
847 get_finished_event() const {
848  return _finished_event;
849 }
850 
851 /**
852  * Get name of sound file
853  */
854 const std::string& OpenALAudioSound::
855 get_name() const {
856  return _basename;
857 }
858 
859 /**
860  * Get status of the sound.
861  *
862  * This returns the status as of the last push_fresh_buffers
863  */
864 AudioSound::SoundStatus OpenALAudioSound::
865 status() const {
866  ReMutexHolder holder(OpenALAudioManager::_lock);
867  if (!is_playing()) {
868  return AudioSound::READY;
869  }
870  if ((_loops_completed >= _playing_loops)&&(_stream_queued.size()==0)) {
871  return AudioSound::READY;
872  } else {
873  return AudioSound::PLAYING;
874  }
875 }
get_filename
Returns the movie's filename.
Definition: movieAudio.h:52
void set_3d_max_distance(PN_stdfloat dist)
Set the distance that this sound stops falling off.
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:68
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const std::string & get_name() const
Get name of sound file.
void set_time(PN_stdfloat time=0.0)
The next time you call play, the sound will start from the specified offset.
PN_stdfloat get_3d_max_distance() const
Get the distance that this sound stops falling off.
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.
void read_samples(int n, Datagram *dg)
Read audio samples from the stream into a Datagram.
PN_stdfloat get_time() const
Gets the play position within the sound.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static size_t add_hash(size_t start, const uint32_t *words, size_t num_words)
Adds a linear sequence of uint32 words to the hash.
Definition: addHash.I:18
void set_3d_min_distance(PN_stdfloat dist)
Set the distance that this sound begins to fall off.
PN_stdfloat get_3d_drop_off_factor() const
Control the effect distance has on audability.
bool get_loop() const
Returns whether looping is on or off.
void set_3d_drop_off_factor(PN_stdfloat factor)
Control the effect distance has on audability.
void set_active(bool active=true)
Sets whether the sound is marked "active".
PN_stdfloat get_balance() const
-1.0 to 1.0 scale -1 should be all the way left.
void stop()
Stop a sound.
A MovieAudio is actually any source that provides a sequence of audio samples.
bool get_active() const
Returns whether the sound has been marked "active".
Similar to MutexHolder, but for a reentrant mutex.
Definition: reMutexHolder.h:25
void play()
Plays a sound.
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.
PN_stdfloat get_3d_min_distance() const
Get the distance that this sound begins to fall off.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void set_loop(bool loop=true)
Turns looping on and off.
A MovieAudio is actually any source that provides a sequence of audio samples.
Definition: movieAudio.h:44
PN_stdfloat get_volume() const
Gets the current volume of a sound.
unsigned long get_loop_count() const
Return how many times a sound will loop.
PN_stdfloat length() const
Get length.
void set_balance(PN_stdfloat balance_right=0.0)
-1.0 to 1.0 scale
virtual void seek(double offset)
Skips to the specified offset within the file.
void set_play_rate(PN_stdfloat play_rate=1.0f)
Sets the speed at which a sound plays back.
AudioSound::SoundStatus status() const
Get status of the sound.