From 67c8067aed14b90cc9103c48031c0a32fa29ce1e Mon Sep 17 00:00:00 2001 From: Erik Hofman Date: Mon, 2 Aug 2010 10:10:58 +0200 Subject: [PATCH] Initial commit for a sample queue extension. --- simgear/sound/Makefile.am | 22 ++++- simgear/sound/openal_test4.cxx | 71 ++++++++++++++ simgear/sound/sample_group.cxx | 74 ++++++++------ simgear/sound/sample_group.hxx | 1 + simgear/sound/sample_openal.hxx | 19 ++-- simgear/sound/sample_queue.cxx | 141 +++++++++++++++++++++++++++ simgear/sound/sample_queue.hxx | 157 ++++++++++++++++++++++++++++++ simgear/sound/soundmgr_openal.cxx | 29 +++--- 8 files changed, 458 insertions(+), 56 deletions(-) create mode 100644 simgear/sound/openal_test4.cxx create mode 100644 simgear/sound/sample_queue.cxx create mode 100644 simgear/sound/sample_queue.hxx diff --git a/simgear/sound/Makefile.am b/simgear/sound/Makefile.am index e76fed45..7719f107 100644 --- a/simgear/sound/Makefile.am +++ b/simgear/sound/Makefile.am @@ -7,22 +7,25 @@ lib_LIBRARIES = libsgsound.a noinst_HEADERS = include_HEADERS = \ + soundmgr_openal.hxx \ sample_group.hxx \ sample_openal.hxx \ - soundmgr_openal.hxx \ - xmlsound.hxx + sample_queue.hxx \ + xmlsound.hxx libsgsound_a_SOURCES = \ + soundmgr_openal.cxx \ sample_group.cxx \ sample_openal.cxx \ - soundmgr_openal.cxx \ - xmlsound.cxx + sample_queue.cxx \ + xmlsound.cxx -noinst_PROGRAMS = openal_test1 openal_test2 openal_test3 +check_PROGRAMS = openal_test1 openal_test2 openal_test3 openal_test4 openal_test1_SOURCES = openal_test1.cxx openal_test2_SOURCES = openal_test2.cxx openal_test3_SOURCES = openal_test3.cxx +openal_test4_SOURCES = openal_test4.cxx openal_test1_LDADD = \ $(top_builddir)/simgear/debug/libsgdebug.a \ @@ -46,4 +49,13 @@ openal_test3_LDADD = \ $(top_builddir)/simgear/math/libsgmath.a \ $(openal_LIBS) -lstdc++ +openal_test4_LDADD = \ + libsgsound.a \ + $(top_builddir)/simgear/structure/libsgstructure.a \ + $(top_builddir)/simgear/timing/libsgtiming.a \ + $(top_builddir)/simgear/debug/libsgdebug.a \ + $(top_builddir)/simgear/misc/libsgmisc.a \ + $(top_builddir)/simgear/math/libsgmath.a \ + $(openal_LIBS) -lstdc++ + INCLUDES = -I$(top_srcdir) -DSRC_DIR=\"$(top_srcdir)/simgear/sound\" diff --git a/simgear/sound/openal_test4.cxx b/simgear/sound/openal_test4.cxx new file mode 100644 index 00000000..320b6e6f --- /dev/null +++ b/simgear/sound/openal_test4.cxx @@ -0,0 +1,71 @@ +#include +#ifdef _WIN32 +#include +#define sleep(x) Sleep(x*1000) +#else +#include +#endif + +#include +#include + +#include "soundmgr_openal.hxx" + + +int main( int argc, char *argv[] ) { + SGSampleQueue *squeue; + SGSampleGroup *sgr; + SGSoundMgr *smgr; + SGGeod pos; + + smgr = new SGSoundMgr; + + smgr->bind(); + smgr->init("OSS Default"); + sgr = smgr->find("default", true); + smgr->set_volume(0.9); + smgr->activate(); + + + void *data; + size_t len; + int freq, fmt; + string file = SRC_DIR"/jet.wav"; + smgr->load(file, &data, &fmt, &len, &freq); + + squeue = new SGSampleQueue( freq, fmt ); + sgr->add(squeue, "queue"); + + squeue->add( data, len ); + squeue->add( data, len ); + squeue->play(); + printf("playing queue\n"); + + smgr->update(1.0); + sleep(10); + smgr->update(10.0); + + printf("source at lat,lon = (10,-10), listener at (9.99,-9.99)\n"); + pos = SGGeod::fromDeg(9.99,-9.99); + squeue->set_position( SGVec3d::fromGeod(SGGeod::fromDeg(10,-10)) ); + smgr->set_position( SGVec3d::fromGeod(pos), pos ); + + squeue->add( data, len ); + squeue->add( data, len ); + squeue->play( true ); // play looped + printf("playing queue\n"); + + smgr->update(1.0); + sleep(10); + smgr->update(10.0); + + squeue->stop(); + smgr->update(1.0); + sleep(1); + + sgr->remove("queue"); + smgr->unbind(); + sleep(2); + + delete smgr; +} diff --git a/simgear/sound/sample_group.cxx b/simgear/sound/sample_group.cxx index a4fbfc49..99a5a0eb 100644 --- a/simgear/sound/sample_group.cxx +++ b/simgear/sound/sample_group.cxx @@ -104,9 +104,11 @@ void SGSampleGroup::update( double dt ) { if ( result == AL_STOPPED ) { sample->stop(); - ALuint buffer = sample->get_buffer(); - alDeleteBuffers( 1, &buffer ); - testForALError("buffer remove"); + if ( !sample->is_queue() ) { + ALuint buffer = sample->get_buffer(); + alDeleteBuffers( 1, &buffer ); + testForALError("buffer remove"); + } _removed_samples.erase( _removed_samples.begin()+i ); size--; continue; @@ -129,33 +131,46 @@ void SGSampleGroup::update( double dt ) { // // 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) + if (alIsSource(source) == 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, 0.3 ); - 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 + if ( sample->is_queue() ) + { + sample->set_source( source ); + update_sample_config( sample ); + + alSourcef( source, AL_ROLLOFF_FACTOR, 0.3 ); + alSourcei( source, AL_LOOPING, AL_FALSE); + alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE ); + alSourcePlay( source ); + testForALError("sample play"); + } + else + { + if (_smgr->request_buffer(sample) == SGSoundMgr::NO_BUFFER) + continue; + + // start playing the sample + ALuint buffer = sample->get_buffer(); + if ( alIsBuffer(buffer) == AL_TRUE ) + { + ALboolean looping; + + alSourcei( source, AL_BUFFER, buffer ); + testForALError("assign buffer to source"); + + sample->set_source( source ); + update_sample_config( sample ); + + looping = sample->is_looping() ? AL_TRUE : AL_FALSE; + alSourcei( source, AL_LOOPING, looping ); + alSourcef( source, AL_ROLLOFF_FACTOR, 0.3 ); + alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE ); + alSourcePlay( source ); + testForALError("sample play"); + } else + SG_LOG( SG_GENERAL, SG_ALERT, "No such buffer!\n"); + } } } else if ( sample->is_valid_source() ) { @@ -215,6 +230,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; @@ -265,7 +281,7 @@ SGSampleGroup::stop () sample->no_valid_source(); } - if (sample->is_valid_buffer() ) { + if ( sample->is_valid_buffer() ) { _smgr->release_buffer( sample ); sample->no_valid_buffer(); } diff --git a/simgear/sound/sample_group.hxx b/simgear/sound/sample_group.hxx index d2d47394..59d42b32 100644 --- a/simgear/sound/sample_group.hxx +++ b/simgear/sound/sample_group.hxx @@ -52,6 +52,7 @@ #include #include "sample_openal.hxx" +#include "sample_queue.hxx" using std::map; using std::string; diff --git a/simgear/sound/sample_openal.hxx b/simgear/sound/sample_openal.hxx index d2cb1824..362915b0 100644 --- a/simgear/sound/sample_openal.hxx +++ b/simgear/sound/sample_openal.hxx @@ -42,7 +42,6 @@ #include #include -// #include /** * manages everything we need to know for an individual audio sample @@ -115,7 +114,7 @@ public: * at the next call op SoundGroup::update() * @param _loop Define whether this sound should be played in a loop. */ - void play( bool loop ) { + void play( bool loop = false ) { _playing = true; _loop = loop; _changed = true; } @@ -128,7 +127,7 @@ public: /** * Schedule this audio sample to stop playing. */ - void stop() { + virtual void stop() { _playing = false; _changed = true; } @@ -158,7 +157,7 @@ public: inline void set_data( const unsigned char **data ) { _data = (unsigned char*)*data; *data = NULL; } - inline void set_data( void **data ) { + inline void set_data( const void **data ) { _data = (unsigned char*)*data; *data = NULL; } @@ -179,7 +178,7 @@ public: * Set the source id of this source * @param sid OpenAL source-id */ - void set_source(unsigned int sid) { + virtual inline void set_source(unsigned int sid) { _source = sid; _valid_source = true; _changed = true; } @@ -187,24 +186,24 @@ public: * Get the OpenAL source id of this source * @return OpenAL source-id */ - inline unsigned int get_source() { return _source; } + virtual inline unsigned int get_source() { return _source; } /** * Test if the source-id of this audio sample may be passed to OpenAL. * @return true if the source-id is valid */ - inline bool is_valid_source() const { return _valid_source; } + virtual inline bool is_valid_source() const { return _valid_source; } /** * Set the source-id of this audio sample to invalid. */ - inline void no_valid_source() { _valid_source = false; } + virtual inline void no_valid_source() { _valid_source = false; } /** * Set the OpenAL buffer-id of this source * @param bid OpenAL buffer-id */ - void set_buffer(unsigned int bid) { + inline void set_buffer(unsigned int bid) { _buffer = bid; _valid_buffer = true; _changed = true; } @@ -443,6 +442,8 @@ public: */ inline std::string get_sample_name() const { return _refname; } + inline virtual bool is_queue() const { return false; } + void update_pos_and_orientation(); private: diff --git a/simgear/sound/sample_queue.cxx b/simgear/sound/sample_queue.cxx new file mode 100644 index 00000000..a7eeac1a --- /dev/null +++ b/simgear/sound/sample_queue.cxx @@ -0,0 +1,141 @@ +// queue.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() + +#include +#include +#include +#include + +#include "soundmgr_openal.hxx" +#include "sample_queue.hxx" + + +// +// SGSampleQueue +// + +// empty constructor +SGSampleQueue::SGSampleQueue( int freq, int format ) : + _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()), + _refname(random_string()), + _format(format), + _freq(freq), + _valid_source(false), + _source(SGSoundMgr::NO_SOURCE), + _inner_angle(360.0), + _outer_angle(360.0), + _outer_gain(0.0), + _pitch(1.0), + _volume(1.0), + _master_volume(1.0), + _reference_dist(500.0), + _max_dist(3000.0), + _playing(false), + _changed(true) +{ + _buffers.clear(); +} + +SGSampleQueue::~SGSampleQueue() { + stop(); +} + +void SGSampleQueue::stop() +{ + ALint num; + alGetSourcei(_source, AL_BUFFERS_PROCESSED, &num); + for (int i=0; i 1) { + alSourceUnqueueBuffers(_source, 1, &buffer); + } else { + alGenBuffers(1, &buffer); + } + alBufferData(buffer, _format, data, len, _freq); + } + else + { + alGenBuffers(1, &buffer); + alBufferData(buffer, _format, data, len, _freq); + _buffers.push_back(buffer); + } +} + +void SGSampleQueue::set_source( unsigned int sid ) +{ + _source = sid; + _valid_source = true; + _changed = true; + + ALuint num = _buffers.size(); + for (unsigned int i=0; i < num; i++) + { + ALuint buffer = _buffers[i]; + alSourceQueueBuffers(_source, 1, &buffer); + } + _buffers.clear(); + +} + +string SGSampleQueue::random_string() { + static const char *r = "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + string rstr = "Queued sample: "; + for (int i=0; i<10; i++) { + rstr.push_back( r[rand() % strlen(r)] ); + } + + return rstr; +} diff --git a/simgear/sound/sample_queue.hxx b/simgear/sound/sample_queue.hxx new file mode 100644 index 00000000..32d49d3e --- /dev/null +++ b/simgear/sound/sample_queue.hxx @@ -0,0 +1,157 @@ +// queue.hxx -- Sample Queue encapsulation class +// +// based on sample.hxx +// +// Copyright (C) 2010 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 sample queue encapsulation + */ + +#ifndef _SG_QUEUE_HXX +#define _SG_QUEUE_HXX 1 + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include "sample_openal.hxx" + +/** + * manages everything we need to know for an individual audio sample + */ + +class SGSampleQueue : public SGSoundSample { +public: + + + /** + * Empty constructor, can be used to read data to the systems + * memory and not to the driver. + * @param freq sample frequentie of the samples + * @param format OpenAL format id of the data + */ + SGSampleQueue(int freq, int format = AL_FORMAT_MONO8); + + /** + * Destructor + */ + ~SGSampleQueue (); + + /** + * Schedule this audio sample to stop playing. + */ + virtual void stop(); + + /** + * Queue new data for this audio sample + * @param data Pointer to a memory block containg this audio sample data. + * @param len length of the sample buffer in bytes + */ + void add( const void* smp_data, size_t len ); + + /** + * Set the source id of this source + * @param sid OpenAL source-id + */ + virtual void set_source(unsigned int sid); + + /** + * Get the OpenAL source id of this source + * @return OpenAL source-id + */ + virtual inline unsigned int get_source() { return _source; } + + /** + * Test if the source-id of this audio sample may be passed to OpenAL. + * @return true if the source-id is valid + */ + virtual inline bool is_valid_source() const { return _valid_source; } + + /** + * Set the source-id of this audio sample to invalid. + */ + virtual inline void no_valid_source() { _valid_source = false; } + + /** + * Test if the buffer-id of this audio sample may be passed to OpenAL. + * @return false for sample queue + */ + inline bool is_valid_buffer() const { return false; } + + inline virtual bool is_queue() const { return true; } + +private: + + // Position of the source sound. + 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 for OpenAL + SGVec3d _base_pos; // base position + + SGQuatd _rotation; + + std::string _refname; // sample name + std::vector _buffers; + unsigned int _buffer; + + // configuration values + int _format; + int _freq; + + // Sources are points emitting sound. + bool _valid_source; + unsigned int _source; + + // The orientation of this sound (direction and cut-off angles) + float _inner_angle; + float _outer_angle; + float _outer_gain; + + float _pitch; + float _volume; + float _master_volume; + float _reference_dist; + float _max_dist; + + bool _playing; + bool _changed; + + string random_string(); +}; + + +#endif // _SG_QUEUE_HXX + + diff --git a/simgear/sound/soundmgr_openal.cxx b/simgear/sound/soundmgr_openal.cxx index 750c4b0f..e91cf767 100644 --- a/simgear/sound/soundmgr_openal.cxx +++ b/simgear/sound/soundmgr_openal.cxx @@ -508,20 +508,23 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample) void SGSoundMgr::release_buffer(SGSoundSample *sample) { - string sample_name = sample->get_sample_name(); - buffer_map_iterator buffer_it = _buffers.find( sample_name ); - if ( buffer_it == _buffers.end() ) { - // buffer was not found - return; - } + if ( !sample->is_queue() ) + { + string sample_name = sample->get_sample_name(); + buffer_map_iterator buffer_it = _buffers.find( sample_name ); + if ( buffer_it == _buffers.end() ) { + // buffer was not found + return; + } - sample->no_valid_buffer(); - buffer_it->second.refctr--; - if (buffer_it->second.refctr == 0) { - ALuint buffer = buffer_it->second.id; - alDeleteBuffers(1, &buffer); - _buffers.erase( buffer_it ); - testForALError("release buffer"); + sample->no_valid_buffer(); + buffer_it->second.refctr--; + if (buffer_it->second.refctr == 0) { + ALuint buffer = buffer_it->second.id; + alDeleteBuffers(1, &buffer); + _buffers.erase( buffer_it ); + testForALError("release buffer"); + } } } -- 2.39.5