X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fsound%2Fsample_group.cxx;h=70df9aa1b6cbe88ff33e466ec71849ecc37157a3;hb=105438fc581a9b1d65a9309f6e845f9558f3a505;hp=43235d8684b7e48e1bc1b7de6c619095671c6662;hpb=1ac944b7c1e7236e6d3493a7c23ea2c099109261;p=simgear.git diff --git a/simgear/sound/sample_group.cxx b/simgear/sound/sample_group.cxx index 43235d86..70df9aa1 100644 --- a/simgear/sound/sample_group.cxx +++ b/simgear/sound/sample_group.cxx @@ -24,11 +24,19 @@ # include #endif +#include #include +#include +#include #include "soundmgr_openal.hxx" +#include "soundmgr_openal_private.hxx" #include "sample_group.hxx" +#ifdef HAVE_STD_ISNAN +using std::isnan; +#endif + bool isNaN(float *v) { return (isnan(v[0]) || isnan(v[1]) || isnan(v[2])); } @@ -39,28 +47,25 @@ SGSampleGroup::SGSampleGroup () : _active(false), _changed(false), _pause(false), + _volume(1.0), _tied_to_listener(false), _velocity(SGVec3d::zeros()), - _orientation(SGQuatd::zeros()), - _position(SGVec3d::zeros()), - _pos_offs(SGVec3d::zeros()), - _position_geod(SGGeod()) + _orientation(SGQuatd::zeros()) { _samples.clear(); } -SGSampleGroup::SGSampleGroup ( SGSoundMgr *smgr, const string &refname ) : +SGSampleGroup::SGSampleGroup ( SGSoundMgr *smgr, + const std::string &refname ): _smgr(smgr), _refname(refname), _active(false), _changed(false), _pause(false), + _volume(1.0), _tied_to_listener(false), _velocity(SGVec3d::zeros()), - _orientation(SGQuatd::zeros()), - _position(SGVec3d::zeros()), - _pos_offs(SGVec3d::zeros()), - _position_geod(SGGeod()) + _orientation(SGQuatd::zeros()) { _smgr->add(this, refname); _samples.clear(); @@ -69,56 +74,138 @@ SGSampleGroup::SGSampleGroup ( SGSoundMgr *smgr, const string &refname ) : SGSampleGroup::~SGSampleGroup () { _active = false; - - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; - - if ( sample->is_valid_source() && sample->is_playing() ) { - sample->no_valid_source(); - _smgr->release_source( sample->get_source() ); - _smgr->release_buffer( sample ); - } - } - + stop(); _smgr = 0; } -void SGSampleGroup::update( double dt ) { - - if ( !_active || _pause ) return; - - testForALError("start of update!!\n"); +static bool is_sample_stopped(SGSoundSample *sample) +{ +#ifdef ENABLE_SOUND + assert(sample->is_valid_source()); + unsigned int source = sample->get_source(); + int result; + alGetSourcei( source, AL_SOURCE_STATE, &result ); + return (result == AL_STOPPED); +#else + return true; +#endif +} +void SGSampleGroup::cleanup_removed_samples() +{ // Delete any OpenAL buffers that might still be in use. unsigned int size = _removed_samples.size(); for (unsigned int i=0; iis_valid_source() ) { - if ( sample->is_looping() ) { + int source = sample->get_source(); + + if ( sample->is_looping() && !stopped) { +#ifdef ENABLE_SOUND + alSourceStop( source ); +#endif + stopped = is_sample_stopped(sample); + } + + if ( stopped ) { sample->no_valid_source(); - _smgr->release_source( sample->get_source() ); + _smgr->release_source( source ); } - else - alGetSourcei( sample->get_source(), AL_SOURCE_STATE, &result ); } - - if ( result == AL_STOPPED ) { - ALuint buffer = sample->get_buffer(); - alDeleteBuffers( 1, &buffer ); - testForALError("buffer remove"); + + if ( stopped ) { + sample->stop(); + if (( !sample->is_queue() )&& + (sample->is_valid_buffer())) + { + _smgr->release_buffer(sample); + } _removed_samples.erase( _removed_samples.begin()+i ); size--; continue; } i++; } +} +void SGSampleGroup::start_playing_sample(SGSoundSample *sample) +{ +#ifdef ENABLE_SOUND + // + // a request to start playing a sound has been filed. + // + ALuint source = _smgr->request_source(); + if (alIsSource(source) == AL_FALSE ) { + return; + } + + sample->set_source( source ); + update_sample_config( sample ); + ALboolean looping = sample->is_looping() ? AL_TRUE : AL_FALSE; + + if ( !sample->is_queue() ) + { + ALuint buffer = _smgr->request_buffer(sample); + if (buffer == SGSoundMgr::FAILED_BUFFER || + buffer == SGSoundMgr::NO_BUFFER) + { + _smgr->release_source(source); + return; + } + + // start playing the sample + buffer = sample->get_buffer(); + if ( alIsBuffer(buffer) == AL_TRUE ) + { + alSourcei( source, AL_BUFFER, buffer ); + testForALError("assign buffer to source"); + } else + SG_LOG( SG_SOUND, SG_ALERT, "No such buffer!"); + } + + alSourcef( source, AL_ROLLOFF_FACTOR, 0.3 ); + alSourcei( source, AL_LOOPING, looping ); + alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE ); + alSourcePlay( source ); + testForALError("sample play"); +#endif +} + +void SGSampleGroup::check_playing_sample(SGSoundSample *sample) +{ + // check if the sound has stopped by itself + + if (is_sample_stopped(sample)) { + // sample is stopped because it wasn't looping + sample->stop(); + sample->no_valid_source(); + _smgr->release_source( sample->get_source() ); + _smgr->release_buffer( sample ); + remove( sample->get_sample_name() ); + } else if ( sample->has_changed() ) { + if ( !sample->is_playing() ) { + // a request to stop playing the sound has been filed. + sample->stop(); + sample->no_valid_source(); + _smgr->release_source( sample->get_source() ); + } else if ( _smgr->has_changed() ) { + update_sample_config( sample ); + } + } +} + +void SGSampleGroup::update( double dt ) { + + if ( !_active || _pause ) return; + + testForALError("start of update!!\n"); + + cleanup_removed_samples(); + // Update the position and orientation information for all samples. - if ( _changed ) { + if ( _changed || _smgr->has_changed() ) { update_pos_and_orientation(); _changed = false; } @@ -128,73 +215,20 @@ void SGSampleGroup::update( double dt ) { for ( ; sample_current != sample_end; ++sample_current ) { SGSoundSample *sample = sample_current->second; - if ( !sample->is_valid_source() && sample->is_playing() ) { - // - // a request to start playing a sound has been filed. - // - if ( _smgr->request_buffer(sample) == SGSoundMgr::NO_BUFFER ) - continue; - - // start playing the sample - ALuint buffer = sample->get_buffer(); - ALuint source = _smgr->request_source(); - if (alIsSource(source) == AL_TRUE && alIsBuffer(buffer) == AL_TRUE) - { - sample->set_source( source ); - - alSourcei( source, AL_BUFFER, buffer ); - testForALError("assign buffer to source"); - - sample->set_source( source ); - update_sample_config( sample ); - - ALboolean looping = sample->is_looping() ? AL_TRUE : AL_FALSE; - alSourcei( source, AL_LOOPING, looping ); - alSourcef( source, AL_ROLLOFF_FACTOR, 1.0 ); - alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE ); - alSourcePlay( source ); - testForALError("sample play"); - } else { - if (alIsBuffer(buffer) == AL_FALSE) - SG_LOG( SG_GENERAL, SG_ALERT, "No such buffer!\n"); - // sample->no_valid_source(); - // sadly, no free source available at this time - } - - } else if ( sample->is_valid_source() && sample->has_changed() ) { - if ( !sample->is_playing() ) { - // a request to stop playing the sound has been filed. - - sample->stop(); - sample->no_valid_source(); - _smgr->release_source( sample->get_source() ); - } else if ( _smgr->has_changed() ) { - update_sample_config( sample ); - } + if ( !sample->is_valid_source() && sample->is_playing() && !sample->test_out_of_range()) { + start_playing_sample(sample); } else if ( sample->is_valid_source() ) { - // check if the sound has stopped by itself - - unsigned int source = sample->get_source(); - int result; - - alGetSourcei( source, AL_SOURCE_STATE, &result ); - if ( result == AL_STOPPED ) { - // sample is stoped because it wasn't looping - sample->stop(); - sample->no_valid_source(); - _smgr->release_source( source ); - _smgr->release_buffer( sample ); - remove( sample->get_sample_name() ); - } + check_playing_sample(sample); } testForALError("update"); } } // add a sound effect, return true if successful -bool SGSampleGroup::add( SGSharedPtr sound, const string& refname ) { - +bool SGSampleGroup::add( SGSharedPtr sound, + const std::string& refname ) +{ sample_map_iterator sample_it = _samples.find( refname ); if ( sample_it != _samples.end() ) { // sample name already exists @@ -207,7 +241,7 @@ bool SGSampleGroup::add( SGSharedPtr sound, const string& refname // remove a sound effect, return true if successful -bool SGSampleGroup::remove( const string &refname ) { +bool SGSampleGroup::remove( const std::string &refname ) { sample_map_iterator sample_it = _samples.find( refname ); if ( sample_it == _samples.end() ) { @@ -217,6 +251,7 @@ bool SGSampleGroup::remove( const string &refname ) { if ( sample_it->second->is_valid_buffer() ) _removed_samples.push_back( sample_it->second ); + _samples.erase( sample_it ); return true; @@ -224,7 +259,7 @@ bool SGSampleGroup::remove( const string &refname ) { // return true of the specified sound exists in the sound manager system -bool SGSampleGroup::exists( const string &refname ) { +bool SGSampleGroup::exists( const std::string &refname ) { sample_map_iterator sample_it = _samples.find( refname ); if ( sample_it == _samples.end() ) { // sample was not found @@ -237,7 +272,7 @@ bool SGSampleGroup::exists( const string &refname ) { // return a pointer to the SGSoundSample if the specified sound exists // in the sound manager system, otherwise return NULL -SGSoundSample *SGSampleGroup::find( const string &refname ) { +SGSoundSample *SGSampleGroup::find( const std::string &refname ) { sample_map_iterator sample_it = _samples.find( refname ); if ( sample_it == _samples.end() ) { // sample was not found @@ -248,9 +283,8 @@ SGSoundSample *SGSampleGroup::find( const string &refname ) { } -// stop playing all associated samples void -SGSampleGroup::suspend () +SGSampleGroup::stop () { _pause = true; sample_map_iterator sample_current = _samples.begin(); @@ -258,33 +292,70 @@ SGSampleGroup::suspend () for ( ; sample_current != sample_end; ++sample_current ) { SGSoundSample *sample = sample_current->second; - if ( sample->is_valid_source() && sample->is_playing() ) { - alSourcePause( sample->get_source() ); + if ( sample->is_valid_source() ) { +#ifdef ENABLE_SOUND + ALint source = sample->get_source(); + if ( sample->is_playing() ) { + alSourceStop( source ); + testForALError("stop"); + } + _smgr->release_source( source ); +#endif + sample->no_valid_source(); + } + + if ( sample->is_valid_buffer() ) { + _smgr->release_buffer( sample ); + sample->no_valid_buffer(); } } - testForALError("suspend"); +} + +// stop playing all associated samples +void +SGSampleGroup::suspend () +{ + if (_active && _pause == false) { + _pause = true; + sample_map_iterator sample_current = _samples.begin(); + sample_map_iterator sample_end = _samples.end(); + for ( ; sample_current != sample_end; ++sample_current ) { +#ifdef ENABLE_SOUND + SGSoundSample *sample = sample_current->second; + if ( sample->is_valid_source() && sample->is_playing() ) { + alSourcePause( sample->get_source() ); + } +#endif + } + testForALError("suspend"); + } } // resume playing all associated samples void SGSampleGroup::resume () { - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; - - if ( sample->is_valid_source() && sample->is_playing() ) { - alSourcePlay( sample->get_source() ); + if (_active && _pause == true) { +#ifdef ENABLE_SOUND + sample_map_iterator sample_current = _samples.begin(); + sample_map_iterator sample_end = _samples.end(); + for ( ; sample_current != sample_end; ++sample_current ) { + SGSoundSample *sample = sample_current->second; + if ( sample->is_valid_source() && sample->is_playing() ) { + alSourcePlay( sample->get_source() ); + } } + testForALError("resume"); +#endif + _pause = false; } - testForALError("resume"); - _pause = false; } // tell the scheduler to play the indexed sample in a continuous loop -bool SGSampleGroup::play( const string &refname, bool looping = false ) { +bool SGSampleGroup::play( const std::string &refname, + bool looping ) +{ SGSoundSample *sample = find( refname ); if ( sample == NULL ) { @@ -297,7 +368,7 @@ bool SGSampleGroup::play( const string &refname, bool looping = false ) { // return true of the specified sound is currently being played -bool SGSampleGroup::is_playing( const string& refname ) { +bool SGSampleGroup::is_playing( const std::string& refname ) { SGSoundSample *sample = find( refname ); if ( sample == NULL ) { @@ -308,7 +379,7 @@ bool SGSampleGroup::is_playing( const string& refname ) { } // immediate stop playing the sound -bool SGSampleGroup::stop( const string& refname ) { +bool SGSampleGroup::stop( const std::string& refname ) { SGSoundSample *sample = find( refname ); if ( sample == NULL ) { @@ -319,97 +390,80 @@ bool SGSampleGroup::stop( const string& refname ) { return true; } -// set source velocity of all managed sounds -void SGSampleGroup::set_velocity( const SGVec3f &vel ) { - if ( isnan(vel[0]) || isnan(vel[1]) || isnan(vel[2]) ) - { - SG_LOG( SG_GENERAL, SG_ALERT, "NAN's found in SampleGroup velocity"); - return; - } - - if (_velocity != vel) { - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; - sample->set_velocity( vel ); - } - _velocity = vel; +void SGSampleGroup::set_volume( float vol ) +{ + if (vol > _volume*1.01 || vol < _volume*0.99) { + _volume = vol; + SG_CLAMP_RANGE(_volume, 0.0f, 1.0f); + _changed = true; } } -// set the source position of all managed sounds +// set the source position and orientation of all managed sounds void SGSampleGroup::update_pos_and_orientation() { - SGVec3d position = SGVec3d::fromGeod( _position_geod ); - SGVec3d pos_offs = SGVec3d::fromGeod( _smgr->get_position_geod() ); + SGVec3d base_position = SGVec3d::fromGeod(_base_pos); + SGVec3d smgr_position = _smgr->get_position(); + SGQuatd hlOr = SGQuatd::fromLonLat(_base_pos); + SGQuatd ec2body = hlOr*_orientation; - if (_position != position || _pos_offs != pos_offs) { - _position = position; - _pos_offs = pos_offs; - - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; - sample->set_position( _position ); - sample->set_position_offset( _pos_offs ); - } + SGVec3f velocity = SGVec3f::zeros(); + if ( _velocity[0] || _velocity[1] || _velocity[2] ) { + velocity = toVec3f( hlOr.backTransform(_velocity*SG_FEET_TO_METER) ); } - // The rotation rotating from the earth centerd frame to - // the horizontal local frame - SGQuatd hlOr = SGQuatd::fromLonLat(_position_geod); - - // Rotate the x-forward, y-right, z-down coordinate system - // into the OpenGL camera system with x-right, y-up, z-back. - SGQuatd q(-0.5, -0.5, 0.5, 0.5); - - // Compute the sounds orientation and position - // wrt the earth centered frame - that is global coorinates - SGQuatd sc2body = hlOr*_orientation*q; - sample_map_iterator sample_current = _samples.begin(); sample_map_iterator sample_end = _samples.end(); for ( ; sample_current != sample_end; ++sample_current ) { SGSoundSample *sample = sample_current->second; + sample->set_master_volume( _volume ); sample->set_orientation( _orientation ); - sample->set_rotation( sc2body ); + sample->set_rotation( ec2body ); + sample->set_position(base_position); + sample->set_velocity( velocity ); + + // Test if a sample is farther away than max distance, if so + // stop the sound playback and free it's source. + if (!_tied_to_listener) { + sample->update_pos_and_orientation(); + SGVec3d position = sample->get_position() - smgr_position; + float max2 = sample->get_max_dist() * sample->get_max_dist(); + float dist2 = position[0]*position[0] + + position[1]*position[1] + position[2]*position[2]; + if ((dist2 > max2) && !sample->test_out_of_range()) { + sample->set_out_of_range(true); + } else if ((dist2 < max2) && sample->test_out_of_range()) { + sample->set_out_of_range(false); + } + } } } -void SGSampleGroup::set_volume( float vol ) +void SGSampleGroup::update_sample_config( SGSoundSample *sample ) { - _volume = vol; - if (_volume < 0.0) _volume = 0.0; - if (_volume > 1.0) _volume = 1.0; - - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; - sample->set_master_volume( _volume ); - } -} - -void SGSampleGroup::update_sample_config( SGSoundSample *sample ) { +#ifdef ENABLE_SOUND SGVec3f orientation, velocity; SGVec3d position; if ( _tied_to_listener ) { orientation = _smgr->get_direction(); - position = _smgr->get_position(); + position = SGVec3d::zeros(); velocity = _smgr->get_velocity(); } else { sample->update_pos_and_orientation(); orientation = sample->get_orientation(); - position = sample->get_position(); + position = sample->get_position() - _smgr->get_position(); velocity = sample->get_velocity(); } + if (_smgr->bad_doppler_effect()) { + velocity *= 100.0f; + } + #if 0 if (length(position) > 20000) - printf("source and listener distance greater than 20km!\n"); + printf("%s source and listener distance greater than 20km!\n", + _refname.c_str()); if (isNaN(toVec3f(position).data())) printf("NaN in source position\n"); if (isNaN(orientation.data())) printf("NaN in source orientation\n"); if (isNaN(velocity.data())) printf("NaN in source velocity\n"); @@ -436,25 +490,28 @@ void SGSampleGroup::update_sample_config( SGSoundSample *sample ) { sample->get_reference_dist() ); testForALError("distance rolloff"); } +#endif } -bool SGSampleGroup::testForError(void *p, string s) +bool SGSampleGroup::testForError(void *p, std::string s) { if (p == NULL) { - SG_LOG( SG_GENERAL, SG_ALERT, "Error (sample group): " << s); + SG_LOG( SG_SOUND, SG_ALERT, "Error (sample group): " << s); return true; } return false; } -bool SGSampleGroup::testForALError(string s) +bool SGSampleGroup::testForALError(std::string s) { +#ifdef SG_C ALenum error = alGetError(); if (error != AL_NO_ERROR) { - SG_LOG( SG_GENERAL, SG_ALERT, "AL Error (" << _refname << "): " + SG_LOG( SG_SOUND, SG_ALERT, "AL Error (" << _refname << "): " << alGetString(error) << " at " << s); return true; } +#endif return false; }