28 #ifndef ALC_DEFAULT_ALL_DEVICES_SPECIFIER 29 #define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 32 #ifndef ALC_ALL_DEVICES_SPECIFIER 33 #define ALC_ALL_DEVICES_SPECIFIER 0x1013 41 ReMutex OpenALAudioManager::_lock;
42 int OpenALAudioManager::_active_managers = 0;
43 bool OpenALAudioManager::_openal_active =
false;
44 ALCdevice* OpenALAudioManager::_device =
nullptr;
45 ALCcontext* OpenALAudioManager::_context =
nullptr;
56 void al_audio_errcheck(
const char *context) {
57 ALenum result = alGetError();
58 if (result != AL_NO_ERROR) {
59 audio_error(context <<
": " << alGetString(result) );
63 void alc_audio_errcheck(
const char *context,ALCdevice* device) {
64 ALCenum result = alcGetError(device);
65 if (result != ALC_NO_ERROR) {
66 audio_error(context <<
": " << alcGetString(device,result) );
74 audio_debug(
"Create_OpenALAudioManager()");
83 OpenALAudioManager() {
85 if (_managers ==
nullptr) {
86 _managers =
new Managers;
87 _al_sources =
new SourceCache;
90 _managers->insert(
this);
92 _cleanup_required =
true;
93 _active = audio_active;
94 _volume = audio_volume;
97 _cache_limit = audio_cache_limit;
99 _concurrent_sound_limit = 0;
103 _distance_factor = 1;
104 _drop_off_factor = 1;
123 if (_active_managers == 0 || !_openal_active) {
125 string dev_name = select_audio_device();
127 if (!dev_name.empty()) {
129 audio_cat.info() <<
"Using OpenAL device " << dev_name <<
"\n";
130 _device = alcOpenDevice(dev_name.c_str());
132 if (_device ==
nullptr) {
134 <<
"Couldn't open OpenAL device \"" << dev_name <<
"\", falling back to default device\n";
137 audio_cat.info() <<
"Using default OpenAL device\n";
140 if (_device ==
nullptr) {
142 _device = alcOpenDevice(
nullptr);
144 if (_device ==
nullptr && dev_name !=
"OpenAL Soft") {
146 _device = alcOpenDevice(
"OpenAL Soft");
148 if (_device ==
nullptr) {
150 <<
"Couldn't open default OpenAL device\n";
155 if (_device !=
nullptr) {
157 alcGetError(_device);
158 _context = alcCreateContext(_device,
nullptr);
159 alc_audio_errcheck(
"alcCreateContext(_device, NULL)", _device);
160 if (_context !=
nullptr) {
161 _openal_active =
true;
169 nassertv(_active_managers>0);
171 if (!_device || !_context) {
172 audio_error(
"OpenALAudioManager: No open device or context");
175 alcGetError(_device);
176 alcMakeContextCurrent(_context);
177 alc_audio_errcheck(
"alcMakeContextCurrent(_context)", _device);
184 if (audio_cat.is_debug()) {
186 <<
"ALC_DEVICE_SPECIFIER:" << alcGetString(_device, ALC_DEVICE_SPECIFIER) << endl;
190 if (audio_cat.is_debug()) {
191 audio_cat.debug() <<
"AL_RENDERER:" << alGetString(AL_RENDERER) << endl;
192 audio_cat.debug() <<
"AL_VENDOR:" << alGetString(AL_VENDOR) << endl;
193 audio_cat.debug() <<
"AL_VERSION:" << alGetString(AL_VERSION) << endl;
201 ~OpenALAudioManager() {
203 nassertv(_managers !=
nullptr);
204 Managers::iterator mi = _managers->find(
this);
205 nassertv(mi != _managers->end());
206 _managers->erase(mi);
219 if (_managers !=
nullptr) {
220 Managers::iterator mi;
221 for (mi = _managers->begin(); mi != _managers->end(); ++mi) {
226 nassertv(_active_managers == 0);
243 string OpenALAudioManager::
244 select_audio_device() {
245 string selected_device = openal_device;
247 const char *devices =
nullptr;
250 if (alcIsExtensionPresent(
nullptr,
"ALC_ENUMERATE_ALL_EXT") == AL_TRUE) {
251 string default_device = alcGetString(
nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
252 devices = (
const char *)alcGetString(
nullptr, ALC_ALL_DEVICES_SPECIFIER);
255 audio_cat.debug() <<
"All OpenAL devices:\n";
258 string device(devices);
259 devices += device.size() + 1;
261 if (audio_cat.is_debug()) {
262 if (device == selected_device) {
263 audio_cat.debug() <<
" " << device <<
" [selected]\n";
264 }
else if (device == default_device) {
265 audio_cat.debug() <<
" " << device <<
" [default]\n";
267 audio_cat.debug() <<
" " << device <<
"\n";
273 audio_cat.debug() <<
"ALC_ENUMERATE_ALL_EXT not supported\n";
278 if (alcIsExtensionPresent(
nullptr,
"ALC_ENUMERATION_EXT") == AL_TRUE) {
279 string default_device = alcGetString(
nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
280 devices = (
const char *)alcGetString(
nullptr, ALC_DEVICE_SPECIFIER);
283 audio_cat.debug() <<
"OpenAL drivers:\n";
286 string device(devices);
287 devices += device.size() + 1;
289 if (selected_device.empty() && device ==
"OpenAL Soft" &&
290 default_device ==
"Generic Software") {
292 selected_device =
"OpenAL Soft";
295 if (audio_cat.is_debug()) {
296 if (device == selected_device) {
297 audio_cat.debug() <<
" " << device <<
" [selected]\n";
298 }
else if (device == default_device) {
299 audio_cat.debug() <<
" " << device <<
" [default]\n";
301 audio_cat.debug() <<
" " << device <<
"\n";
307 audio_cat.debug() <<
"ALC_ENUMERATION_EXT not supported\n";
310 return selected_device;
317 void OpenALAudioManager::
318 make_current()
const {
327 bool OpenALAudioManager::
330 int channels = source->audio_channels();
331 if ((channels != 1)&&(channels != 2)) {
332 audio_error(
"Currently, only mono and stereo are supported.");
343 bool OpenALAudioManager::
346 if (mode == SM_stream) {
350 if (source->get_source()->get_filename().empty()) {
354 if (source->
ready() != 0x40000000) {
358 if (source->length() > 3600.0) {
362 int channels = source->audio_channels();
363 int samples = (int)(source->length() * source->audio_rate());
364 int bytes = samples * channels * 2;
365 if ((mode == SM_heuristic)&&(bytes > audio_preload_threshold)) {
378 OpenALAudioManager::SoundData *OpenALAudioManager::
386 if (mode != SM_stream) {
387 SampleCache::iterator lsmi=_sample_cache.find(path);
388 if (lsmi != _sample_cache.end()) {
389 SoundData *sd = (*lsmi).second;
390 increment_client_count(sd);
395 if (mode != SM_sample) {
396 ExpirationQueue::iterator exqi;
397 for (exqi=_expiring_streams.begin(); exqi!=_expiring_streams.end(); exqi++) {
398 SoundData *sd = (SoundData*)(*exqi);
399 if (sd->_movie->get_filename() == path) {
400 increment_client_count(sd);
408 if (stream ==
nullptr) {
409 audio_error(
"Cannot open file: "<<path);
413 if (!can_use_audio(stream)) {
414 audio_error(
"File is not in usable format: "<<path);
418 SoundData *sd =
new SoundData();
419 sd->_client_count = 1;
422 sd->_rate = stream->audio_rate();
423 sd->_channels = stream->audio_channels();
424 sd->_length = stream->length();
425 audio_debug(
"Creating: " << sd->_movie->get_filename().get_basename());
426 audio_debug(
" - Rate: " << sd->_rate);
427 audio_debug(
" - Channels: " << sd->_channels);
428 audio_debug(
" - Length: " << sd->_length);
430 if (should_load_audio(stream, mode)) {
431 audio_debug(path.
get_basename() <<
": loading as sample");
435 alGenBuffers(1, &sd->_sample);
436 al_audio_errcheck(
"alGenBuffers");
437 if (sd->_sample == 0) {
438 audio_error(
"Could not create an OpenAL buffer object");
442 int channels = stream->audio_channels();
443 int samples = (int)(stream->length() * stream->audio_rate());
444 int16_t *data =
new int16_t[samples * channels];
445 stream->read_samples(samples, data);
446 alBufferData(sd->_sample,
447 (channels>1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
448 data, samples * channels * 2, stream->audio_rate());
450 int err = alGetError();
451 if (err != AL_NO_ERROR) {
452 audio_error(
"could not fill OpenAL buffer object with data");
456 _sample_cache.insert(SampleCache::value_type(path, sd));
458 audio_debug(path.
get_basename() <<
": loading as stream");
459 sd->_stream = stream;
469 get_sound(
MovieAudio *sound,
bool positional,
int mode) {
472 return get_null_sound();
480 return get_null_sound();
483 _all_sounds.insert(oas);
492 get_sound(
const Filename &file_name,
bool positional,
int mode) {
495 return get_null_sound();
503 audio_error(
"get_sound - invalid filename");
515 return get_null_sound();
518 _all_sounds.insert(oas);
536 SampleCache::iterator sci = _sample_cache.find(path);
537 if (sci == _sample_cache.end()) {
538 sci = _sample_cache.find(file_name);
540 if (sci != _sample_cache.end()) {
541 SoundData *sd = (*sci).second;
542 if (sd->_client_count == 0) {
543 _expiring_samples.erase(sd->_expire);
544 _sample_cache.erase(sci);
549 ExpirationQueue::iterator exqi;
550 for (exqi = _expiring_streams.begin(); exqi != _expiring_streams.end();) {
551 SoundData *sd = (SoundData *)(*exqi);
552 if (sd->_client_count == 0) {
553 if (sd->_movie->get_filename() == path ||
554 sd->_movie->get_filename() == file_name) {
555 exqi = _expiring_streams.erase(exqi);
570 discard_excess_cache(0);
580 discard_excess_cache(count);
586 unsigned int OpenALAudioManager::
587 get_cache_limit()
const {
594 void OpenALAudioManager::
597 AllSounds::iterator ai = _all_sounds.find(audioSound);
598 if (ai != _all_sounds.end()) {
599 _all_sounds.erase(ai);
609 if (_volume!=volume) {
613 AllSounds::iterator i=_all_sounds.begin();
614 for (; i!=_all_sounds.end(); ++i) {
615 (**i).set_volume((**i).get_volume());
644 if (_play_rate!=play_rate) {
645 _play_rate = play_rate;
647 AllSounds::iterator i=_all_sounds.begin();
648 for (; i!=_all_sounds.end(); ++i) {
649 (**i).set_play_rate((**i).get_play_rate());
668 if (_active!=active) {
671 AllSounds::iterator i=_all_sounds.begin();
672 for (; i!=_all_sounds.end(); ++i) {
673 (**i).set_active(_active);
681 bool OpenALAudioManager::
698 audio_3d_set_listener_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz, PN_stdfloat fx, PN_stdfloat fy, PN_stdfloat fz, PN_stdfloat ux, PN_stdfloat uy, PN_stdfloat uz) {
710 _forward_up[2] = -fy;
714 _forward_up[5] = -uy;
720 alListenerfv(AL_POSITION,_position);
721 al_audio_errcheck(
"alListerfv(AL_POSITION)");
722 alListenerfv(AL_VELOCITY,_velocity);
723 al_audio_errcheck(
"alListerfv(AL_VELOCITY)");
724 alListenerfv(AL_ORIENTATION,_forward_up);
725 al_audio_errcheck(
"alListerfv(AL_ORIENTATION)");
732 audio_3d_get_listener_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz, PN_stdfloat *fx, PN_stdfloat *fy, PN_stdfloat *fz, PN_stdfloat *ux, PN_stdfloat *uy, PN_stdfloat *uz) {
742 *fx = _forward_up[0];
743 *fy = -_forward_up[2];
744 *fz = _forward_up[1];
746 *ux = _forward_up[3];
747 *uy = -_forward_up[5];
748 *uz = _forward_up[4];
760 _distance_factor = factor;
766 if (_distance_factor>0) {
767 alSpeedOfSound(343.3*_distance_factor);
768 al_audio_errcheck(
"alSpeedOfSound()");
771 alDopplerFactor(_doppler_factor);
772 al_audio_errcheck(
"alDopplerFactor()");
774 audio_debug(
"can't set speed of sound if distance_factor <=0.0, setting doppler factor to 0.0 instead");
775 alDopplerFactor(0.0);
776 al_audio_errcheck(
"alDopplerFactor()");
779 AllSounds::iterator i=_all_sounds.begin();
780 for (; i!=_all_sounds.end(); ++i) {
781 (**i).set_3d_min_distance((**i).get_3d_min_distance());
782 (**i).set_3d_max_distance((**i).get_3d_max_distance());
791 return _distance_factor;
800 _doppler_factor = factor;
805 alDopplerFactor(_doppler_factor);
806 al_audio_errcheck(
"alDopplerFactor()");
812 PN_stdfloat OpenALAudioManager::
813 audio_3d_get_doppler_factor()
const {
814 return _doppler_factor;
823 _drop_off_factor = factor;
825 AllSounds::iterator i=_all_sounds.begin();
826 for (; i!=_all_sounds.end(); ++i) {
827 (**i).set_3d_drop_off_factor((**i).get_3d_drop_off_factor());
834 PN_stdfloat OpenALAudioManager::
835 audio_3d_get_drop_off_factor()
const {
836 return _drop_off_factor;
844 void OpenALAudioManager::
850 if (audio->_source) {
858 if (_concurrent_sound_limit) {
859 reduce_sounds_playing_to(_concurrent_sound_limit-1);
863 if (_al_sources->empty()) {
866 alGenSources(1,&source);
867 ALenum result = alGetError();
868 if (result!=AL_NO_ERROR) {
869 audio_error(
"alGenSources(): " << alGetString(result) );
872 reduce_sounds_playing_to(_sounds_playing.size()-1);
877 if (!source && !_al_sources->empty()) {
878 source = *(_al_sources->begin());
879 _al_sources->erase(source);
882 audio->_source = source;
885 _sounds_playing.insert(audio);
892 void OpenALAudioManager::
895 if (audio->_source) {
896 _al_sources->insert(audio->_source);
899 _sounds_playing.erase(audio);
905 void OpenALAudioManager::
906 set_concurrent_sound_limit(
unsigned int limit) {
908 _concurrent_sound_limit = limit;
909 reduce_sounds_playing_to(_concurrent_sound_limit);
915 unsigned int OpenALAudioManager::
916 get_concurrent_sound_limit()
const {
917 return _concurrent_sound_limit;
923 void OpenALAudioManager::
924 reduce_sounds_playing_to(
unsigned int count) {
930 int limit = _sounds_playing.size() - count;
931 while (limit-- > 0) {
932 SoundsPlaying::iterator sound = _sounds_playing.begin();
933 nassertv(sound != _sounds_playing.end());
950 reduce_sounds_playing_to(0);
964 SoundsPlaying sounds_finished;
967 SoundsPlaying::iterator i=_sounds_playing.begin();
968 for (; i!=_sounds_playing.end(); ++i) {
970 sound->pull_used_buffers();
971 sound->push_fresh_buffers();
972 sound->restart_stalled_audio();
973 sound->cache_time(rtc);
974 if ((sound->_source == 0)||
975 ((sound->_stream_queued.size() == 0)&&
976 (sound->_loops_completed >= sound->_playing_loops))) {
977 sounds_finished.insert(*i);
981 i=sounds_finished.begin();
982 for (; i!=sounds_finished.end(); ++i) {
992 void OpenALAudioManager::
995 if (!_cleanup_required) {
1001 AllSounds sounds(_all_sounds);
1002 AllSounds::iterator ai;
1003 for (ai = sounds.begin(); ai != sounds.end(); ++ai) {
1009 nassertv(_active_managers > 0);
1012 if (_active_managers == 0) {
1013 if (_openal_active) {
1017 sources =
new ALuint[_al_sources->size()];
1018 for (SourceCache::iterator si = _al_sources->begin(); si!=_al_sources->end(); ++si) {
1023 alDeleteSources(_al_sources->size(),sources);
1024 al_audio_errcheck(
"alDeleteSources()");
1026 _al_sources->clear();
1029 alcGetError(_device);
1030 alcMakeContextCurrent(
nullptr);
1031 alc_audio_errcheck(
"alcMakeContextCurrent(NULL)",_device);
1033 alcDestroyContext(_context);
1034 alc_audio_errcheck(
"alcDestroyContext(_context)",_device);
1038 audio_debug(
"Going to try to close openAL");
1039 alcCloseDevice(_device);
1042 audio_debug(
"openAL Closed");
1045 _openal_active =
false;
1048 _cleanup_required =
false;
1054 OpenALAudioManager::SoundData::
1069 OpenALAudioManager::SoundData::
1073 if (_manager->_is_valid) {
1074 _manager->make_current();
1075 _manager->delete_buffer(_sample);
1085 void OpenALAudioManager::
1086 increment_client_count(SoundData *sd) {
1088 sd->_client_count += 1;
1089 audio_debug(
"Incrementing: " << sd->_movie->get_filename().get_basename() <<
" " << sd->_client_count);
1090 if (sd->_client_count == 1) {
1092 _expiring_samples.erase(sd->_expire);
1094 _expiring_streams.erase(sd->_expire);
1104 void OpenALAudioManager::
1105 decrement_client_count(SoundData *sd) {
1107 sd->_client_count -= 1;
1108 audio_debug(
"Decrementing: " << sd->_movie->get_filename().get_basename() <<
" " << sd->_client_count);
1109 if (sd->_client_count == 0) {
1111 _expiring_samples.push_back(sd);
1112 sd->_expire = _expiring_samples.end();
1115 _expiring_streams.push_back(sd);
1116 sd->_expire = _expiring_streams.end();
1119 discard_excess_cache(_cache_limit);
1127 void OpenALAudioManager::
1128 discard_excess_cache(
int sample_limit) {
1130 int stream_limit = 5;
1132 while (((
int)_expiring_samples.size()) > sample_limit) {
1133 SoundData *sd = (SoundData*)(_expiring_samples.front());
1134 nassertv(sd->_client_count == 0);
1135 nassertv(sd->_expire == _expiring_samples.begin());
1136 _expiring_samples.pop_front();
1137 _sample_cache.erase(_sample_cache.find(sd->_movie->get_filename()));
1138 audio_debug(
"Expiring: " << sd->_movie->get_filename().get_basename());
1142 while (((
int)_expiring_streams.size()) > stream_limit) {
1143 SoundData *sd = (SoundData*)(_expiring_streams.front());
1144 nassertv(sd->_client_count == 0);
1145 nassertv(sd->_expire == _expiring_streams.begin());
1146 _expiring_streams.pop_front();
1147 audio_debug(
"Expiring: " << sd->_movie->get_filename().get_basename());
1160 void OpenALAudioManager::
1161 delete_buffer(ALuint buffer) {
1168 alDeleteBuffers(1, &buffer);
1169 error = alGetError();
1171 if (error == AL_NO_ERROR) {
1174 }
else if (error != AL_INVALID_OPERATION) {
1177 }
else if (tries >= openal_buffer_delete_retries.
get_value()) {
1188 audio_error(
"failed to delete a buffer: " << alGetString(error) );
get_filename
Returns the movie's filename.
virtual void audio_3d_get_listener_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz, PN_stdfloat *fx, PN_stdfloat *fy, PN_stdfloat *fz, PN_stdfloat *ux, PN_stdfloat *uy, PN_stdfloat *uz)
Get position of the "ear" that picks up 3d sounds.
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AudioManager * Create_OpenALAudioManager()
Factory Function.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void set_cache_limit(unsigned int count)
Set the number of sounds that the cache can hold.
A hierarchy of directories and files that appears to be one continuous file system,...
virtual void set_volume(PN_stdfloat)
Sets listener gain.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PN_stdfloat get_play_rate() const
get the overall speed/pitch/play rate
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
virtual void clear_cache()
Clear out the sound cache.
virtual PN_stdfloat get_volume() const
Gets listener gain.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void stop_all_sounds()
Stop playback on all sounds managed by this manager.
virtual void audio_3d_set_doppler_factor(PN_stdfloat factor)
Exaggerates or diminishes the Doppler effect.
get_value
Returns the variable's value.
virtual void audio_3d_set_drop_off_factor(PN_stdfloat factor)
Control the effect distance has on audability.
virtual bool is_valid()
This is mostly for debugging, but it it could be used to detect errors in a release build if you don'...
virtual void uncache_sound(const Filename &)
Deletes a sample from the expiration queues.
virtual void audio_3d_set_listener_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat xy, PN_stdfloat xz, PN_stdfloat fx, PN_stdfloat fy, PN_stdfloat fz, PN_stdfloat ux, PN_stdfloat uy, PN_stdfloat uz)
Set position of the "ear" that picks up 3d sounds NOW LISTEN UP!!! THIS IS IMPORTANT!...
The name of a file, such as a texture file or an Egg file.
void set_play_rate(PN_stdfloat play_rate)
set the overall play rate
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A MovieAudio is actually any source that provides a sequence of audio samples.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
PT(AudioSound) OpenALAudioManager
This is what creates a sound instance.
Similar to MutexHolder, but for a reentrant mutex.
static void sleep(double seconds)
Suspends the current thread for at least the indicated amount of time.
virtual PN_stdfloat audio_3d_get_distance_factor() const
Get value in units per meter.
std::string get_basename() const
Returns the basename part of the filename.
virtual void audio_3d_set_distance_factor(PN_stdfloat factor)
Set value in units per meter WARNING: OpenAL has no distance factor but we use this as a scale on the...
virtual void update()
Perform all per-frame update functions.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void set_active(bool)
Turn on/off Warning: not implemented.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL set.
TypeHandle is the identifier used to differentiate C++ class types.
A MovieAudio is actually any source that provides a sequence of audio samples.
virtual void shutdown()
Call this at exit time to shut down the audio system.
virtual int ready() const
Returns the number of audio samples that are ready to read.
get_value
Returns the variable's value.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.