Initial commit for a sample queue extension.

This commit is contained in:
Erik Hofman
2010-08-02 10:10:58 +02:00
parent c46c735f2f
commit 67c8067aed
8 changed files with 456 additions and 54 deletions

View File

@@ -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\"

View File

@@ -0,0 +1,71 @@
#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;
}

View File

@@ -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");
if ( sample->is_queue() )
{
sample->set_source( source );
update_sample_config( sample );
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;
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
// 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();
}

View File

@@ -52,6 +52,7 @@
#include <simgear/structure/exception.hxx>
#include "sample_openal.hxx"
#include "sample_queue.hxx"
using std::map;
using std::string;

View File

@@ -42,7 +42,6 @@
#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
@@ -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:

View File

@@ -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 <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;
}

View File

@@ -0,0 +1,157 @@
// 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

View File

@@ -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");
}
}
}