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  _paused = false;
221 
222  _manager->stopping_sound(this);
223  release_sound_data(false);
224 }
225 
226 /**
227  *
228  */
229 void OpenALAudioSound::
230 finished() {
231  ReMutexHolder holder(OpenALAudioManager::_lock);
232 
233  if (!is_valid()) return;
234 
235  stop();
236  _current_time = _length;
237  if (!_finished_event.empty()) {
238  throw_event(_finished_event);
239  }
240 }
241 
242 /**
243  * Turns looping on and off
244  */
246 set_loop(bool loop) {
247  ReMutexHolder holder(OpenALAudioManager::_lock);
248  set_loop_count((loop)?0:1);
249 }
250 
251 /**
252  * Returns whether looping is on or off
253  */
255 get_loop() const {
256  return (_loop_count == 0);
257 }
258 
259 /**
260  *
261  */
262 void OpenALAudioSound::
263 set_loop_count(unsigned long loop_count) {
264  ReMutexHolder holder(OpenALAudioManager::_lock);
265 
266  if (!is_valid()) return;
267 
268  if (loop_count >= 1000000000) {
269  loop_count = 0;
270  }
271  _loop_count=loop_count;
272 }
273 
274 /**
275  * Return how many times a sound will loop.
276  */
277 unsigned long OpenALAudioSound::
278 get_loop_count() const {
279  return _loop_count;
280 }
281 
282 /**
283  * When streaming audio, the computer is supposed to keep OpenAL's queue full.
284  * However, there are times when the computer is running slow and the queue
285  * empties prematurely. In that case, OpenAL will stop. When the computer
286  * finally gets around to refilling the queue, it is necessary to tell OpenAL
287  * to resume playing.
288  */
289 void OpenALAudioSound::
290 restart_stalled_audio() {
291  ReMutexHolder holder(OpenALAudioManager::_lock);
292  ALenum status;
293 
294  if (!is_valid()) return;
295  nassertv(is_playing());
296 
297  if (_stream_queued.size() == 0) {
298  return;
299  }
300 
301  alGetError();
302  alGetSourcei(_source, AL_SOURCE_STATE, &status);
303  if (status != AL_PLAYING) {
304  alSourcePlay(_source);
305  }
306 }
307 
308 /**
309  * Pushes a buffer into the source queue.
310  */
311 void OpenALAudioSound::
312 queue_buffer(ALuint buffer, int samples, int loop_index, double time_offset) {
313  ReMutexHolder holder(OpenALAudioManager::_lock);
314 
315  nassertv(is_playing());
316 
317  // Now push the buffer into the stream queue.
318  alGetError();
319  alSourceQueueBuffers(_source,1,&buffer);
320  ALenum err = alGetError();
321  if (err != AL_NO_ERROR) {
322  audio_error("could not load sample buffer into the queue");
323  cleanup();
324  return;
325  }
326  QueuedBuffer buf;
327  buf._buffer = buffer;
328  buf._samples = samples;
329  buf._loop_index = loop_index;
330  buf._time_offset = time_offset;
331  _stream_queued.push_back(buf);
332 }
333 
334 /**
335  * Creates an OpenAL buffer object.
336  */
337 ALuint OpenALAudioSound::
338 make_buffer(int samples, int channels, int rate, unsigned char *data) {
339  ReMutexHolder holder(OpenALAudioManager::_lock);
340 
341  nassertr(is_playing(), 0);
342 
343  // Allocate a buffer to hold the data.
344  alGetError();
345  ALuint buffer;
346  alGenBuffers(1, &buffer);
347  if (alGetError() != AL_NO_ERROR) {
348  audio_error("could not allocate an OpenAL buffer object");
349  cleanup();
350  return 0;
351  }
352 
353  // Now fill the buffer with the data provided.
354  alBufferData(buffer,
355  (channels>1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
356  data, samples * channels * 2, rate);
357  int err = alGetError();
358  if (err != AL_NO_ERROR) {
359  audio_error("could not fill OpenAL buffer object with data");
360  cleanup();
361  return 0;
362  }
363 
364  return buffer;
365 }
366 
367 /**
368  * Fills a buffer with data from the stream. Returns the number of samples
369  * stored in the buffer.
370  */
371 int OpenALAudioSound::
372 read_stream_data(int bytelen, unsigned char *buffer) {
373  ReMutexHolder holder(OpenALAudioManager::_lock);
374 
375  nassertr(has_sound_data(), 0);
376 
377  MovieAudioCursor *cursor = _sd->_stream;
378  double length = cursor->length();
379  int channels = cursor->audio_channels();
380  int rate = cursor->audio_rate();
381  int space = bytelen / (channels * 2);
382  int fill = 0;
383 
384  while (space && (_loops_completed < _playing_loops)) {
385  double t = cursor->tell();
386  double remain = length - t;
387  if (remain > 60.0) {
388  remain = 60.0;
389  }
390  int samples = (int)(remain * rate);
391  if (samples <= 0) {
392  _loops_completed += 1;
393  cursor->seek(0.0);
394  continue;
395  }
396  if (_sd->_stream->ready() == 0) {
397  if (_sd->_stream->aborted()) {
398  _loops_completed = _playing_loops;
399  }
400  return fill;
401  }
402  if (samples > space) {
403  samples = space;
404  }
405  if (samples > _sd->_stream->ready()) {
406  samples = _sd->_stream->ready();
407  }
408  cursor->read_samples(samples, (int16_t *)buffer);
409  size_t hval = AddHash::add_hash(0, (uint8_t*)buffer, samples*channels*2);
410  audio_debug("Streaming " << cursor->get_source()->get_name() << " at " << t << " hash " << hval);
411  fill += samples;
412  space -= samples;
413  buffer += (samples * channels * 2);
414  }
415  return fill;
416 }
417 
418 /**
419  * Compares the specified time to the value of the calibrated clock, and
420  * adjusts the calibrated clock speed to make it closer to the target value.
421  * This routine is quite careful to make sure that the calibrated clock moves
422  * in a smooth, monotonic way.
423  */
424 void OpenALAudioSound::
425 correct_calibrated_clock(double rtc, double t) {
426  ReMutexHolder holder(OpenALAudioManager::_lock);
427 
428  nassertv(is_playing());
429 
430  double cc = (rtc - _calibrated_clock_base) * _calibrated_clock_scale;
431  double diff = cc-t;
432  _calibrated_clock_decavg = (_calibrated_clock_decavg * 0.95) + (diff * 0.05);
433  if (diff > 0.5) {
434  set_calibrated_clock(rtc, t, 1.0);
435  _calibrated_clock_decavg = 0.0;
436  } else {
437  double scale = 1.0;
438  if ((_calibrated_clock_decavg > 0.01) && (diff > 0.01)) {
439  scale = 0.98;
440  }
441  if ((_calibrated_clock_decavg < -0.01) && (diff < -0.01)) {
442  scale = 1.03;
443  }
444  if ((_calibrated_clock_decavg < -0.05) && (diff < -0.05)) {
445  scale = 1.2;
446  }
447  if ((_calibrated_clock_decavg < -0.15) && (diff < -0.15)) {
448  scale = 1.5;
449  }
450  set_calibrated_clock(rtc, cc, scale);
451  }
452  cc = (rtc - _calibrated_clock_base) * _calibrated_clock_scale;
453 }
454 
455 /**
456  * Pulls any used buffers out of OpenAL's queue.
457  */
458 void OpenALAudioSound::
459 pull_used_buffers() {
460  ReMutexHolder holder(OpenALAudioManager::_lock);
461 
462  if (!is_valid()) return;
463  nassertv(is_playing());
464  nassertv(has_sound_data());
465 
466  while (_stream_queued.size()) {
467  ALuint buffer = 0;
468  ALint num_buffers = 0;
469  alGetSourcei(_source, AL_BUFFERS_PROCESSED, &num_buffers);
470  if (num_buffers <= 0) {
471  break;
472  }
473  alSourceUnqueueBuffers(_source, 1, &buffer);
474  int err = alGetError();
475  if (err == AL_NO_ERROR) {
476  if (_stream_queued[0]._buffer != buffer) {
477  // This is certainly atypical: most implementations of OpenAL unqueue
478  // buffers in FIFO order. However, some (e.g. Apple's) can unqueue
479  // buffers out-of-order if playback is interrupted. So, we don't freak
480  // out unless `buffer` isn't in _stream_queued at all.
481  bool found_culprit = false;
482  for (auto it = _stream_queued.begin(); it != _stream_queued.end(); ++it) {
483  if (it->_buffer == buffer) {
484  // Phew. Found it. Just remove that.
485  _stream_queued.erase(it);
486  found_culprit = true;
487  break;
488  }
489  }
490  if (!found_culprit) {
491  audio_error("corruption in stream queue");
492  cleanup();
493  return;
494  }
495  } else {
496  _stream_queued.pop_front();
497  if (_stream_queued.size()) {
498  double al = _stream_queued[0]._time_offset + _stream_queued[0]._loop_index * _length;
499  double rtc = TrueClock::get_global_ptr()->get_short_time();
500  correct_calibrated_clock(rtc, al);
501  }
502  if (buffer != _sd->_sample) {
503  _manager->delete_buffer(buffer);
504  }
505  }
506  } else {
507  break;
508  }
509  }
510 }
511 
512 /**
513  * Pushes fresh buffers into OpenAL's queue until the queue is "full" (ie, has
514  * plenty of data).
515  */
516 void OpenALAudioSound::
517 push_fresh_buffers() {
518  ReMutexHolder holder(OpenALAudioManager::_lock);
519  static unsigned char data[65536];
520 
521  if (!is_valid()) return;
522  nassertv(is_playing());
523  nassertv(has_sound_data());
524 
525  if (_sd->_sample) {
526  while ((_loops_completed < _playing_loops) &&
527  (_stream_queued.size() < 100)) {
528  queue_buffer(_sd->_sample, 0,_loops_completed, 0.0);
529  _loops_completed += 1;
530  }
531  } else {
532  MovieAudioCursor *cursor = _sd->_stream;
533  int channels = cursor->audio_channels();
534  int rate = cursor->audio_rate();
535 
536  int fill = 0;
537  for (size_t i = 0; i < _stream_queued.size(); i++) {
538  fill += _stream_queued[i]._samples;
539  }
540 
541  while ((_loops_completed < _playing_loops) &&
542  (fill < (int)(audio_buffering_seconds * rate * channels))) {
543  int loop_index = _loops_completed;
544  double time_offset = cursor->tell();
545  int samples = read_stream_data(65536, data);
546  if (samples == 0) {
547  break;
548  }
549  ALuint buffer = make_buffer(samples, channels, rate, data);
550  if (!is_valid() || !buffer) return;
551  queue_buffer(buffer, samples, loop_index, time_offset);
552  if (!is_valid()) return;
553  fill += samples;
554  }
555  }
556 }
557 
558 /**
559  * The next time you call play, the sound will start from the specified
560  * offset.
561  */
563 set_time(PN_stdfloat time) {
564  ReMutexHolder holder(OpenALAudioManager::_lock);
565  _start_time = time;
566 }
567 
568 /**
569  * Gets the play position within the sound
570  */
572 get_time() const {
573  ReMutexHolder holder(OpenALAudioManager::_lock);
574  if (!is_valid()) {
575  return 0.0;
576  }
577  return _current_time;
578 }
579 
580 /**
581  * Updates the current_time field of a playing sound.
582  */
583 void OpenALAudioSound::
584 cache_time(double rtc) {
585  ReMutexHolder holder(OpenALAudioManager::_lock);
586 
587  nassertv(is_playing());
588 
589  double t=get_calibrated_clock(rtc);
590  double max = _length * _playing_loops;
591  if (t >= max) {
592  _current_time = _length;
593  } else {
594  _current_time = fmod(t, _length);
595  }
596 }
597 
598 /**
599  * 0.0 to 1.0 scale of volume converted to Fmod's internal 0.0 to 255.0 scale.
600  */
602 set_volume(PN_stdfloat volume) {
603  ReMutexHolder holder(OpenALAudioManager::_lock);
604  _volume=volume;
605 
606  if (is_playing()) {
607  volume*=_manager->get_volume();
608  _manager->make_current();
609  alGetError(); // clear errors
610  alSourcef(_source,AL_GAIN,volume);
611  al_audio_errcheck("alSourcef(_source,AL_GAIN)");
612  }
613 }
614 
615 /**
616  * Gets the current volume of a sound. 1 is Max. O is Min.
617  */
619 get_volume() const {
620  return _volume;
621 }
622 
623 /**
624  * -1.0 to 1.0 scale
625  */
627 set_balance(PN_stdfloat balance_right) {
628  audio_debug("OpenALAudioSound::set_balance() not implemented");
629 }
630 
631 /**
632  * -1.0 to 1.0 scale -1 should be all the way left. 1 is all the way to the
633  * right.
634  */
636 get_balance() const {
637  audio_debug("OpenALAudioSound::get_balance() not implemented");
638  return 0;
639 }
640 
641 /**
642  * Sets the speed at which a sound plays back. The rate is a multiple of the
643  * sound, normal playback speed. IE 2 would play back 2 times fast, 3 would
644  * play 3 times, and so on.
645  */
647 set_play_rate(PN_stdfloat play_rate) {
648  ReMutexHolder holder(OpenALAudioManager::_lock);
649  _play_rate = play_rate;
650  if (is_playing()) {
651  alSourcef(_source, AL_PITCH, play_rate);
652  }
653 }
654 
655 /**
656  *
657  */
658 PN_stdfloat OpenALAudioSound::
659 get_play_rate() const {
660  return _play_rate;
661 }
662 
663 /**
664  * Get length
665  */
667 length() const {
668  return _length;
669 }
670 
671 /**
672  * Set position and velocity of this sound
673  *
674  * Both Panda3D and OpenAL use a right handed coordinate system. However, in
675  * Panda3D the Y-Axis is going into the Screen and the Z-Axis is going up. In
676  * OpenAL the Y-Axis is going up and the Z-Axis is coming out of the screen.
677  *
678  * The solution is simple, we just flip the Y and Z axis and negate the Z, as
679  * we move coordinates from Panda to OpenAL and back.
680  */
682 set_3d_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz) {
683  ReMutexHolder holder(OpenALAudioManager::_lock);
684  _location[0] = px;
685  _location[1] = pz;
686  _location[2] = -py;
687 
688  _velocity[0] = vx;
689  _velocity[1] = vz;
690  _velocity[2] = -vy;
691 
692  if (is_playing()) {
693  _manager->make_current();
694 
695  alGetError(); // clear errors
696  alSourcefv(_source,AL_POSITION,_location);
697  al_audio_errcheck("alSourcefv(_source,AL_POSITION)");
698  alSourcefv(_source,AL_VELOCITY,_velocity);
699  al_audio_errcheck("alSourcefv(_source,AL_VELOCITY)");
700  }
701 }
702 
703 /**
704  * Get position and velocity of this sound Currently unimplemented. Get the
705  * attributes of the attached object.
706  */
708 get_3d_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz) {
709  ReMutexHolder holder(OpenALAudioManager::_lock);
710  *px = _location[0];
711  *py = -_location[2];
712  *pz = _location[1];
713 
714  *vx = _velocity[0];
715  *vy = -_velocity[2];
716  *vz = _velocity[1];
717 }
718 
719 /**
720  * Set the distance that this sound begins to fall off. Also affects the rate
721  * it falls off.
722  */
724 set_3d_min_distance(PN_stdfloat dist) {
725  ReMutexHolder holder(OpenALAudioManager::_lock);
726  _min_dist = dist;
727 
728  if (is_playing()) {
729  _manager->make_current();
730 
731  alGetError(); // clear errors
732  alSourcef(_source,AL_REFERENCE_DISTANCE,_min_dist);
733  al_audio_errcheck("alSourcefv(_source,AL_REFERENCE_DISTANCE)");
734  }
735 }
736 
737 /**
738  * Get the distance that this sound begins to fall off
739  */
741 get_3d_min_distance() const {
742  return _min_dist;
743 }
744 
745 /**
746  * Set the distance that this sound stops falling off
747  */
749 set_3d_max_distance(PN_stdfloat dist) {
750  ReMutexHolder holder(OpenALAudioManager::_lock);
751  _max_dist = dist;
752 
753  if (is_playing()) {
754  _manager->make_current();
755 
756  alGetError(); // clear errors
757  alSourcef(_source,AL_MAX_DISTANCE,_max_dist);
758  al_audio_errcheck("alSourcefv(_source,AL_MAX_DISTANCE)");
759  }
760 }
761 
762 /**
763  * Get the distance that this sound stops falling off
764  */
766 get_3d_max_distance() const {
767  return _max_dist;
768 }
769 
770 /**
771  * Control the effect distance has on audability. Defaults to 1.0
772  */
774 set_3d_drop_off_factor(PN_stdfloat factor) {
775  ReMutexHolder holder(OpenALAudioManager::_lock);
776  _drop_off_factor = factor;
777 
778  if (is_playing()) {
779  _manager->make_current();
780 
781  alGetError(); // clear errors
782  alSourcef(_source,AL_ROLLOFF_FACTOR,_drop_off_factor*_manager->audio_3d_get_drop_off_factor());
783  al_audio_errcheck("alSourcefv(_source,AL_ROLLOFF_FACTOR)");
784  }
785 }
786 
787 /**
788  * Control the effect distance has on audability. Defaults to 1.0
789  */
791 get_3d_drop_off_factor() const {
792  return _drop_off_factor;
793 }
794 
795 /**
796  * Sets whether the sound is marked "active". By default, the active flag is
797  * true for all sounds. If the active flag is set to false for any particular
798  * sound, the sound will not be heard.
799  */
801 set_active(bool active) {
802  ReMutexHolder holder(OpenALAudioManager::_lock);
803 
804  if (!is_valid()) return;
805 
806  if (_active!=active) {
807  _active=active;
808  if (_active) {
809  // ...activate the sound.
810  if (_paused && _loop_count==0) {
811  // ...this sound was looping when it was paused.
812  _paused=false;
813  play();
814  }
815  } else {
816  // ...deactivate the sound.
817  if (status()==PLAYING) {
818  stop();
819  if (_loop_count==0) {
820  // ...we're pausing a looping sound.
821  _paused=true;
822  }
823  }
824  }
825  }
826 }
827 
828 
829 /**
830  * Returns whether the sound has been marked "active".
831  */
833 get_active() const {
834  return _active;
835 }
836 
837 /**
838  *
839  */
840 void OpenALAudioSound::
841 set_finished_event(const std::string& event) {
842  _finished_event = event;
843 }
844 
845 /**
846  *
847  */
848 const std::string& OpenALAudioSound::
849 get_finished_event() const {
850  return _finished_event;
851 }
852 
853 /**
854  * Get name of sound file
855  */
856 const std::string& OpenALAudioSound::
857 get_name() const {
858  return _basename;
859 }
860 
861 /**
862  * Get status of the sound.
863  *
864  * This returns the status as of the last push_fresh_buffers
865  */
866 AudioSound::SoundStatus OpenALAudioSound::
867 status() const {
868  ReMutexHolder holder(OpenALAudioManager::_lock);
869  if (!is_playing()) {
870  return AudioSound::READY;
871  }
872  if ((_loops_completed >= _playing_loops)&&(_stream_queued.size()==0)) {
873  return AudioSound::READY;
874  } else {
875  return AudioSound::PLAYING;
876  }
877 }
MovieAudio::get_filename
get_filename
Returns the movie's filename.
Definition: movieAudio.h:52
openalAudioSound.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OpenALAudioSound::set_active
void set_active(bool active=true)
Sets whether the sound is marked "active".
Definition: openalAudioSound.cxx:801
throw_event.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OpenALAudioSound::get_balance
PN_stdfloat get_balance() const
-1.0 to 1.0 scale -1 should be all the way left.
Definition: openalAudioSound.cxx:636
ReMutexHolder
Similar to MutexHolder, but for a reentrant mutex.
Definition: reMutexHolder.h:25
pandabase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OpenALAudioSound::play
void play()
Plays a sound.
Definition: openalAudioSound.cxx:119
OpenALAudioSound::get_3d_min_distance
PN_stdfloat get_3d_min_distance() const
Get the distance that this sound begins to fall off.
Definition: openalAudioSound.cxx:741
OpenALAudioSound::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: openalAudioSound.cxx:602
OpenALAudioSound::get_active
bool get_active() const
Returns whether the sound has been marked "active".
Definition: openalAudioSound.cxx:833
OpenALAudioSound::stop
void stop()
Stop a sound.
Definition: openalAudioSound.cxx:196
OpenALAudioSound::set_loop
void set_loop(bool loop=true)
Turns looping on and off.
Definition: openalAudioSound.cxx:246
OpenALAudioSound::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: openalAudioSound.cxx:708
AddHash::add_hash
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
MovieAudioCursor::seek
virtual void seek(double offset)
Skips to the specified offset within the file.
Definition: movieAudioCursor.cxx:133
OpenALAudioSound::status
AudioSound::SoundStatus status() const
Get status of the sound.
Definition: openalAudioSound.cxx:867
OpenALAudioSound::get_loop_count
unsigned long get_loop_count() const
Return how many times a sound will loop.
Definition: openalAudioSound.cxx:278
OpenALAudioSound::set_play_rate
void set_play_rate(PN_stdfloat play_rate=1.0f)
Sets the speed at which a sound plays back.
Definition: openalAudioSound.cxx:647
OpenALAudioSound::set_balance
void set_balance(PN_stdfloat balance_right=0.0)
-1.0 to 1.0 scale
Definition: openalAudioSound.cxx:627
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
OpenALAudioSound::set_time
void set_time(PN_stdfloat time=0.0)
The next time you call play, the sound will start from the specified offset.
Definition: openalAudioSound.cxx:563
OpenALAudioSound::set_3d_max_distance
void set_3d_max_distance(PN_stdfloat dist)
Set the distance that this sound stops falling off.
Definition: openalAudioSound.cxx:749
OpenALAudioSound::get_volume
PN_stdfloat get_volume() const
Gets the current volume of a sound.
Definition: openalAudioSound.cxx:619
OpenALAudioSound::length
PN_stdfloat length() const
Get length.
Definition: openalAudioSound.cxx:667
MovieAudioCursor::read_samples
void read_samples(int n, Datagram *dg)
Read audio samples from the stream into a Datagram.
Definition: movieAudioCursor.cxx:73
OpenALAudioSound::get_3d_max_distance
PN_stdfloat get_3d_max_distance() const
Get the distance that this sound stops falling off.
Definition: openalAudioSound.cxx:766
OpenALAudioManager
Definition: openalAudioManager.h:39
OpenALAudioSound::get_time
PN_stdfloat get_time() const
Gets the play position within the sound.
Definition: openalAudioSound.cxx:572
OpenALAudioSound::get_name
const std::string & get_name() const
Get name of sound file.
Definition: openalAudioSound.cxx:857
OpenALAudioSound::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.
Definition: openalAudioSound.cxx:682
MovieAudioCursor
A MovieAudio is actually any source that provides a sequence of audio samples.
Definition: movieAudioCursor.h:34
OpenALAudioSound::get_loop
bool get_loop() const
Returns whether looping is on or off.
Definition: openalAudioSound.cxx:255
MovieAudio
A MovieAudio is actually any source that provides a sequence of audio samples.
Definition: movieAudio.h:44
OpenALAudioSound::set_3d_min_distance
void set_3d_min_distance(PN_stdfloat dist)
Set the distance that this sound begins to fall off.
Definition: openalAudioSound.cxx:724
TrueClock::get_global_ptr
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:68
openalAudioManager.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OpenALAudioSound::get_3d_drop_off_factor
PN_stdfloat get_3d_drop_off_factor() const
Control the effect distance has on audability.
Definition: openalAudioSound.cxx:791
OpenALAudioSound::set_3d_drop_off_factor
void set_3d_drop_off_factor(PN_stdfloat factor)
Control the effect distance has on audability.
Definition: openalAudioSound.cxx:774