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 \
$(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\"
--- /dev/null
+#include <stdio.h>
+#ifdef _WIN32
+#include <windows.h>
+#define sleep(x) Sleep(x*1000)
+#else
+#include <unistd.h>
+#endif
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/sg_path.hxx>
+
+#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;
+}
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;
//
// 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() ) {
if ( sample_it->second->is_valid_buffer() )
_removed_samples.push_back( sample_it->second );
+
_samples.erase( sample_it );
return true;
sample->no_valid_source();
}
- if (sample->is_valid_buffer() ) {
+ if ( sample->is_valid_buffer() ) {
_smgr->release_buffer( sample );
sample->no_valid_buffer();
}
#include <simgear/structure/exception.hxx>
#include "sample_openal.hxx"
+#include "sample_queue.hxx"
using std::map;
using std::string;
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/SGMath.hxx>
-// #include <plib/sg.h>
/**
* manages everything we need to know for an individual audio sample
* 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;
}
/**
* Schedule this audio sample to stop playing.
*/
- void stop() {
+ virtual void stop() {
_playing = false; _changed = true;
}
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;
}
* 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;
}
* 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;
}
*/
inline std::string get_sample_name() const { return _refname; }
+ inline virtual bool is_queue() const { return false; }
+
void update_pos_and_orientation();
private:
--- /dev/null
+// 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 <erik@ehofman.com>
+//
+// 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 <simgear_config.h>
+#endif
+
+#include <stdlib.h> // rand()
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/structure/exception.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/math/SGMath.hxx>
+
+#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<num; i++) {
+ ALuint buffer;
+ alSourceUnqueueBuffers(_source, 1, &buffer);
+ alDeleteBuffers(1, &buffer);
+ }
+ _buffers.clear();
+
+ _playing = false;
+ _changed = true;
+}
+
+void SGSampleQueue::add( const void* smp_data, size_t len )
+{
+ const ALvoid *data = (const ALvoid *)smp_data;
+ ALuint buffer;
+ ALint num;
+
+ if ( _valid_source )
+ {
+ alGetSourcei(_source, AL_BUFFERS_PROCESSED, &num);
+ if (num > 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;
+}
--- /dev/null
+// queue.hxx -- Sample Queue encapsulation class
+//
+// based on sample.hxx
+//
+// Copyright (C) 2010 Erik Hofman <erik@ehofman.com>
+//
+// 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 <string>
+#include <vector>
+
+#include <simgear/compiler.h>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/structure/SGReferenced.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
+#include <simgear/math/SGMath.hxx>
+
+#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<unsigned int> _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
+
+
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");
+ }
}
}