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 }
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
A MovieAudio is actually any source that provides a sequence of audio samples.
virtual void seek(double offset)
Skips to the specified offset within the file.
void read_samples(int n, Datagram *dg)
Read audio samples from the stream into a Datagram.
A MovieAudio is actually any source that provides a sequence of audio samples.
Definition: movieAudio.h:44
get_filename
Returns the movie's filename.
Definition: movieAudio.h:52
AudioSound::SoundStatus status() const
Get status of the sound.
void set_loop(bool loop=true)
Turns looping on and off.
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.
void set_3d_min_distance(PN_stdfloat dist)
Set the distance that this sound begins to fall off.
bool get_loop() const
Returns whether looping is on or off.
void set_3d_max_distance(PN_stdfloat dist)
Set the distance that this sound stops falling off.
PN_stdfloat get_time() const
Gets the play position within the sound.
void set_active(bool active=true)
Sets whether the sound is marked "active".
void play()
Plays a sound.
const std::string & get_name() const
Get name of sound file.
PN_stdfloat get_3d_drop_off_factor() const
Control the effect distance has on audability.
bool get_active() const
Returns whether the sound has been marked "active".
PN_stdfloat get_volume() const
Gets the current volume of a sound.
void stop()
Stop a sound.
void set_play_rate(PN_stdfloat play_rate=1.0f)
Sets the speed at which a sound plays back.
PN_stdfloat length() const
Get length.
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_drop_off_factor(PN_stdfloat factor)
Control the effect distance has on audability.
PN_stdfloat get_balance() const
-1.0 to 1.0 scale -1 should be all the way left.
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.
void set_balance(PN_stdfloat balance_right=0.0)
-1.0 to 1.0 scale
PN_stdfloat get_3d_min_distance() const
Get the distance that this sound begins to fall 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.
unsigned long get_loop_count() const
Return how many times a sound will loop.
Similar to MutexHolder, but for a reentrant mutex.
Definition: reMutexHolder.h:25
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:68
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.