00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 # include <simgear_config.h>
00030 #endif
00031
00032 #if defined( __APPLE__ )
00033 # include <OpenAL/alut.h>
00034 #else
00035 # include <AL/alut.h>
00036 #endif
00037
00038 #include <iostream>
00039 #include <algorithm>
00040
00041 #include "soundmgr_openal.hxx"
00042
00043 #include <simgear/structure/exception.hxx>
00044 #include <simgear/debug/logstream.hxx>
00045 #include <simgear/misc/sg_path.hxx>
00046 #include <simgear/math/SGMath.hxx>
00047
00048 extern bool isNaN(float *v);
00049
00050 #define MAX_SOURCES 128
00051
00052
00053
00054
00055
00056 int SGSoundMgr::_alut_init = 0;
00057
00058
00059 SGSoundMgr::SGSoundMgr() :
00060 _working(false),
00061 _active(false),
00062 _changed(true),
00063 _volume(0.0),
00064 _device(NULL),
00065 _context(NULL),
00066 _absolute_pos(SGVec3d::zeros()),
00067 _offset_pos(SGVec3d::zeros()),
00068 _base_pos(SGVec3d::zeros()),
00069 _geod_pos(SGGeod::fromCart(SGVec3d::zeros())),
00070 _velocity(SGVec3d::zeros()),
00071 _orientation(SGQuatd::zeros()),
00072 _bad_doppler(false),
00073 _renderer("unknown"),
00074 _vendor("unknown")
00075 {
00076 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
00077 if (_alut_init == 0) {
00078 if ( !alutInitWithoutContext(NULL, NULL) ) {
00079 testForALUTError("alut initialization");
00080 return;
00081 }
00082 }
00083 _alut_init++;
00084 #endif
00085 }
00086
00087
00088
00089 SGSoundMgr::~SGSoundMgr() {
00090
00091 stop();
00092 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
00093 _alut_init--;
00094 if (_alut_init == 0) {
00095 alutExit ();
00096 }
00097 #endif
00098 }
00099
00100
00101 void SGSoundMgr::init(const char *devname) {
00102
00103 SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
00104
00105 ALCdevice *device = alcOpenDevice(devname);
00106 if ( testForError(device, "Audio device not available, trying default") ) {
00107 device = alcOpenDevice(NULL);
00108 if (testForError(device, "Default Audio device not available.") ) {
00109 return;
00110 }
00111 }
00112
00113 _device = device;
00114 ALCcontext *context = alcCreateContext(device, NULL);
00115 testForALCError("context creation.");
00116 if ( testForError(context, "Unable to create a valid context.") ) {
00117 alcCloseDevice (device);
00118 return;
00119 }
00120
00121 if ( !alcMakeContextCurrent(context) ) {
00122 testForALCError("context initialization");
00123 alcDestroyContext (context);
00124 alcCloseDevice (device);
00125 return;
00126 }
00127
00128 if (_context != NULL)
00129 SG_LOG(SG_GENERAL, SG_ALERT, "context is already assigned");
00130 _context = context;
00131 _working = true;
00132
00133 _at_up_vec[0] = 0.0; _at_up_vec[1] = 0.0; _at_up_vec[2] = -1.0;
00134 _at_up_vec[3] = 0.0; _at_up_vec[4] = 1.0; _at_up_vec[5] = 0.0;
00135
00136 alListenerf( AL_GAIN, 0.0f );
00137 alListenerfv( AL_ORIENTATION, _at_up_vec );
00138 alListenerfv( AL_POSITION, SGVec3f::zeros().data() );
00139 alListenerfv( AL_VELOCITY, SGVec3f::zeros().data() );
00140
00141 alDopplerFactor(1.0);
00142 alDopplerVelocity(340.3);
00143
00144
00145
00146 alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
00147
00148 testForALError("listener initialization");
00149
00150
00151
00152 for (unsigned int i=0; i<MAX_SOURCES; i++) {
00153 ALuint source;
00154 ALenum error;
00155
00156 alGetError();
00157 alGenSources(1, &source);
00158 error = alGetError();
00159 if ( error == AL_NO_ERROR ) {
00160 _free_sources.push_back( source );
00161 }
00162 else break;
00163 }
00164
00165 _vendor = (const char *)alGetString(AL_VENDOR);
00166 _renderer = (const char *)alGetString(AL_RENDERER);
00167 if ( (_vendor != "OpenAL Community" && _vendor != "Apple Computer Inc.") ||
00168 (_renderer != "Software" && _renderer != "OpenAL Sample Implementation")
00169 )
00170 {
00171 _bad_doppler = true;
00172 }
00173
00174 if (_free_sources.size() == 0) {
00175 SG_LOG(SG_GENERAL, SG_ALERT, "Unable to grab any OpenAL sources!");
00176 }
00177 }
00178
00179 void SGSoundMgr::activate() {
00180 if ( _working ) {
00181 _active = true;
00182 sample_group_map_iterator sample_grp_current = _sample_groups.begin();
00183 sample_group_map_iterator sample_grp_end = _sample_groups.end();
00184 for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
00185 SGSampleGroup *sgrp = sample_grp_current->second;
00186 sgrp->activate();
00187 }
00188 }
00189 }
00190
00191
00192 void SGSoundMgr::stop() {
00193
00194
00195 sample_group_map_iterator sample_grp_current = _sample_groups.begin();
00196 sample_group_map_iterator sample_grp_end = _sample_groups.end();
00197 for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
00198 SGSampleGroup *sgrp = sample_grp_current->second;
00199 sgrp->stop();
00200 }
00201
00202
00203 for (unsigned int i=0; i<_free_sources.size(); i++) {
00204 ALuint source = _free_sources[i];
00205 alDeleteSources( 1 , &source );
00206 }
00207 _free_sources.clear();
00208
00209
00210 buffer_map_iterator buffers_current = _buffers.begin();
00211 buffer_map_iterator buffers_end = _buffers.end();
00212 for ( ; buffers_current != buffers_end; ++buffers_current ) {
00213 refUint ref = buffers_current->second;
00214 ALuint buffer = ref.id;
00215 alDeleteBuffers(1, &buffer);
00216 }
00217 _buffers.clear();
00218
00219 if (_working) {
00220 _working = false;
00221 _active = false;
00222 _context = alcGetCurrentContext();
00223 _device = alcGetContextsDevice(_context);
00224 alcDestroyContext(_context);
00225 alcCloseDevice(_device);
00226 _context = NULL;
00227
00228 _renderer = "unknown";
00229 _vendor = "unknown";
00230 }
00231 }
00232
00233 void SGSoundMgr::suspend() {
00234 if (_working) {
00235 sample_group_map_iterator sample_grp_current = _sample_groups.begin();
00236 sample_group_map_iterator sample_grp_end = _sample_groups.end();
00237 for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
00238 SGSampleGroup *sgrp = sample_grp_current->second;
00239 sgrp->stop();
00240 }
00241 _active = false;
00242 }
00243 }
00244
00245 void SGSoundMgr::resume() {
00246 if (_working) {
00247 sample_group_map_iterator sample_grp_current = _sample_groups.begin();
00248 sample_group_map_iterator sample_grp_end = _sample_groups.end();
00249 for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
00250 SGSampleGroup *sgrp = sample_grp_current->second;
00251 sgrp->resume();
00252 }
00253 _active = true;
00254 }
00255 }
00256
00257 void SGSoundMgr::bind ()
00258 {
00259 _free_sources.clear();
00260 _free_sources.reserve( MAX_SOURCES );
00261 _sources_in_use.clear();
00262 _sources_in_use.reserve( MAX_SOURCES );
00263 }
00264
00265
00266 void SGSoundMgr::unbind ()
00267 {
00268 _sample_groups.clear();
00269
00270
00271 for (unsigned int i=0; i<_free_sources.size(); i++) {
00272 ALuint source = _free_sources[i];
00273 alDeleteSources( 1 , &source );
00274 }
00275
00276 _free_sources.clear();
00277 _sources_in_use.clear();
00278 }
00279
00280
00281 void SGSoundMgr::update( double dt ) {
00282 if (_active) {
00283 alcSuspendContext(_context);
00284
00285 if (_changed) {
00286 update_pos_and_orientation();
00287 }
00288
00289 sample_group_map_iterator sample_grp_current = _sample_groups.begin();
00290 sample_group_map_iterator sample_grp_end = _sample_groups.end();
00291 for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) {
00292 SGSampleGroup *sgrp = sample_grp_current->second;
00293 sgrp->update(dt);
00294 }
00295
00296 if (_changed) {
00297 #if 0
00298 if (isNaN(_at_up_vec)) printf("NaN in listener orientation\n");
00299 if (isNaN(toVec3f(_absolute_pos).data())) printf("NaN in listener position\n");
00300 if (isNaN(_velocity.data())) printf("NaN in listener velocity\n");
00301 #endif
00302 alListenerf( AL_GAIN, _volume );
00303 alListenerfv( AL_ORIENTATION, _at_up_vec );
00304
00305
00306 SGQuatd hlOr = SGQuatd::fromLonLat( _geod_pos );
00307 SGVec3d velocity = SGVec3d::zeros();
00308 if ( _velocity[0] || _velocity[1] || _velocity[2] ) {
00309 velocity = hlOr.backTransform(_velocity*SG_FEET_TO_METER);
00310 }
00311
00312 if ( _bad_doppler ) {
00313 velocity *= 100.0f;
00314 }
00315
00316 alListenerfv( AL_VELOCITY, toVec3f(velocity).data() );
00317
00318 testForALError("update");
00319 _changed = false;
00320 }
00321
00322 alcProcessContext(_context);
00323 }
00324 }
00325
00326
00327 bool SGSoundMgr::add( SGSampleGroup *sgrp, const string& refname )
00328 {
00329 sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
00330 if ( sample_grp_it != _sample_groups.end() ) {
00331
00332 return false;
00333 }
00334
00335 if (_active) sgrp->activate();
00336 _sample_groups[refname] = sgrp;
00337
00338 return true;
00339 }
00340
00341
00342
00343 bool SGSoundMgr::remove( const string &refname )
00344 {
00345 sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
00346 if ( sample_grp_it == _sample_groups.end() ) {
00347
00348 return false;
00349 }
00350
00351 _sample_groups.erase( sample_grp_it );
00352
00353 return true;
00354 }
00355
00356
00357
00358 bool SGSoundMgr::exists( const string &refname ) {
00359 sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
00360 if ( sample_grp_it == _sample_groups.end() ) {
00361
00362 return false;
00363 }
00364
00365 return true;
00366 }
00367
00368
00369
00370
00371 SGSampleGroup *SGSoundMgr::find( const string &refname, bool create ) {
00372 sample_group_map_iterator sample_grp_it = _sample_groups.find( refname );
00373 if ( sample_grp_it == _sample_groups.end() ) {
00374
00375 if (create) {
00376 SGSampleGroup* sgrp = new SGSampleGroup(this, refname);
00377 add( sgrp, refname );
00378 return sgrp;
00379 }
00380 else
00381 return NULL;
00382 }
00383
00384 return sample_grp_it->second;
00385 }
00386
00387
00388 void SGSoundMgr::set_volume( float v )
00389 {
00390 _volume = v;
00391 if (_volume > 1.0) _volume = 1.0;
00392 if (_volume < 0.0) _volume = 0.0;
00393 _changed = true;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 unsigned int SGSoundMgr::request_source()
00406 {
00407 unsigned int source = NO_SOURCE;
00408
00409 if (_free_sources.size() > 0) {
00410 source = _free_sources.back();
00411 _free_sources.pop_back();
00412 _sources_in_use.push_back(source);
00413 }
00414 else
00415 SG_LOG( SG_GENERAL, SG_INFO, "No more free sources available\n");
00416
00417 return source;
00418 }
00419
00420
00421 void SGSoundMgr::release_source( unsigned int source )
00422 {
00423 vector<ALuint>::iterator it;
00424
00425 it = std::find(_sources_in_use.begin(), _sources_in_use.end(), source);
00426 if ( it != _sources_in_use.end() ) {
00427 ALint result;
00428
00429 alGetSourcei( source, AL_SOURCE_STATE, &result );
00430 if ( result == AL_PLAYING )
00431 alSourceStop( source );
00432 testForALError("release source");
00433
00434 alSourcei( source, AL_BUFFER, 0 );
00435 _free_sources.push_back( source );
00436 _sources_in_use.erase( it );
00437 }
00438 }
00439
00440 unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
00441 {
00442 ALuint buffer = NO_BUFFER;
00443
00444 if ( !sample->is_valid_buffer() ) {
00445
00446 string sample_name = sample->get_sample_name();
00447 void *sample_data = NULL;
00448
00449
00450 buffer_map_iterator buffer_it = _buffers.find( sample_name );
00451 if ( buffer_it != _buffers.end() ) {
00452 buffer_it->second.refctr++;
00453 buffer = buffer_it->second.id;
00454 sample->set_buffer( buffer );
00455 return buffer;
00456 }
00457
00458
00459 if ( sample->is_file() ) {
00460 int freq, format;
00461 size_t size;
00462 bool res;
00463
00464 res = load(sample_name, &sample_data, &format, &size, &freq);
00465 if (res == false) return buffer;
00466
00467 sample->set_frequency( freq );
00468 sample->set_format( format );
00469 sample->set_size( size );
00470 }
00471 else
00472 sample_data = sample->get_data();
00473
00474
00475 alGenBuffers(1, &buffer);
00476 if ( !testForALError("generate buffer") ) {
00477
00478
00479 ALenum format = sample->get_format();
00480 ALsizei size = sample->get_size();
00481 ALsizei freq = sample->get_frequency();
00482 alBufferData( buffer, format, sample_data, size, freq );
00483
00484 if ( sample->is_file() ) free(sample_data);
00485
00486 if ( !testForALError("buffer add data") ) {
00487 sample->set_buffer(buffer);
00488 _buffers[sample_name] = refUint(buffer);
00489 }
00490 }
00491 }
00492 else {
00493 buffer = sample->get_buffer();
00494 }
00495
00496 return buffer;
00497 }
00498
00499 void SGSoundMgr::release_buffer(SGSoundSample *sample)
00500 {
00501 string sample_name = sample->get_sample_name();
00502 buffer_map_iterator buffer_it = _buffers.find( sample_name );
00503 if ( buffer_it == _buffers.end() ) {
00504
00505 return;
00506 }
00507
00508 sample->no_valid_buffer();
00509 buffer_it->second.refctr--;
00510 if (buffer_it->second.refctr == 0) {
00511 ALuint buffer = buffer_it->second.id;
00512 alDeleteBuffers(1, &buffer);
00513 _buffers.erase( buffer_it );
00514 testForALError("release buffer");
00515 }
00516 }
00517
00518 void SGSoundMgr::update_pos_and_orientation() {
00530 SGVec3d sgv_at = _orientation.backTransform(-SGVec3d::e3());
00531 SGVec3d sgv_up = _orientation.backTransform(SGVec3d::e2());
00532 _at_up_vec[0] = sgv_at[0];
00533 _at_up_vec[1] = sgv_at[1];
00534 _at_up_vec[2] = sgv_at[2];
00535 _at_up_vec[3] = sgv_up[0];
00536 _at_up_vec[4] = sgv_up[1];
00537 _at_up_vec[5] = sgv_up[2];
00538
00539
00540
00541
00542 _absolute_pos = _base_pos;
00543 }
00544
00545 bool SGSoundMgr::load(string &samplepath, void **dbuf, int *fmt,
00546 size_t *sz, int *frq )
00547 {
00548 if ( !_working ) return false;
00549
00550 ALenum format;
00551 ALsizei size;
00552 ALsizei freq;
00553 ALvoid *data;
00554
00555 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
00556 ALfloat freqf;
00557
00558 alGetError();
00559 alcGetError(_device);
00560 data = alutLoadMemoryFromFile(samplepath.c_str(), &format, &size, &freqf );
00561 freq = (ALsizei)freqf;
00562 int error = alutGetError();
00563 if (data == NULL || error != ALUT_ERROR_NO_ERROR) {
00564 string msg = "Failed to load wav file: ";
00565 msg.append(alutGetErrorString(error));
00566 throw sg_io_exception(msg.c_str(), sg_location(samplepath));
00567 return false;
00568 }
00569
00570 #else
00571 ALbyte *fname = (ALbyte *)samplepath.c_str();
00572 # if defined (__APPLE__)
00573 alutLoadWAVFile( fname, &format, &data, &size, &freq );
00574 # else
00575 ALboolean loop;
00576 alutLoadWAVFile( fname, &format, &data, &size, &freq, &loop );
00577 # endif
00578 ALenum error = alGetError();
00579 if ( error != AL_NO_ERROR ) {
00580 string msg = "Failed to load wav file: ";
00581 const ALchar *errorString = alGetString(error);
00582 if (errorString) {
00583 msg.append(errorString);
00584 } else {
00585
00586
00587
00588
00589 stringstream ss;
00590 ss << alGetString(alGetError()) << "(" << error << ")";
00591 msg.append(ss.str());
00592 }
00593 throw sg_io_exception(msg.c_str(), sg_location(samplepath));
00594 return false;
00595 }
00596 #endif
00597
00598 *dbuf = (void *)data;
00599 *fmt = (int)format;
00600 *sz = (size_t)size;
00601 *frq = (int)freq;
00602
00603 return true;
00604 }
00605
00606 vector<const char*> SGSoundMgr::get_available_devices()
00607 {
00608 vector<const char*> devices;
00609 const ALCchar *s;
00610
00611 if (alcIsExtensionPresent(NULL, "ALC_enumerate_all_EXT") == AL_TRUE) {
00612 s = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
00613 } else {
00614 s = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
00615 }
00616
00617 if (s) {
00618 ALCchar *nptr, *ptr = (ALCchar *)s;
00619
00620 nptr = ptr;
00621 while (*(nptr += strlen(ptr)+1) != 0)
00622 {
00623 devices.push_back(ptr);
00624 ptr = nptr;
00625 }
00626 devices.push_back(ptr);
00627 }
00628
00629 return devices;
00630 }
00631
00632
00633 bool SGSoundMgr::testForError(void *p, string s)
00634 {
00635 if (p == NULL) {
00636 SG_LOG( SG_GENERAL, SG_ALERT, "Error: " << s);
00637 return true;
00638 }
00639 return false;
00640 }
00641
00642
00643 bool SGSoundMgr::testForALError(string s)
00644 {
00645 ALenum error = alGetError();
00646 if (error != AL_NO_ERROR) {
00647 SG_LOG( SG_GENERAL, SG_ALERT, "AL Error (sound manager): "
00648 << alGetString(error) << " at " << s);
00649 return true;
00650 }
00651 return false;
00652 }
00653
00654 bool SGSoundMgr::testForALCError(string s)
00655 {
00656 ALCenum error;
00657 error = alcGetError(_device);
00658 if (error != ALC_NO_ERROR) {
00659 SG_LOG( SG_GENERAL, SG_ALERT, "ALC Error (sound manager): "
00660 << alcGetString(_device, error) << " at "
00661 << s);
00662 return true;
00663 }
00664 return false;
00665 }
00666
00667 bool SGSoundMgr::testForALUTError(string s)
00668 {
00669 #if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
00670 ALenum error;
00671 error = alutGetError ();
00672 if (error != ALUT_ERROR_NO_ERROR) {
00673 SG_LOG( SG_GENERAL, SG_ALERT, "ALUT Error (sound manager): "
00674 << alutGetErrorString(error) << " at "
00675 << s);
00676 return true;
00677 }
00678 #endif
00679 return false;
00680 }