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