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