From: Erik Hofman Date: Fri, 27 May 2016 12:40:49 +0000 (+0200) Subject: Move all OpenAL function calls from SampleMgr to soundMgr X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=76e82a2cbc7c2d64f0678f8c9ffce4543593030b;p=simgear.git Move all OpenAL function calls from SampleMgr to soundMgr --- diff --git a/simgear/sound/CMakeLists.txt b/simgear/sound/CMakeLists.txt index c2538938..cd52e6d1 100644 --- a/simgear/sound/CMakeLists.txt +++ b/simgear/sound/CMakeLists.txt @@ -1,16 +1,16 @@ include (SimGearComponent) set(HEADERS + sample.hxx sample_group.hxx - sample_openal.hxx soundmgr_openal.hxx xmlsound.hxx readwav.hxx ) set(SOURCES + sample.cxx sample_group.cxx - sample_openal.cxx soundmgr_openal.cxx xmlsound.cxx readwav.cxx diff --git a/simgear/sound/openal_test2.cxx b/simgear/sound/openal_test2.cxx index 43bd464d..260eea97 100644 --- a/simgear/sound/openal_test2.cxx +++ b/simgear/sound/openal_test2.cxx @@ -12,7 +12,7 @@ #include "soundmgr_openal.hxx" #include "sample_group.hxx" -#include "sample_openal.hxx" +#include "sample.hxx" int main( int argc, char *argv[] ) { diff --git a/simgear/sound/openal_test3.cxx b/simgear/sound/openal_test3.cxx index bbf5b089..e93aa272 100644 --- a/simgear/sound/openal_test3.cxx +++ b/simgear/sound/openal_test3.cxx @@ -11,7 +11,7 @@ #include "soundmgr_openal.hxx" #include "sample_group.hxx" -#include "sample_openal.hxx" +#include "sample.hxx" int main( int argc, char *argv[] ) { SGSampleGroup *sgr; diff --git a/simgear/sound/readwav.cxx b/simgear/sound/readwav.cxx index 30429bd2..4f96d883 100644 --- a/simgear/sound/readwav.cxx +++ b/simgear/sound/readwav.cxx @@ -30,7 +30,7 @@ #include #include -#include "sample_openal.hxx" +#include "sample.hxx" namespace { diff --git a/simgear/sound/sample.cxx b/simgear/sound/sample.cxx new file mode 100644 index 00000000..2a02e82a --- /dev/null +++ b/simgear/sound/sample.cxx @@ -0,0 +1,195 @@ +// sample.cxx -- Audio sample encapsulation class +// +// Written by Curtis Olson, started April 2004. +// Modified to match the new SoundSystem by Erik Hofman, October 2009 +// +// Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt +// 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 // rand(), free() +#include +#include + +#include +#include +#include +#include + +#include "soundmgr_openal_private.hxx" +#include "soundmgr_openal.hxx" +#include "sample.hxx" + +#define AL_FALSE 0 + +using std::string; + +// +// SGSoundSampleInfo +// + +// empty constructor +SGSoundSampleInfo::SGSoundSampleInfo() : + _refname(random_string()), + _bits(16), + _tracks(1), + _samples(0), + _frequency(22500), + _compressed(false), + _loop(false), + _static_changed(true), + _playing(false), + _pitch(1.0f), + _volume(1.0f), + _master_volume(1.0f), + _use_pos_props(false), + _out_of_range(false), + _inner_angle(360.0f), + _outer_angle(360.0f), + _outer_gain(0.0f), + _reference_dist(500.0f), + _max_dist(3000.0f), + _absolute_pos(SGVec3d::zeros()), + _relative_pos(SGVec3d::zeros()), + _direction(SGVec3d::zeros()), + _velocity(SGVec3f::zeros()), + _orientation(SGQuatd::zeros()), + _orivec(SGVec3f::zeros()), + _base_pos(SGVec3d::zeros()), + _rotation(SGQuatd::zeros()) +{ + _pos_prop[0] = 0; + _pos_prop[1] = 0; + _pos_prop[2] = 0; +} + +std::string SGSoundSampleInfo::random_string() +{ + static const char *r = "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + string rstr = "Auto: "; + for (int i=0; i<10; i++) { + rstr.push_back( r[rand() % strlen(r)] ); + } + + return rstr; +} + +// +// SGSoundSample +// + +// empty constructor +SGSoundSample::SGSoundSample() : + _is_file(false), + _changed(true), + _valid_source(false), + _source(SGSoundMgr::NO_SOURCE), + _data(NULL), + _valid_buffer(false), + _buffer(SGSoundMgr::NO_BUFFER) +{ +} + +// constructor +SGSoundSample::SGSoundSample(const char *file, const SGPath& currentDir) : + _is_file(true), + _changed(true), + _valid_source(false), + _source(SGSoundMgr::NO_SOURCE), + _data(NULL), + _valid_buffer(false), + _buffer(SGSoundMgr::NO_BUFFER) +{ + SGPath p = simgear::ResourceManager::instance()->findPath(file, currentDir); + _refname = p.str(); +} + +// constructor +SGSoundSample::SGSoundSample( const unsigned char** data, + int len, int freq, int format ) : + _is_file(false), + _changed(true), + _valid_source(false), + _source(SGSoundMgr::NO_SOURCE), + _valid_buffer(false), + _buffer(SGSoundMgr::NO_BUFFER) +{ + SG_LOG( SG_SOUND, SG_DEBUG, "In memory sounds sample" ); + _data = (unsigned char*)*data; *data = NULL; +} + +// constructor +SGSoundSample::SGSoundSample( void** data, int len, int freq, int format ) : + _is_file(false), + _changed(true), + _valid_source(false), + _source(SGSoundMgr::NO_SOURCE), + _valid_buffer(false), + _buffer(SGSoundMgr::NO_BUFFER) +{ + SG_LOG( SG_SOUND, SG_DEBUG, "In memory sounds sample" ); + _data = (unsigned char*)*data; *data = NULL; +} + + +// destructor +SGSoundSample::~SGSoundSample() { + if ( _data != NULL ) free(_data); +} + +void SGSoundSample::update_pos_and_orientation() { + + if (_use_pos_props) { + if (_pos_prop[0]) _absolute_pos[0] = _pos_prop[0]->getDoubleValue(); + if (_pos_prop[1]) _absolute_pos[1] = _pos_prop[1]->getDoubleValue(); + if (_pos_prop[2]) _absolute_pos[2] = _pos_prop[2]->getDoubleValue(); + } + else { + _absolute_pos = _base_pos; + if (_relative_pos[0] || _relative_pos[1] || _relative_pos[2] ) { + _absolute_pos += _rotation.rotate( _relative_pos ); + } + } + + _orivec = SGVec3f::zeros(); + if ( _direction[0] || _direction[1] || _direction[2] ) { + _orivec = toVec3f( _rotation.rotate( _direction ) ); + } +} + +SGPath SGSoundSample::file_path() const +{ + if (!_is_file) { + return SGPath(); + } + + return SGPath(_refname); +} + +void SGSoundSample::free_data() +{ + if ( _data != NULL ) { + free( _data ); + } + _data = NULL; +} diff --git a/simgear/sound/sample.hxx b/simgear/sound/sample.hxx new file mode 100644 index 00000000..408c5fcc --- /dev/null +++ b/simgear/sound/sample.hxx @@ -0,0 +1,555 @@ +// sample.hxx -- Audio sample encapsulation class +// +// Written by Curtis Olson, started April 2004. +// Modified to match the new SoundSystem by Erik Hofman, October 2009 +// +// Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt +// 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$ + +/** + * \file audio sample.hxx + * Provides a audio sample encapsulation + */ + +#ifndef _SG_SAMPLE_HXX +#define _SG_SAMPLE_HXX 1 + +#include +#include + +enum { + SG_SAMPLE_MONO = 1, + SG_SAMPLE_STEREO = 2, + + SG_SAMPLE_4BITS = 4, + SG_SAMPLE_8BITS = 8, + SG_SAMPLE_16BITS = 16, + + SG_SAMPLE_UNCOMPRESSED = 0, + SG_SAMPLE_COMPRESSED = 256, + + SG_SAMPLE_MONO8 = (SG_SAMPLE_MONO|SG_SAMPLE_8BITS), + SG_SAMPLE_MONO16 = (SG_SAMPLE_MONO|SG_SAMPLE_16BITS), + SG_SAMPLE_MULAW = (SG_SAMPLE_MONO|SG_SAMPLE_8BITS|SG_SAMPLE_COMPRESSED), + SG_SAMPLE_ADPCM = (SG_SAMPLE_MONO|SG_SAMPLE_4BITS|SG_SAMPLE_COMPRESSED) +}; + + +/** + * manages everything we need to know for an individual audio sample + */ + +class SGSoundSampleInfo +{ +public: + SGSoundSampleInfo(); + ~SGSoundSampleInfo() {} + + /** + * Returns the format of this audio sample. + * @return SimGear format-id + */ + inline unsigned int get_format() { return (_tracks | _bits | _compressed*256); } + + /** + * Get the reference name of this audio sample. + * @return Sample name + */ + inline std::string get_sample_name() const { return _refname; } + + /** + * Returns the frequency (in Herz) of this audio sample. + * @return Frequency + */ + inline unsigned int get_frequency() { return _frequency; } + + /** + * Get the current pitch value of this audio sample. + * @return Pitch + */ + inline float get_pitch() { return _pitch; } + + /** + * Get the final volume value of this audio sample. + * @return Volume + */ + inline float get_volume() { return _volume * _master_volume; } + + /** + * Returns the size (in bytes) of this audio sample. + * @return Data size + */ + inline size_t get_size() const { + return (_samples * _tracks * _bits)/8; + } + + + /** + * Get the absolute position of this sound. + * This is in the same coordinate system as OpenGL; y=up, z=back, x=right. + * @return Absolute position + */ + inline SGVec3d& get_position() { return _absolute_pos; } + + /** + * Get the orientation vector of this sound. + * This is in the same coordinate system as OpenGL; y=up, z=back, x=right + * @return Orientaton vector + */ + inline SGVec3f& get_orientation() { return _orivec; } + + /** + * Get the inner angle of the audio cone. + * @return Inner angle in degrees + */ + inline float get_innerangle() { return _inner_angle; } + + /** + * Get the outer angle of the audio cone. + * @return Outer angle in degrees + */ + inline float get_outerangle() { return _outer_angle; } + + /** + * Get the remaining gain at the edge of the outer cone. + * @return Gain + */ + inline float get_outergain() { return _outer_gain; } + + /** + * Get velocity vector (in meters per second) of this sound. + * This is in the same coordinate system as OpenGL; y=up, z=back, x=right + * @return Velocity vector + */ + inline SGVec3f& get_velocity() { return _velocity; } + + /** + * Get reference distance ((in meters) of this sound. + * This is the distance where the gain will be half. + * @return Reference distance + */ + inline float get_reference_dist() { return _reference_dist; } + + /** + * Get maximum distance (in meters) of this sound. + * This is the distance where this sound is no longer audible. + * @return dist Maximum distance + */ + inline float get_max_dist() { return _max_dist; } + + /** + * Test if static data of audio sample configuration has changed. + * Calling this function will reset the flag so calling it a second + * time in a row will return false. + * @return Return true is the static data has changed in the mean time. + */ + bool has_static_data_changed() { + bool b = _static_changed; _static_changed = false; return b; + } + +protected: + // static sound emitter info + std::string _refname; + unsigned int _bits; + unsigned int _tracks; + unsigned int _samples; + unsigned int _frequency; + bool _compressed; + bool _loop; + + // dynamic sound emitter info (non 3d) + bool _static_changed; + bool _playing; + + float _pitch; + float _volume; + float _master_volume; + + // dynamic sound emitter info (3d) + bool _use_pos_props; + bool _out_of_range; + + float _inner_angle; + float _outer_angle; + float _outer_gain; + + float _reference_dist; + float _max_dist; + + SGPropertyNode_ptr _pos_prop[3]; + SGVec3d _absolute_pos; // absolute position + SGVec3d _relative_pos; // position relative to the base position + SGVec3d _direction; // orientation offset + SGVec3f _velocity; // Velocity of the source sound. + + // The position and orientation of this sound + SGQuatd _orientation; // base orientation + SGVec3f _orivec; // orientation vector + SGVec3d _base_pos; // base position + + SGQuatd _rotation; + +private: + static std::string random_string(); +}; + + +class SGSoundSample : public SGSoundSampleInfo, public SGReferenced { +public: + + /** + * Empty constructor, can be used to read data to the systems + * memory and not to the driver. + */ + SGSoundSample(); + + /** + * Constructor + * @param file File name of sound + Buffer data is freed by the sample group + */ + SGSoundSample(const char *file, const SGPath& currentDir); + + /** + * Constructor. + * @param data Pointer to a memory buffer containing this audio sample data + The application may free the data by calling free_data(), otherwise it + will be resident until the class is destroyed. This pointer will be + set to NULL after calling this function. + * @param len Byte length of array + * @param freq Frequency of the provided data (bytes per second) + * @param format SimGear format id of the data + */ + SGSoundSample( void** data, int len, int freq, int format=SG_SAMPLE_MONO8 ); + SGSoundSample( const unsigned char** data, int len, int freq, + int format = SG_SAMPLE_MONO8 ); + + /** + * Destructor + */ + virtual ~SGSoundSample (); + + /** + * Test if this audio sample configuration has changed since the last call. + * Calling this function will reset the flag so calling it a second + * time in a row will return false. + * @return Return true is the configuration has changed in the mean time. + */ + bool has_changed() { + bool b = _changed; _changed = false; return b; + } + + /** + * Detect whether this audio sample holds the information of a sound file. + * @return Return true if this sample is to be constructed from a file. + */ + inline bool is_file() const { return _is_file; } + + SGPath file_path() const; + + /** + * Schedule this audio sample for playing. Actual playing will only start + * at the next call op SoundGroup::update() + * @param _loop Define whether this sound should be played in a loop. + */ + void play( bool loop = false ) { + _playing = true; _loop = loop; _changed = true; _static_changed = true; + } + + /** + * Check if this audio sample is set to be continuous looping. + * @return Return true if this audio sample is set to looping. + */ + inline bool is_looping() { return _loop; } + + /** + * Schedule this audio sample to stop playing. + */ + virtual void stop() { + _playing = false; _changed = true; + } + + /** + * Schedule this audio sample to play once. + * @see #play + */ + inline void play_once() { play(false); } + + /** + * Schedule this audio sample to play looped. + * @see #play + */ + inline void play_looped() { play(true); } + + /** + * Test if a audio sample is scheduled for playing. + * @return true if this audio sample is playing, false otherwise. + */ + inline bool is_playing() { return _playing; } + + + /** + * Set this sample to out-of-range (or not) and + * Schedule this audio sample to stop (or start) playing. + */ + inline void set_out_of_range(bool oor = true) { + _out_of_range = oor; _playing = (!oor && _loop); _changed = true; + } + + /** + * Test if this sample to out-of-range or not. + */ + inline bool test_out_of_range() { + return _out_of_range; + } + + /** + * Set the data associated with this audio sample + * @param data Pointer to a memory block containg this audio sample data. + This pointer will be set to NULL after calling this function. + */ + inline void set_data( const unsigned char **data ) { + _data = (unsigned char*)*data; *data = NULL; + } + inline void set_data( const void **data ) { + _data = (unsigned char*)*data; *data = NULL; + } + + /** + * Return the data associated with this audio sample. + * @return A pointer to this sound data of this audio sample. + */ + inline void* get_data() const { return _data; } + + /** + * Free the data associated with this audio sample + */ + void free_data(); + + /** + * Set the source id of this source + * @param sid source-id + */ + virtual void set_source(unsigned int sid) { + _source = sid; _valid_source = true; _changed = true; + } + + /** + * Get the source id of this source + * @return source-id + */ + virtual unsigned int get_source() { return _source; } + + /** + * Test if the source-id of this audio sample is usable. + * @return true if the source-id is valid + */ + virtual bool is_valid_source() const { return _valid_source; } + + /** + * Set the source-id of this audio sample to invalid. + */ + virtual void no_valid_source() { _valid_source = false; } + + /** + * Set the buffer-id of this source + * @param bid buffer-id + */ + inline void set_buffer(unsigned int bid) { + _buffer = bid; _valid_buffer = true; _changed = true; + } + + /** + * Get the buffer-id of this source + * @return buffer-id + */ + inline unsigned int get_buffer() { return _buffer; } + + /** + * Test if the buffer-id of this audio sample is usable. + * @return true if the buffer-id is valid + */ + inline bool is_valid_buffer() const { return _valid_buffer; } + + /** + * Set the buffer-id of this audio sample to invalid. + */ + inline void no_valid_buffer() { _valid_buffer = false; } + + /** + * Set the playback pitch of this audio sample. + * Should be between 0.0 and 2.0 for maximum compatibility. + * @param p Pitch + */ + inline void set_pitch( float p ) { + if (p > 2.0) p = 2.0; else if (p < 0.01) p = 0.01; + _pitch = p; _changed = true; + } + + /** + * Set the master volume of this sample. Should be between 0.0 and 1.0. + * The final volume is calculated by multiplying the master and audio sample + * volume. + * @param v Volume + */ + inline void set_master_volume( float v ) { + if (v > 1.0) v = 1.0; else if (v < 0.0) v = 0.0; + _master_volume = v; _changed = true; + } + + /** + * Set the volume of this audio sample. Should be between 0.0 and 1.0. + * The final volume is calculated by multiplying the master and audio sample + * volume. + * @param v Volume + */ + inline void set_volume( float v ) { + if (v > 1.0) v = 1.0; else if (v < 0.0) v = 0.0; + _volume = v; _changed = true; + } + + /** + * Set the SimGear format of this audio sample. + * @param format SimGear format-id + */ + inline void set_format( int fmt ) { + _tracks = fmt & 0x3; _bits = fmt & 0x1C; _compressed = fmt & 0x100; + } + + /** + * Set the frequency (in Herz) of this audio sample. + * @param freq Frequency + */ + inline void set_frequency( int freq ) { _frequency = freq; } + + /** + * Sets the size (in bytes) of this audio sample. + * @param size Data size + */ + inline void set_size( size_t size ) { + _samples = size*8/(_bits*_tracks); + } + inline void set_no_samples(size_t samples) { _samples = samples; } + + /** + * Set the position of this sound relative to the base position. + * This is in the same coordinate system as OpenGL; y=up, z=back, x=right. + * @param pos Relative position of this sound + */ + inline void set_relative_position( const SGVec3f& pos ) { + _relative_pos = toVec3d(pos); _changed = true; + } + + /** + * Set the base position in Cartesian coordinates + * @param pos position in Cartesian coordinates + */ + inline void set_position( const SGVec3d& pos ) { + _base_pos = pos; _changed = true; + } + + inline void set_position_properties(SGPropertyNode_ptr pos[3]) { + _pos_prop[0] = pos[0]; _pos_prop[1] = pos[1]; _pos_prop[2] = pos[2]; + if (pos[0] || pos[1] || pos[2]) _use_pos_props = true; + _changed = true; + } + + /** + * Set the orientation of this sound. + * @param ori Quaternation containing the orientation information + */ + inline void set_orientation( const SGQuatd& ori ) { + _orientation = ori; _changed = true; + } + + inline void set_rotation( const SGQuatd& ec2body ) { + _rotation = ec2body; _changed = true; + } + + /** + * Set direction of this sound relative to the orientation. + * This is in the same coordinate system as OpenGL; y=up, z=back, x=right + * @param dir Sound emission direction + */ + inline void set_direction( const SGVec3f& dir ) { + _direction = toVec3d(dir); _static_changed = true; + } + + /** + * Define the audio cone parameters for directional audio. + * Note: setting it to 2 degree will result in 1 degree to both sides. + * @param inner Inner cone angle (0 - 360 degrees) + * @param outer Outer cone angle (0 - 360 degrees) + * @param gain Remaining gain at the edge of the outer cone (0.0 - 1.0) + */ + void set_audio_cone( float inner, float outer, float gain ) { + _inner_angle = inner; _outer_angle = outer; _outer_gain = gain; + _static_changed = true; + } + + /** + * Set the velocity vector (in meters per second) of this sound. + * This is in the local frame coordinate system; x=north, y=east, z=down + * @param Velocity vector + */ + inline void set_velocity( const SGVec3f& vel ) { + _velocity = vel; _changed = true; + } + + /** + * Set reference distance (in meters) of this sound. + * This is the distance where the gain will be half. + * @param dist Reference distance + */ + inline void set_reference_dist( float dist ) { + _reference_dist = dist; _static_changed = true; + } + + /** + * Set maximum distance (in meters) of this sound. + * This is the distance where this sound is no longer audible. + * @param dist Maximum distance + */ + inline void set_max_dist( float dist ) { + _max_dist = dist; _static_changed = true; + } + + inline virtual bool is_queue() const { return false; } + + void update_pos_and_orientation(); + +protected: + bool _is_file; + bool _changed; + + // Sources are points emitting sound. + bool _valid_source; + unsigned int _source; + +private: + unsigned char* _data; + + // Buffers hold sound data. + bool _valid_buffer; + unsigned int _buffer; +}; + +#endif // _SG_SAMPLE_HXX + + diff --git a/simgear/sound/sample_group.cxx b/simgear/sound/sample_group.cxx index dbbb22ab..d4f77bff 100644 --- a/simgear/sound/sample_group.cxx +++ b/simgear/sound/sample_group.cxx @@ -24,7 +24,6 @@ # include #endif -#include #include #include #include @@ -78,42 +77,15 @@ SGSampleGroup::~SGSampleGroup () _smgr = 0; } -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() ) { - 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( source ); - } - } + _smgr->sample_stop(sample); + bool stopped = _smgr->is_sample_stopped(sample); if ( stopped ) { sample->stop(); @@ -132,52 +104,16 @@ void SGSampleGroup::cleanup_removed_samples() 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 ); + _smgr->sample_init( sample ); 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 + _smgr->sample_play( sample ); } void SGSampleGroup::check_playing_sample(SGSoundSample *sample) { // check if the sound has stopped by itself - if (is_sample_stopped(sample)) { + if (_smgr->is_sample_stopped(sample)) { // sample is stopped because it wasn't looping sample->stop(); sample->no_valid_source(); @@ -291,23 +227,7 @@ SGSampleGroup::stop () sample_map_iterator sample_end = _samples.end(); for ( ; sample_current != sample_end; ++sample_current ) { SGSoundSample *sample = sample_current->second; - - 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(); - } + _smgr->sample_destroy( sample ); } } @@ -322,9 +242,7 @@ SGSampleGroup::suspend () 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() ); - } + _smgr->sample_suspend( sample ); #endif } testForALError("suspend"); @@ -341,9 +259,7 @@ SGSampleGroup::resume () 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() ); - } + _smgr->sample_resume( sample ); } testForALError("resume"); #endif @@ -469,27 +385,7 @@ void SGSampleGroup::update_sample_config( SGSoundSample *sample ) if (isNaN(velocity.data())) printf("NaN in source velocity\n"); #endif - 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"); - } + _smgr->update_sample_config( sample, position, orientation, velocity ); #endif } @@ -504,14 +400,7 @@ bool SGSampleGroup::testForError(void *p, std::string s) bool SGSampleGroup::testForALError(std::string s) { -#ifdef SG_C - ALenum error = alGetError(); - if (error != AL_NO_ERROR) { - SG_LOG( SG_SOUND, SG_ALERT, "AL Error (" << _refname << "): " - << alGetString(error) << " at " << s); - return true; - } -#endif + _smgr->testForError(s, _refname); return false; } diff --git a/simgear/sound/sample_group.hxx b/simgear/sound/sample_group.hxx index 4d307dd9..30fcebbe 100644 --- a/simgear/sound/sample_group.hxx +++ b/simgear/sound/sample_group.hxx @@ -36,7 +36,7 @@ #include #include -#include "sample_openal.hxx" +#include "sample.hxx" typedef std::map < std::string, SGSharedPtr > sample_map; diff --git a/simgear/sound/sample_openal.cxx b/simgear/sound/sample_openal.cxx deleted file mode 100644 index 0c613d52..00000000 --- a/simgear/sound/sample_openal.cxx +++ /dev/null @@ -1,195 +0,0 @@ -// sample_openal.cxx -- Audio sample encapsulation class -// -// Written by Curtis Olson, started April 2004. -// Modified to match the new SoundSystem by Erik Hofman, October 2009 -// -// Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt -// 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 // rand(), free() -#include -#include - -#include -#include -#include -#include - -#include "soundmgr_openal.hxx" -#include "sample_openal.hxx" -#include "soundmgr_openal_private.hxx" - -#define AL_FALSE 0 - -using std::string; - -// -// SGSoundSampleInfo -// - -// empty constructor -SGSoundSampleInfo::SGSoundSampleInfo() : - _refname(random_string()), - _bits(16), - _tracks(1), - _samples(0), - _frequency(22500), - _compressed(false), - _loop(false), - _static_changed(true), - _playing(false), - _pitch(1.0f), - _volume(1.0f), - _master_volume(1.0f), - _use_pos_props(false), - _out_of_range(false), - _inner_angle(360.0f), - _outer_angle(360.0f), - _outer_gain(0.0f), - _reference_dist(500.0f), - _max_dist(3000.0f), - _absolute_pos(SGVec3d::zeros()), - _relative_pos(SGVec3d::zeros()), - _direction(SGVec3d::zeros()), - _velocity(SGVec3f::zeros()), - _orientation(SGQuatd::zeros()), - _orivec(SGVec3f::zeros()), - _base_pos(SGVec3d::zeros()), - _rotation(SGQuatd::zeros()) -{ - _pos_prop[0] = 0; - _pos_prop[1] = 0; - _pos_prop[2] = 0; -} - -std::string SGSoundSampleInfo::random_string() -{ - static const char *r = "0123456789abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - string rstr = "Auto: "; - for (int i=0; i<10; i++) { - rstr.push_back( r[rand() % strlen(r)] ); - } - - return rstr; -} - -// -// SGSoundSample -// - -// empty constructor -SGSoundSample::SGSoundSample() : - _is_file(false), - _changed(true), - _valid_source(false), - _source(SGSoundMgr::NO_SOURCE), - _data(NULL), - _valid_buffer(false), - _buffer(SGSoundMgr::NO_BUFFER) -{ -} - -// constructor -SGSoundSample::SGSoundSample(const char *file, const SGPath& currentDir) : - _is_file(true), - _changed(true), - _valid_source(false), - _source(SGSoundMgr::NO_SOURCE), - _data(NULL), - _valid_buffer(false), - _buffer(SGSoundMgr::NO_BUFFER) -{ - SGPath p = simgear::ResourceManager::instance()->findPath(file, currentDir); - _refname = p.str(); -} - -// constructor -SGSoundSample::SGSoundSample( const unsigned char** data, - int len, int freq, int format ) : - _is_file(false), - _changed(true), - _valid_source(false), - _source(SGSoundMgr::NO_SOURCE), - _valid_buffer(false), - _buffer(SGSoundMgr::NO_BUFFER) -{ - SG_LOG( SG_SOUND, SG_DEBUG, "In memory sounds sample" ); - _data = (unsigned char*)*data; *data = NULL; -} - -// constructor -SGSoundSample::SGSoundSample( void** data, int len, int freq, int format ) : - _is_file(false), - _changed(true), - _valid_source(false), - _source(SGSoundMgr::NO_SOURCE), - _valid_buffer(false), - _buffer(SGSoundMgr::NO_BUFFER) -{ - SG_LOG( SG_SOUND, SG_DEBUG, "In memory sounds sample" ); - _data = (unsigned char*)*data; *data = NULL; -} - - -// destructor -SGSoundSample::~SGSoundSample() { - if ( _data != NULL ) free(_data); -} - -void SGSoundSample::update_pos_and_orientation() { - - if (_use_pos_props) { - if (_pos_prop[0]) _absolute_pos[0] = _pos_prop[0]->getDoubleValue(); - if (_pos_prop[1]) _absolute_pos[1] = _pos_prop[1]->getDoubleValue(); - if (_pos_prop[2]) _absolute_pos[2] = _pos_prop[2]->getDoubleValue(); - } - else { - _absolute_pos = _base_pos; - if (_relative_pos[0] || _relative_pos[1] || _relative_pos[2] ) { - _absolute_pos += _rotation.rotate( _relative_pos ); - } - } - - _orivec = SGVec3f::zeros(); - if ( _direction[0] || _direction[1] || _direction[2] ) { - _orivec = toVec3f( _rotation.rotate( _direction ) ); - } -} - -SGPath SGSoundSample::file_path() const -{ - if (!_is_file) { - return SGPath(); - } - - return SGPath(_refname); -} - -void SGSoundSample::free_data() -{ - if ( _data != NULL ) { - free( _data ); - } - _data = NULL; -} diff --git a/simgear/sound/sample_openal.hxx b/simgear/sound/sample_openal.hxx deleted file mode 100644 index 91e2b2ac..00000000 --- a/simgear/sound/sample_openal.hxx +++ /dev/null @@ -1,555 +0,0 @@ -// sample_openal.hxx -- Audio sample encapsulation class -// -// Written by Curtis Olson, started April 2004. -// Modified to match the new SoundSystem by Erik Hofman, October 2009 -// -// Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt -// 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$ - -/** - * \file audio sample.hxx - * Provides a audio sample encapsulation - */ - -#ifndef _SG_SAMPLE_HXX -#define _SG_SAMPLE_HXX 1 - -#include -#include - -enum { - SG_SAMPLE_MONO = 1, - SG_SAMPLE_STEREO = 2, - - SG_SAMPLE_4BITS = 4, - SG_SAMPLE_8BITS = 8, - SG_SAMPLE_16BITS = 16, - - SG_SAMPLE_UNCOMPRESSED = 0, - SG_SAMPLE_COMPRESSED = 256, - - SG_SAMPLE_MONO8 = (SG_SAMPLE_MONO|SG_SAMPLE_8BITS), - SG_SAMPLE_MONO16 = (SG_SAMPLE_MONO|SG_SAMPLE_16BITS), - SG_SAMPLE_MULAW = (SG_SAMPLE_MONO|SG_SAMPLE_8BITS|SG_SAMPLE_COMPRESSED), - SG_SAMPLE_ADPCM = (SG_SAMPLE_MONO|SG_SAMPLE_4BITS|SG_SAMPLE_COMPRESSED) -}; - - -/** - * manages everything we need to know for an individual audio sample - */ - -class SGSoundSampleInfo -{ -public: - SGSoundSampleInfo(); - ~SGSoundSampleInfo() {} - - /** - * Returns the format of this audio sample. - * @return SimGear format-id - */ - inline unsigned int get_format() { return (_tracks | _bits | _compressed*256); } - - /** - * Get the reference name of this audio sample. - * @return Sample name - */ - inline std::string get_sample_name() const { return _refname; } - - /** - * Returns the frequency (in Herz) of this audio sample. - * @return Frequency - */ - inline unsigned int get_frequency() { return _frequency; } - - /** - * Get the current pitch value of this audio sample. - * @return Pitch - */ - inline float get_pitch() { return _pitch; } - - /** - * Get the final volume value of this audio sample. - * @return Volume - */ - inline float get_volume() { return _volume * _master_volume; } - - /** - * Returns the size (in bytes) of this audio sample. - * @return Data size - */ - inline size_t get_size() const { - return (_samples * _tracks * _bits)/8; - } - - - /** - * Get the absolute position of this sound. - * This is in the same coordinate system as OpenGL; y=up, z=back, x=right. - * @return Absolute position - */ - inline SGVec3d& get_position() { return _absolute_pos; } - - /** - * Get the orientation vector of this sound. - * This is in the same coordinate system as OpenGL; y=up, z=back, x=right - * @return Orientaton vector - */ - inline SGVec3f& get_orientation() { return _orivec; } - - /** - * Get the inner angle of the audio cone. - * @return Inner angle in degrees - */ - inline float get_innerangle() { return _inner_angle; } - - /** - * Get the outer angle of the audio cone. - * @return Outer angle in degrees - */ - inline float get_outerangle() { return _outer_angle; } - - /** - * Get the remaining gain at the edge of the outer cone. - * @return Gain - */ - inline float get_outergain() { return _outer_gain; } - - /** - * Get velocity vector (in meters per second) of this sound. - * This is in the same coordinate system as OpenGL; y=up, z=back, x=right - * @return Velocity vector - */ - inline SGVec3f& get_velocity() { return _velocity; } - - /** - * Get reference distance ((in meters) of this sound. - * This is the distance where the gain will be half. - * @return Reference distance - */ - inline float get_reference_dist() { return _reference_dist; } - - /** - * Get maximum distance (in meters) of this sound. - * This is the distance where this sound is no longer audible. - * @return dist Maximum distance - */ - inline float get_max_dist() { return _max_dist; } - - /** - * Test if static data of audio sample configuration has changed. - * Calling this function will reset the flag so calling it a second - * time in a row will return false. - * @return Return true is the static data has changed in the mean time. - */ - bool has_static_data_changed() { - bool b = _static_changed; _static_changed = false; return b; - } - -protected: - // static sound emitter info - std::string _refname; - unsigned int _bits; - unsigned int _tracks; - unsigned int _samples; - unsigned int _frequency; - bool _compressed; - bool _loop; - - // dynamic sound emitter info (non 3d) - bool _static_changed; - bool _playing; - - float _pitch; - float _volume; - float _master_volume; - - // dynamic sound emitter info (3d) - bool _use_pos_props; - bool _out_of_range; - - float _inner_angle; - float _outer_angle; - float _outer_gain; - - float _reference_dist; - float _max_dist; - - SGPropertyNode_ptr _pos_prop[3]; - SGVec3d _absolute_pos; // absolute position - SGVec3d _relative_pos; // position relative to the base position - SGVec3d _direction; // orientation offset - SGVec3f _velocity; // Velocity of the source sound. - - // The position and orientation of this sound - SGQuatd _orientation; // base orientation - SGVec3f _orivec; // orientation vector - SGVec3d _base_pos; // base position - - SGQuatd _rotation; - -private: - static std::string random_string(); -}; - - -class SGSoundSample : public SGSoundSampleInfo, public SGReferenced { -public: - - /** - * Empty constructor, can be used to read data to the systems - * memory and not to the driver. - */ - SGSoundSample(); - - /** - * Constructor - * @param file File name of sound - Buffer data is freed by the sample group - */ - SGSoundSample(const char *file, const SGPath& currentDir); - - /** - * Constructor. - * @param data Pointer to a memory buffer containing this audio sample data - The application may free the data by calling free_data(), otherwise it - will be resident until the class is destroyed. This pointer will be - set to NULL after calling this function. - * @param len Byte length of array - * @param freq Frequency of the provided data (bytes per second) - * @param format SimGear format id of the data - */ - SGSoundSample( void** data, int len, int freq, int format=SG_SAMPLE_MONO8 ); - SGSoundSample( const unsigned char** data, int len, int freq, - int format = SG_SAMPLE_MONO8 ); - - /** - * Destructor - */ - virtual ~SGSoundSample (); - - /** - * Test if this audio sample configuration has changed since the last call. - * Calling this function will reset the flag so calling it a second - * time in a row will return false. - * @return Return true is the configuration has changed in the mean time. - */ - bool has_changed() { - bool b = _changed; _changed = false; return b; - } - - /** - * Detect whether this audio sample holds the information of a sound file. - * @return Return true if this sample is to be constructed from a file. - */ - inline bool is_file() const { return _is_file; } - - SGPath file_path() const; - - /** - * Schedule this audio sample for playing. Actual playing will only start - * at the next call op SoundGroup::update() - * @param _loop Define whether this sound should be played in a loop. - */ - void play( bool loop = false ) { - _playing = true; _loop = loop; _changed = true; _static_changed = true; - } - - /** - * Check if this audio sample is set to be continuous looping. - * @return Return true if this audio sample is set to looping. - */ - inline bool is_looping() { return _loop; } - - /** - * Schedule this audio sample to stop playing. - */ - virtual void stop() { - _playing = false; _changed = true; - } - - /** - * Schedule this audio sample to play once. - * @see #play - */ - inline void play_once() { play(false); } - - /** - * Schedule this audio sample to play looped. - * @see #play - */ - inline void play_looped() { play(true); } - - /** - * Test if a audio sample is scheduled for playing. - * @return true if this audio sample is playing, false otherwise. - */ - inline bool is_playing() { return _playing; } - - - /** - * Set this sample to out-of-range (or not) and - * Schedule this audio sample to stop (or start) playing. - */ - inline void set_out_of_range(bool oor = true) { - _out_of_range = oor; _playing = (!oor && _loop); _changed = true; - } - - /** - * Test if this sample to out-of-range or not. - */ - inline bool test_out_of_range() { - return _out_of_range; - } - - /** - * Set the data associated with this audio sample - * @param data Pointer to a memory block containg this audio sample data. - This pointer will be set to NULL after calling this function. - */ - inline void set_data( const unsigned char **data ) { - _data = (unsigned char*)*data; *data = NULL; - } - inline void set_data( const void **data ) { - _data = (unsigned char*)*data; *data = NULL; - } - - /** - * Return the data associated with this audio sample. - * @return A pointer to this sound data of this audio sample. - */ - inline void* get_data() const { return _data; } - - /** - * Free the data associated with this audio sample - */ - void free_data(); - - /** - * Set the source id of this source - * @param sid source-id - */ - virtual void set_source(unsigned int sid) { - _source = sid; _valid_source = true; _changed = true; - } - - /** - * Get the source id of this source - * @return source-id - */ - virtual unsigned int get_source() { return _source; } - - /** - * Test if the source-id of this audio sample is usable. - * @return true if the source-id is valid - */ - virtual bool is_valid_source() const { return _valid_source; } - - /** - * Set the source-id of this audio sample to invalid. - */ - virtual void no_valid_source() { _valid_source = false; } - - /** - * Set the buffer-id of this source - * @param bid buffer-id - */ - inline void set_buffer(unsigned int bid) { - _buffer = bid; _valid_buffer = true; _changed = true; - } - - /** - * Get the buffer-id of this source - * @return buffer-id - */ - inline unsigned int get_buffer() { return _buffer; } - - /** - * Test if the buffer-id of this audio sample is usable. - * @return true if the buffer-id is valid - */ - inline bool is_valid_buffer() const { return _valid_buffer; } - - /** - * Set the buffer-id of this audio sample to invalid. - */ - inline void no_valid_buffer() { _valid_buffer = false; } - - /** - * Set the playback pitch of this audio sample. - * Should be between 0.0 and 2.0 for maximum compatibility. - * @param p Pitch - */ - inline void set_pitch( float p ) { - if (p > 2.0) p = 2.0; else if (p < 0.01) p = 0.01; - _pitch = p; _changed = true; - } - - /** - * Set the master volume of this sample. Should be between 0.0 and 1.0. - * The final volume is calculated by multiplying the master and audio sample - * volume. - * @param v Volume - */ - inline void set_master_volume( float v ) { - if (v > 1.0) v = 1.0; else if (v < 0.0) v = 0.0; - _master_volume = v; _changed = true; - } - - /** - * Set the volume of this audio sample. Should be between 0.0 and 1.0. - * The final volume is calculated by multiplying the master and audio sample - * volume. - * @param v Volume - */ - inline void set_volume( float v ) { - if (v > 1.0) v = 1.0; else if (v < 0.0) v = 0.0; - _volume = v; _changed = true; - } - - /** - * Set the SimGear format of this audio sample. - * @param format SimGear format-id - */ - inline void set_format( int fmt ) { - _tracks = fmt & 0x3; _bits = fmt & 0x1C; _compressed = fmt & 0x100; - } - - /** - * Set the frequency (in Herz) of this audio sample. - * @param freq Frequency - */ - inline void set_frequency( int freq ) { _frequency = freq; } - - /** - * Sets the size (in bytes) of this audio sample. - * @param size Data size - */ - inline void set_size( size_t size ) { - _samples = size*8/(_bits*_tracks); - } - inline void set_no_samples(size_t samples) { _samples = samples; } - - /** - * Set the position of this sound relative to the base position. - * This is in the same coordinate system as OpenGL; y=up, z=back, x=right. - * @param pos Relative position of this sound - */ - inline void set_relative_position( const SGVec3f& pos ) { - _relative_pos = toVec3d(pos); _changed = true; - } - - /** - * Set the base position in Cartesian coordinates - * @param pos position in Cartesian coordinates - */ - inline void set_position( const SGVec3d& pos ) { - _base_pos = pos; _changed = true; - } - - inline void set_position_properties(SGPropertyNode_ptr pos[3]) { - _pos_prop[0] = pos[0]; _pos_prop[1] = pos[1]; _pos_prop[2] = pos[2]; - if (pos[0] || pos[1] || pos[2]) _use_pos_props = true; - _changed = true; - } - - /** - * Set the orientation of this sound. - * @param ori Quaternation containing the orientation information - */ - inline void set_orientation( const SGQuatd& ori ) { - _orientation = ori; _changed = true; - } - - inline void set_rotation( const SGQuatd& ec2body ) { - _rotation = ec2body; _changed = true; - } - - /** - * Set direction of this sound relative to the orientation. - * This is in the same coordinate system as OpenGL; y=up, z=back, x=right - * @param dir Sound emission direction - */ - inline void set_direction( const SGVec3f& dir ) { - _direction = toVec3d(dir); _static_changed = true; - } - - /** - * Define the audio cone parameters for directional audio. - * Note: setting it to 2 degree will result in 1 degree to both sides. - * @param inner Inner cone angle (0 - 360 degrees) - * @param outer Outer cone angle (0 - 360 degrees) - * @param gain Remaining gain at the edge of the outer cone (0.0 - 1.0) - */ - void set_audio_cone( float inner, float outer, float gain ) { - _inner_angle = inner; _outer_angle = outer; _outer_gain = gain; - _static_changed = true; - } - - /** - * Set the velocity vector (in meters per second) of this sound. - * This is in the local frame coordinate system; x=north, y=east, z=down - * @param Velocity vector - */ - inline void set_velocity( const SGVec3f& vel ) { - _velocity = vel; _changed = true; - } - - /** - * Set reference distance (in meters) of this sound. - * This is the distance where the gain will be half. - * @param dist Reference distance - */ - inline void set_reference_dist( float dist ) { - _reference_dist = dist; _static_changed = true; - } - - /** - * Set maximum distance (in meters) of this sound. - * This is the distance where this sound is no longer audible. - * @param dist Maximum distance - */ - inline void set_max_dist( float dist ) { - _max_dist = dist; _static_changed = true; - } - - inline virtual bool is_queue() const { return false; } - - void update_pos_and_orientation(); - -protected: - bool _is_file; - bool _changed; - - // Sources are points emitting sound. - bool _valid_source; - unsigned int _source; - -private: - unsigned char* _data; - - // Buffers hold sound data. - bool _valid_buffer; - unsigned int _buffer; -}; - -#endif // _SG_SAMPLE_HXX - - diff --git a/simgear/sound/soundmgr_openal.cxx b/simgear/sound/soundmgr_openal.cxx index a931cd0d..68147b0b 100644 --- a/simgear/sound/soundmgr_openal.cxx +++ b/simgear/sound/soundmgr_openal.cxx @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -215,7 +216,7 @@ void SGSoundMgr::init() // AL_ROLLOFF_FACTOR * (distance - AL_REFERENCE_DISTANCE)); alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); - testForALError("listener initialization"); + testForError("listener initialization"); // get a free source one at a time // if an error is returned no more (hardware) sources are available @@ -296,7 +297,7 @@ void SGSoundMgr::stop() // clear all OpenAL sources BOOST_FOREACH(ALuint source, d->_free_sources) { alDeleteSources( 1 , &source ); - testForALError("SGSoundMgr::stop: delete sources"); + testForError("SGSoundMgr::stop: delete sources"); } d->_free_sources.clear(); @@ -307,7 +308,7 @@ void SGSoundMgr::stop() refUint ref = buffers_current->second; ALuint buffer = ref.id; alDeleteBuffers(1, &buffer); - testForALError("SGSoundMgr::stop: delete buffers"); + testForError("SGSoundMgr::stop: delete buffers"); } d->_buffers.clear(); @@ -396,7 +397,7 @@ if (isNaN(_velocity.data())) printf("NaN in listener velocity\n"); alListenerfv( AL_VELOCITY, toVec3f(velocity).data() ); // alDopplerVelocity(340.3); // TODO: altitude dependent - testForALError("update"); + testForError("update"); _changed = false; } @@ -509,7 +510,7 @@ void SGSoundMgr::release_source( unsigned int source ) } alSourcei( source, AL_BUFFER, 0 ); // detach the associated buffer - testForALError("release_source"); + testForError("release_source"); #endif d->_free_sources.push_back( source ); d->_sources_in_use.erase( it ); @@ -559,7 +560,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample) // create an OpenAL buffer handle alGenBuffers(1, &buffer); - if ( !testForALError("generate buffer") ) { + if ( !testForError("generate buffer") ) { // Copy data to the internal OpenAL buffer ALenum format = AL_NONE; @@ -571,7 +572,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample) ALsizei freq = sample->get_frequency(); alBufferData( buffer, format, sample_data, size, freq ); - if ( !testForALError("buffer add data") ) { + if ( !testForError("buffer add data") ) { sample->set_buffer(buffer); d->_buffers[sample_name] = refUint(buffer); } @@ -605,11 +606,153 @@ void SGSoundMgr::release_buffer(SGSoundSample *sample) alDeleteBuffers(1, &buffer); #endif d->_buffers.erase( buffer_it ); - testForALError("release buffer"); + testForError("release buffer"); } } } +void SGSoundMgr::sample_suspend( SGSoundSample *sample ) +{ + if ( sample->is_valid_source() && sample->is_playing() ) { + alSourcePause( sample->get_source() ); + } +} + +void SGSoundMgr::sample_resume( SGSoundSample *sample ) +{ + if ( sample->is_valid_source() && sample->is_playing() ) { + alSourcePlay( sample->get_source() ); + } +} + +void SGSoundMgr::sample_init( SGSoundSample *sample ) +{ +#ifdef ENABLE_SOUND + // + // a request to start playing a sound has been filed. + // + ALuint source = request_source(); + if (alIsSource(source) == AL_FALSE ) { + return; + } + + sample->set_source( source ); +#endif +} + +void SGSoundMgr::sample_play( SGSoundSample *sample ) +{ +#ifdef ENABLE_SOUND + ALboolean looping = sample->is_looping() ? AL_TRUE : AL_FALSE; + ALint source = sample->get_source(); + + if ( !sample->is_queue() ) + { + ALuint buffer = request_buffer(sample); + if (buffer == SGSoundMgr::FAILED_BUFFER || + buffer == SGSoundMgr::NO_BUFFER) + { + release_source(source); + return; + } + + // start playing the sample + buffer = sample->get_buffer(); + if ( alIsBuffer(buffer) == AL_TRUE ) + { + alSourcei( source, AL_BUFFER, buffer ); + testForError("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 ); + testForError("sample play"); +#endif +} + +void SGSoundMgr::sample_stop( SGSoundSample *sample ) +{ + if ( sample->is_valid_source() ) { + int source = sample->get_source(); + + bool stopped = is_sample_stopped(sample); + if ( sample->is_looping() && !stopped) { +#ifdef ENABLE_SOUND + alSourceStop( source ); +#endif + stopped = is_sample_stopped(sample); + } + + if ( stopped ) { + sample->no_valid_source(); + release_source( source ); + } + } +} + +void SGSoundMgr::sample_destroy( SGSoundSample *sample ) +{ + if ( sample->is_valid_source() ) { +#ifdef ENABLE_SOUND + ALint source = sample->get_source(); + if ( sample->is_playing() ) { + alSourceStop( source ); + testForError("stop"); + } + release_source( source ); +#endif + sample->no_valid_source(); + } + + if ( sample->is_valid_buffer() ) { + release_buffer( sample ); + sample->no_valid_buffer(); + } +} + +bool SGSoundMgr::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 SGSoundMgr::update_sample_config( SGSoundSample *sample, SGVec3d& position, SGVec3f& orientation, SGVec3f& velocity ) +{ + 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() ); + testForError("position and orientation"); + + alSourcef( source, AL_PITCH, sample->get_pitch() ); + alSourcef( source, AL_GAIN, sample->get_volume() ); + testForError("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() ); + testForError("audio cone"); + + alSourcef( source, AL_MAX_DISTANCE, sample->get_max_dist() ); + alSourcef( source, AL_REFERENCE_DISTANCE, + sample->get_reference_dist() ); + testForError("distance rolloff"); + } +} + + bool SGSoundMgr::load( const std::string &samplepath, void **dbuf, int *fmt, @@ -683,12 +826,12 @@ bool SGSoundMgr::testForError(void *p, std::string s) } -bool SGSoundMgr::testForALError(std::string s) +bool SGSoundMgr::testForError(std::string s, std::string name) { #ifdef ENABLE_SOUND ALenum error = alGetError(); if (error != AL_NO_ERROR) { - SG_LOG( SG_SOUND, SG_ALERT, "AL Error (sound manager): " + SG_LOG( SG_SOUND, SG_ALERT, "AL Error (" << name << "): " << alGetString(error) << " at " << s); return true; } diff --git a/simgear/sound/soundmgr_openal.hxx b/simgear/sound/soundmgr_openal.hxx index 19897e32..60f07367 100644 --- a/simgear/sound/soundmgr_openal.hxx +++ b/simgear/sound/soundmgr_openal.hxx @@ -225,6 +225,63 @@ public: */ void release_buffer( SGSoundSample *sample ); + /** + * Initialize sample for playback. + * + * @param sample Pointer to an audio sample to initialize. + */ + void sample_init( SGSoundSample *sample ); + + /** + * Stop and destroy a sample + * + * @param sample Pointer to an audio sample to destroy. + */ + void sample_destroy( SGSoundSample *sample ); + + /** + * Start playback of a sample + * + * @param sample Pointer to an audio sample to start playing. + */ + void sample_play( SGSoundSample *sample ); + + /** + * Stop a sample + * + * @param sample Pointer to an audio sample to stop. + */ + void sample_stop( SGSoundSample *sample ); + + /** + * Suspend playback of a sample + * + * @param sample Pointer to an audio sample to suspend. + */ + void sample_suspend( SGSoundSample *sample ); + + /** + * Resume playback of a sample + * + * @param sample Pointer to an audio sample to resume. + */ + void sample_resume( SGSoundSample *sample ); + + /** + * Check if a sample is stopped, or still playing + * + * @param sample Pointer to an audio sample to test. + * @return true if the sample is stopped. + */ + bool is_sample_stopped( SGSoundSample *sample ); + + /** + * Update all status and 3d parameters of a sample. + * + * @param sample Pointer to an audio sample to update. + */ + void update_sample_config( SGSoundSample *sample, SGVec3d& position, SGVec3f& orientation, SGVec3f& velocity ); + /** * Test if the position of the sound manager has changed. * The value will be set to false upon the next call to update_late() @@ -268,6 +325,8 @@ public: const std::string& get_vendor() { return _vendor; } const std::string& get_renderer() { return _renderer; } + bool testForError(std::string s, std::string name = "sound manager"); + static const char* subsystemName() { return "sound"; }; private: class SoundManagerPrivate; @@ -290,7 +349,6 @@ private: std::string _vendor; std::string _device_name; - bool testForALError(std::string s); bool testForALCError(std::string s); bool testForError(void *p, std::string s); diff --git a/simgear/sound/soundmgr_openal_private.hxx b/simgear/sound/soundmgr_openal_private.hxx index 8fb0c796..6bc3591f 100644 --- a/simgear/sound/soundmgr_openal_private.hxx +++ b/simgear/sound/soundmgr_openal_private.hxx @@ -47,6 +47,10 @@ # include #endif +#include + +class SGSampleGroup; + struct refUint { unsigned int refctr; ALuint id; diff --git a/simgear/sound/xmlsound.cxx b/simgear/sound/xmlsound.cxx index fb3e7d73..36907f5b 100644 --- a/simgear/sound/xmlsound.cxx +++ b/simgear/sound/xmlsound.cxx @@ -40,7 +40,7 @@ #include #include "sample_group.hxx" -#include "sample_openal.hxx" +#include "sample.hxx" using std::string;