X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fsound%2Fsample_group.cxx;h=a5d19641d385e86097f7a20cccbf6069ac37c4bb;hb=145a7fa1467c028f80e141a324950b2c47e34b7b;hp=ffa23e680262dad8875340d69d38a157aac736fa;hpb=e2e1524454d94db9e1b8cf591f337ca0a5fd06da;p=simgear.git diff --git a/simgear/sound/sample_group.cxx b/simgear/sound/sample_group.cxx index ffa23e68..a5d19641 100644 --- a/simgear/sound/sample_group.cxx +++ b/simgear/sound/sample_group.cxx @@ -1,67 +1,62 @@ +// sample_group.cxx -- Manage a group of samples relative to a base position +// +// Written for the new SoundSystem by Erik Hofman, October 2009 +// +// Copyright (C) 2009 Erik Hofman +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id$ + #ifdef HAVE_CONFIG_H # include #endif #include -#if defined (__APPLE__) -# ifdef __GNUC__ -# if ( __GNUC__ >= 3 ) && ( __GNUC_MINOR__ >= 3 ) -// # include -inline int (isnan)(double r) { return !(r <= 0 || r >= 0); } -# else - // any C++ header file undefines isinf and isnan - // so this should be included before - // the functions are STILL in libm (libSystem on mac os x) -extern "C" int isnan (double); -extern "C" int isinf (double); -# endif -# else -// inline int (isinf)(double r) { return isinf(r); } -// inline int (isnan)(double r) { return isnan(r); } -# endif -#endif - -#if defined (__FreeBSD__) -# if __FreeBSD_version < 500000 - extern "C" { - inline int isnan(double r) { return !(r <= 0 || r >= 0); } - } -# endif -#endif - -#if defined (__CYGWIN__) -# include -#endif - -#if defined(__MINGW32__) -# define isnan(x) _isnan(x) -#endif - #include "soundmgr_openal.hxx" #include "sample_group.hxx" +bool isNaN(float *v) { + return (isnan(v[0]) || isnan(v[1]) || isnan(v[2])); +} + SGSampleGroup::SGSampleGroup () : _smgr(NULL), + _refname(""), _active(false), - _changed(true), - _position_changed(true), - _position(SGVec3d::zeros().data()), - _orientation(SGVec3f::zeros().data()) + _pause(false), + _tied_to_listener(false), + _velocity(SGVec3d::zeros()), + _orientation(SGQuatd::zeros()), + _position(SGGeod()) { _samples.clear(); } SGSampleGroup::SGSampleGroup ( SGSoundMgr *smgr, const string &refname ) : _smgr(smgr), + _refname(refname), _active(false), - _changed(true), - _position_changed(true), - _position(SGVec3d::zeros().data()), - _orientation(SGVec3f::zeros().data()) + _pause(false), + _tied_to_listener(false), + _velocity(SGVec3d::zeros()), + _orientation(SGQuatd::zeros()), + _position(SGGeod()) { _smgr->add(this, refname); - _active = _smgr->is_working(); _samples.clear(); } @@ -77,6 +72,7 @@ SGSampleGroup::~SGSampleGroup () if ( sample->is_valid_source() && sample->is_playing() ) { sample->no_valid_source(); _smgr->release_source( sample->get_source() ); + _smgr->release_buffer( sample ); } } @@ -85,9 +81,35 @@ SGSampleGroup::~SGSampleGroup () void SGSampleGroup::update( double dt ) { - if ( !_active ) return; + if ( !_active || _pause ) return; + + testForALError("start of update!!\n"); + + // 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() ) { + sample->no_valid_source(); + _smgr->release_source( sample->get_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"); + _removed_samples.erase( _removed_samples.begin()+i ); + size--; + continue; + } + i++; + } sample_map_iterator sample_current = _samples.begin(); sample_map_iterator sample_end = _samples.end(); @@ -98,40 +120,8 @@ void SGSampleGroup::update( double dt ) { // // a request to start playing a sound has been filed. // - ALboolean looping = sample->get_looping() ? AL_TRUE : AL_FALSE; - - if ( !sample->is_valid_buffer() ) { - // sample was not yet loaded or removed again - -// TODO: Create a buffer cache that checks whether a file is already present -// as an OpenAL buffer since buffers can be shared among sources. - load_file(sample); - if ( testForALError("load sample") ) { - throw sg_exception("Failed to load sound sample."); - continue; - } - - // create an OpenAL buffer handle - ALuint buffer; - alGenBuffers(1, &buffer); - if ( testForALError("generate buffer") ) { - throw sg_exception("Failed to generate OpenAL buffer."); - continue; - } - - // Copy data to the internal OpenAL buffer - const ALvoid *data = sample->get_data(); - ALenum format = sample->get_format(); - ALsizei size = sample->get_size(); - ALsizei freq = sample->get_frequency(); - alBufferData( buffer, format, data, size, freq ); - sample->free_data(); - if ( testForALError("buffer add data") ) { - continue; - } - - sample->set_buffer(buffer); - } + if ( _smgr->request_buffer(sample) == SGSoundMgr::NO_BUFFER ) + continue; // start playing the sample ALuint buffer = sample->get_buffer(); @@ -146,8 +136,10 @@ void SGSampleGroup::update( double dt ) { sample->set_source( source ); update_sample_config( sample ); - alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE ); + 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 { @@ -161,10 +153,10 @@ void SGSampleGroup::update( double dt ) { if ( !sample->is_playing() ) { // a request to stop playing the sound has been filed. - sample->no_valid_source(); sample->stop(); + sample->no_valid_source(); _smgr->release_source( sample->get_source() ); - } else { + } else if ( _smgr->has_changed() ) { update_sample_config( sample ); } @@ -177,10 +169,11 @@ void SGSampleGroup::update( double dt ) { alGetSourcei( source, AL_SOURCE_STATE, &result ); if ( result == AL_STOPPED ) { // sample is stoped because it wasn't looping - sample->no_valid_source(); sample->stop(); + sample->no_valid_source(); _smgr->release_source( source ); - + _smgr->release_buffer( sample ); + remove( sample->get_sample_name() ); } } testForALError("update"); @@ -188,7 +181,7 @@ void SGSampleGroup::update( double dt ) { } // add a sound effect, return true if successful -bool SGSampleGroup::add( SGSoundSample *sound, const string& refname ) { +bool SGSampleGroup::add( SGSharedPtr sound, const string& refname ) { sample_map_iterator sample_it = _samples.find( refname ); if ( sample_it != _samples.end() ) { @@ -210,7 +203,10 @@ bool SGSampleGroup::remove( const string &refname ) { return false; } + if ( sample_it->second->is_valid_buffer() ) + _removed_samples.push_back( sample_it->second ); _samples.erase( sample_it ); + return true; } @@ -244,15 +240,14 @@ SGSoundSample *SGSampleGroup::find( const string &refname ) { void SGSampleGroup::suspend () { - _active = false; + _pause = true; 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() ) { - unsigned int source = sample->get_source(); - alSourcePause( source ); + alSourcePause( sample->get_source() ); } } testForALError("suspend"); @@ -268,12 +263,11 @@ SGSampleGroup::resume () SGSoundSample *sample = sample_current->second; if ( sample->is_valid_source() && sample->is_playing() ) { - unsigned int source = sample->get_source(); - alSourcePlay( source ); + alSourcePlay( sample->get_source() ); } } testForALError("resume"); - _active = true; + _pause = false; } @@ -313,97 +307,49 @@ bool SGSampleGroup::stop( const string& refname ) { return true; } - -// set source position of all managed sounds -void SGSampleGroup::set_position( SGVec3d pos ) { - if ( isnan(pos.data()[0]) || isnan(pos.data()[1]) || isnan(pos.data()[2]) ) - { - SG_LOG( SG_GENERAL, SG_ALERT, "NAN's found in SampleGroup postion"); - return; - } - - 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_base_position( pos ); - } -} - // set source velocity of all managed sounds -void SGSampleGroup::set_velocity( SGVec3f vel ) { - if ( isnan(vel.data()[0]) || isnan(vel.data()[1]) || isnan(vel.data()[2]) ) +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; } - 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 ); + 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; } } -// ste the source orientation of all managed sounds -void SGSampleGroup::set_orientation( SGVec3f ori ) { - if ( isnan(ori.data()[0]) || isnan(ori.data()[1]) || isnan(ori.data()[2]) ) - { - SG_LOG( SG_GENERAL, SG_ALERT, "NAN's found in SampleGroup orientation"); - return; - } +// set the source position of all managed sounds +void SGSampleGroup::set_position( const SGGeod& pos ) { 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_orientation( ori ); - } -} - -void SGSampleGroup::update_sample_config( SGSoundSample *sample ) { - if ( sample->is_valid_source() ) { - unsigned int source = sample->get_source(); - - alSourcefv( source, AL_POSITION, sample->get_position()); - alSourcefv( source, AL_DIRECTION, sample->get_direction() ); - alSourcefv( source, AL_VELOCITY, sample->get_velocity() ); - testForALError("position and orientation"); - - alSourcef( source, AL_PITCH, sample->get_pitch() ); - alSourcef( source, AL_GAIN, sample->get_volume() ); - testForALError("pitch and gain"); - - if ( sample->has_static_data_changed() ) { - alSourcef( source, AL_CONE_INNER_ANGLE, sample->get_innerangle() ); - alSourcef( source, AL_CONE_OUTER_ANGLE, sample->get_outerangle() ); - alSourcef( source, AL_CONE_OUTER_GAIN, sample->get_outergain() ); - testForALError("audio cone"); - - alSourcef( source, AL_ROLLOFF_FACTOR, 1.0 ); - alSourcef( source, AL_MAX_DISTANCE, sample->get_max_dist() ); - alSourcef( source, AL_REFERENCE_DISTANCE, - sample->get_reference_dist() ); - testForALError("distance rolloff"); - } + sample->set_position( pos ); } + _position = pos; } -ALvoid -SGSampleGroup::load_file(SGSoundSample *sample) { - if (sample->is_file()) { - unsigned int size; - int freq, format; - void *data; - string sample_name = sample->get_sample_name(); - _smgr->load(sample_name, &data, &format, &size, &freq); +// set the source orientation of all managed sounds +void SGSampleGroup::set_orientation( const SGQuatd& ori ) { - sample->set_data( (unsigned char *)data ); - sample->set_frequency( freq ); - sample->set_format( format ); - sample->set_size( size ); + if (_orientation != ori) { + 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_orientation( ori ); + } + _orientation = ori; } } @@ -421,6 +367,50 @@ void SGSampleGroup::set_volume( float vol ) } } +void SGSampleGroup::update_sample_config( SGSoundSample *sample ) { + SGVec3f orientation, velocity; + SGVec3d position; + + if ( _tied_to_listener ) { + orientation = _smgr->get_direction(); + position = _smgr->get_position(); + velocity = _smgr->get_velocity(); + } else { + sample->update_absolute_position(); + orientation = sample->get_orientation(); + position = sample->get_position(); + velocity = sample->get_velocity(); + } + + if (dist(position, _smgr->get_position()) > 10000) + printf("source and listener distance greater than 20km!\n"); + 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"); + + unsigned int source = sample->get_source(); + alSourcefv( source, AL_POSITION, toVec3f(position).data() ); + alSourcefv( source, AL_VELOCITY, velocity.data() ); + alSourcefv( source, AL_DIRECTION, orientation.data() ); + testForALError("position and orientation"); + + alSourcef( source, AL_PITCH, sample->get_pitch() ); + alSourcef( source, AL_GAIN, sample->get_volume() ); + testForALError("pitch and gain"); + + if ( sample->has_static_data_changed() ) { + alSourcef( source, AL_CONE_INNER_ANGLE, sample->get_innerangle() ); + alSourcef( source, AL_CONE_OUTER_ANGLE, sample->get_outerangle() ); + alSourcef( source, AL_CONE_OUTER_GAIN, sample->get_outergain() ); + testForALError("audio cone"); + + alSourcef( source, AL_MAX_DISTANCE, sample->get_max_dist() ); + alSourcef( source, AL_REFERENCE_DISTANCE, + sample->get_reference_dist() ); + testForALError("distance rolloff"); + } +} + bool SGSampleGroup::testForError(void *p, string s) { if (p == NULL) { @@ -434,7 +424,7 @@ bool SGSampleGroup::testForALError(string s) { ALenum error = alGetError(); if (error != AL_NO_ERROR) { - SG_LOG( SG_GENERAL, SG_ALERT, "AL Error (sample group): " + SG_LOG( SG_GENERAL, SG_ALERT, "AL Error (" << _refname << "): " << alGetString(error) << " at " << s); return true; }