Panda3D
Loading...
Searching...
No Matches
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
20TypeHandle 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
35OpenALAudioSound::
36OpenALAudioSound(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 */
90OpenALAudioSound::
91~OpenALAudioSound() {
92 cleanup();
93}
94
95/**
96 * Disables the sound forever. Releases resources and detaches the sound from
97 * its audio manager.
98 */
99void OpenALAudioSound::
100cleanup() {
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 */
119play() {
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 */
196stop() {
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 */
229void OpenALAudioSound::
230finished() {
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 */
246set_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 */
255get_loop() const {
256 return (_loop_count == 0);
257}
258
259/**
260 *
261 */
262void OpenALAudioSound::
263set_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 */
278get_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 */
289void OpenALAudioSound::
290restart_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 */
311void OpenALAudioSound::
312queue_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 */
337ALuint OpenALAudioSound::
338make_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 */
371int OpenALAudioSound::
372read_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 */
424void OpenALAudioSound::
425correct_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 */
458void OpenALAudioSound::
459pull_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 */
516void OpenALAudioSound::
517push_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 */
563set_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 */
572get_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 */
583void OpenALAudioSound::
584cache_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 */
602set_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 */
619get_volume() const {
620 return _volume;
621}
622
623/**
624 * -1.0 to 1.0 scale
625 */
627set_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 */
636get_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 */
647set_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 */
658PN_stdfloat OpenALAudioSound::
659get_play_rate() const {
660 return _play_rate;
661}
662
663/**
664 * Get length
665 */
667length() 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 */
682set_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 */
708get_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 */
724set_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 */
741get_3d_min_distance() const {
742 return _min_dist;
743}
744
745/**
746 * Set the distance that this sound stops falling off
747 */
749set_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 */
766get_3d_max_distance() const {
767 return _max_dist;
768}
769
770/**
771 * Control the effect distance has on audability. Defaults to 1.0
772 */
774set_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 */
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 */
801set_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 */
833get_active() const {
834 return _active;
835}
836
837/**
838 *
839 */
840void OpenALAudioSound::
841set_finished_event(const std::string& event) {
842 _finished_event = event;
843}
844
845/**
846 *
847 */
848const std::string& OpenALAudioSound::
849get_finished_event() const {
850 return _finished_event;
851}
852
853/**
854 * Get name of sound file
855 */
856const std::string& OpenALAudioSound::
857get_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 */
866AudioSound::SoundStatus OpenALAudioSound::
867status() 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.
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.