Move the FlightGear sound code over to SimGear
This commit is contained in:
@@ -423,6 +423,7 @@ AC_CONFIG_FILES([ \
|
|||||||
simgear/serial/Makefile \
|
simgear/serial/Makefile \
|
||||||
simgear/sky/Makefile \
|
simgear/sky/Makefile \
|
||||||
simgear/sky/clouds3d/Makefile \
|
simgear/sky/clouds3d/Makefile \
|
||||||
|
simgear/sound/Makefile \
|
||||||
simgear/threads/Makefile \
|
simgear/threads/Makefile \
|
||||||
simgear/timing/Makefile \
|
simgear/timing/Makefile \
|
||||||
simgear/xgl/Makefile \
|
simgear/xgl/Makefile \
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ SUBDIRS = \
|
|||||||
screen \
|
screen \
|
||||||
serial \
|
serial \
|
||||||
sky \
|
sky \
|
||||||
|
sound \
|
||||||
$(SGTHREAD_DIR) \
|
$(SGTHREAD_DIR) \
|
||||||
timing \
|
timing \
|
||||||
xgl
|
xgl
|
||||||
|
|||||||
@@ -27,4 +27,5 @@ include_HEADERS = \
|
|||||||
cstddef \
|
cstddef \
|
||||||
ctime \
|
ctime \
|
||||||
iomanip \
|
iomanip \
|
||||||
|
new \
|
||||||
streambuf
|
streambuf
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
#ifndef __SG_NEW
|
||||||
|
#define __SG_NEW 1
|
||||||
|
|
||||||
|
#if defined(sgi) && !defined(__GNUC__)
|
||||||
|
|
||||||
|
# include <new.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // !__SG_NEW
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.deps
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
includedir = @includedir@/sound
|
||||||
|
|
||||||
|
lib_LIBRARIES = libsgsound.a
|
||||||
|
|
||||||
|
noinst_HEADERS =
|
||||||
|
|
||||||
|
include_HEADERS = sound.hxx soundmgr.hxx
|
||||||
|
|
||||||
|
libsgsound_a_SOURCES = sound.cxx soundmgr.cxx
|
||||||
|
|
||||||
|
INCLUDES = -I$(top_srcdir)
|
||||||
@@ -0,0 +1,408 @@
|
|||||||
|
// sound.cxx -- Sound class implementation
|
||||||
|
//
|
||||||
|
// Started by Erik Hofman, February 2002
|
||||||
|
// (Reuses some code from fg_fx.cxx created by David Megginson)
|
||||||
|
//
|
||||||
|
// Copyright (C) 2002 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#ifdef SG_HAVE_STD_INCLUDES
|
||||||
|
# include <cmath>
|
||||||
|
#else
|
||||||
|
# include <math.h>
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/props/condition.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
#include "sound.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// static double _snd_lin(double v) { return v; }
|
||||||
|
static double _snd_inv(double v) { return (v == 0) ? 1e99 : 1/v; }
|
||||||
|
static double _snd_abs(double v) { return (v >= 0) ? v : -v; }
|
||||||
|
static double _snd_sqrt(double v) { return (v < 0) ? sqrt(-v) : sqrt(v); }
|
||||||
|
static double _snd_log10(double v) { return (v < 1) ? 0 : log10(v); }
|
||||||
|
static double _snd_log(double v) { return (v < 1) ? 0 : log(v); }
|
||||||
|
// static double _snd_sqr(double v) { return pow(v, 2); }
|
||||||
|
// static double _snd_pow3(double v) { return pow(v, 3); }
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
char *name;
|
||||||
|
double (*fn)(double);
|
||||||
|
} __sound_fn[] = {
|
||||||
|
// {"lin", _snd_lin},
|
||||||
|
{"inv", _snd_inv},
|
||||||
|
{"abs", _snd_abs},
|
||||||
|
{"sqrt", _snd_sqrt},
|
||||||
|
{"log", _snd_log10},
|
||||||
|
{"ln", _snd_log},
|
||||||
|
// {"sqr", _snd_sqr},
|
||||||
|
// {"pow3", _snd_pow3},
|
||||||
|
{"", NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
Sound::Sound()
|
||||||
|
: _sample(NULL),
|
||||||
|
_condition(NULL),
|
||||||
|
_property(NULL),
|
||||||
|
_active(false),
|
||||||
|
_name(""),
|
||||||
|
_mode(Sound::ONCE),
|
||||||
|
_prev_value(0),
|
||||||
|
_dt_play(0.0),
|
||||||
|
_dt_stop(0.0),
|
||||||
|
_stopping(0.0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Sound::~Sound()
|
||||||
|
{
|
||||||
|
_mgr->get_scheduler()->stopSample(_sample->get_sample());
|
||||||
|
|
||||||
|
if (_property)
|
||||||
|
delete _property;
|
||||||
|
|
||||||
|
if (_condition)
|
||||||
|
delete _condition;
|
||||||
|
|
||||||
|
_volume.clear();
|
||||||
|
_pitch.clear();
|
||||||
|
delete _sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Sound::init(SGPropertyNode *root, SGPropertyNode *node, SoundMgr *sndmgr,
|
||||||
|
const string &path)
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// set global sound properties
|
||||||
|
//
|
||||||
|
|
||||||
|
_name = node->getStringValue("name", "");
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "Loading sound information for: " << _name );
|
||||||
|
|
||||||
|
const char *mode_str = node->getStringValue("mode", "");
|
||||||
|
if ( !strcmp(mode_str, "looped") ) {
|
||||||
|
_mode = Sound::LOOPED;
|
||||||
|
|
||||||
|
} else if ( !strcmp(mode_str, "in-transit") ) {
|
||||||
|
_mode = Sound::IN_TRANSIT;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_mode = Sound::ONCE;
|
||||||
|
|
||||||
|
if ( strcmp(mode_str, "") )
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, " Unknown sound mode, default to 'once'");
|
||||||
|
}
|
||||||
|
|
||||||
|
_property = root->getNode(node->getStringValue("property", ""), true);
|
||||||
|
SGPropertyNode *condition = node->getChild("condition");
|
||||||
|
if (condition != NULL)
|
||||||
|
_condition = fgReadCondition(root, condition);
|
||||||
|
|
||||||
|
if (!_property && !_condition)
|
||||||
|
SG_LOG(SG_GENERAL, SG_WARN,
|
||||||
|
" Neither a condition nor a property specified");
|
||||||
|
|
||||||
|
//
|
||||||
|
// set volume properties
|
||||||
|
//
|
||||||
|
unsigned int i;
|
||||||
|
float v = 0.0;
|
||||||
|
vector<SGPropertyNode_ptr> kids = node->getChildren("volume");
|
||||||
|
for (i = 0; (i < kids.size()) && (i < Sound::MAXPROP); i++) {
|
||||||
|
_snd_prop volume = {NULL, NULL, NULL, 1.0, 0.0, 0.0, 0.0, false};
|
||||||
|
|
||||||
|
if (strcmp(kids[i]->getStringValue("property"), ""))
|
||||||
|
volume.prop = root->getNode(kids[i]->getStringValue("property", ""), true);
|
||||||
|
|
||||||
|
const char *intern_str = kids[i]->getStringValue("internal", "");
|
||||||
|
if (!strcmp(intern_str, "dt_play"))
|
||||||
|
volume.intern = &_dt_play;
|
||||||
|
else if (!strcmp(intern_str, "dt_stop"))
|
||||||
|
volume.intern = &_dt_stop;
|
||||||
|
|
||||||
|
if ((volume.factor = kids[i]->getDoubleValue("factor", 1.0)) != 0.0)
|
||||||
|
if (volume.factor < 0.0) {
|
||||||
|
volume.factor = -volume.factor;
|
||||||
|
volume.subtract = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *type_str = kids[i]->getStringValue("type", "");
|
||||||
|
if ( strcmp(type_str, "") ) {
|
||||||
|
|
||||||
|
for (int j=0; __sound_fn[j].fn; j++)
|
||||||
|
if ( !strcmp(type_str, __sound_fn[j].name) ) {
|
||||||
|
volume.fn = __sound_fn[j].fn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!volume.fn)
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO,
|
||||||
|
" Unknown volume type, default to 'lin'");
|
||||||
|
}
|
||||||
|
|
||||||
|
volume.offset = kids[i]->getDoubleValue("offset", 0.0);
|
||||||
|
|
||||||
|
if ((volume.min = kids[i]->getDoubleValue("min", 0.0)) < 0.0)
|
||||||
|
SG_LOG( SG_GENERAL, SG_WARN,
|
||||||
|
"Volume minimum value below 0. Forced to 0.");
|
||||||
|
|
||||||
|
volume.max = kids[i]->getDoubleValue("max", 0.0);
|
||||||
|
if (volume.max && (volume.max < volume.min) )
|
||||||
|
SG_LOG(SG_GENERAL,SG_ALERT,
|
||||||
|
" Volume maximum below minimum. Neglected.");
|
||||||
|
|
||||||
|
_volume.push_back(volume);
|
||||||
|
v += volume.offset;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// set pitch properties
|
||||||
|
//
|
||||||
|
float p = 0.0;
|
||||||
|
kids = node->getChildren("pitch");
|
||||||
|
for (i = 0; (i < kids.size()) && (i < Sound::MAXPROP); i++) {
|
||||||
|
_snd_prop pitch = {NULL, NULL, NULL, 1.0, 1.0, 0.0, 0.0, false};
|
||||||
|
|
||||||
|
if (strcmp(kids[i]->getStringValue("property", ""), ""))
|
||||||
|
pitch.prop = root->getNode(kids[i]->getStringValue("property", ""), true);
|
||||||
|
|
||||||
|
const char *intern_str = kids[i]->getStringValue("internal", "");
|
||||||
|
if (!strcmp(intern_str, "dt_play"))
|
||||||
|
pitch.intern = &_dt_play;
|
||||||
|
else if (!strcmp(intern_str, "dt_stop"))
|
||||||
|
pitch.intern = &_dt_stop;
|
||||||
|
|
||||||
|
if ((pitch.factor = kids[i]->getDoubleValue("factor", 1.0)) != 0.0)
|
||||||
|
if (pitch.factor < 0.0) {
|
||||||
|
pitch.factor = -pitch.factor;
|
||||||
|
pitch.subtract = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *type_str = kids[i]->getStringValue("type", "");
|
||||||
|
if ( strcmp(type_str, "") ) {
|
||||||
|
|
||||||
|
for (int j=0; __sound_fn[j].fn; j++)
|
||||||
|
if ( !strcmp(type_str, __sound_fn[j].name) ) {
|
||||||
|
pitch.fn = __sound_fn[j].fn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pitch.fn)
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO,
|
||||||
|
" Unknown pitch type, default to 'lin'");
|
||||||
|
}
|
||||||
|
|
||||||
|
pitch.offset = kids[i]->getDoubleValue("offset", 1.0);
|
||||||
|
|
||||||
|
if ((pitch.min = kids[i]->getDoubleValue("min", 0.0)) < 0.0)
|
||||||
|
SG_LOG(SG_GENERAL,SG_WARN,
|
||||||
|
" Pitch minimum value below 0. Forced to 0.");
|
||||||
|
|
||||||
|
pitch.max = kids[i]->getDoubleValue("max", 0.0);
|
||||||
|
if (pitch.max && (pitch.max < pitch.min) )
|
||||||
|
SG_LOG(SG_GENERAL,SG_ALERT,
|
||||||
|
" Pitch maximum below minimum. Neglected");
|
||||||
|
|
||||||
|
_pitch.push_back(pitch);
|
||||||
|
p += pitch.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the sample
|
||||||
|
//
|
||||||
|
_mgr = sndmgr;
|
||||||
|
if ((_sample = _mgr->find(_name)) == NULL)
|
||||||
|
_sample = _mgr->add(_name, path.c_str(), node->getStringValue("path", ""));
|
||||||
|
|
||||||
|
_sample->set_volume(v);
|
||||||
|
_sample->set_pitch(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Sound::update (double dt)
|
||||||
|
{
|
||||||
|
double curr_value = 0.0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// If the state changes to false, stop playing.
|
||||||
|
//
|
||||||
|
if (_property)
|
||||||
|
curr_value = _property->getDoubleValue();
|
||||||
|
|
||||||
|
if ( // Lisp, anyone?
|
||||||
|
(_condition && !_condition->test()) ||
|
||||||
|
(!_condition && _property &&
|
||||||
|
(
|
||||||
|
!curr_value ||
|
||||||
|
( (_mode == Sound::IN_TRANSIT) && (curr_value == _prev_value) )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if ((_mode != Sound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME)) {
|
||||||
|
if (_sample->is_playing()) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "Stopping audio after " << _dt_play
|
||||||
|
<< " sec: " << _name );
|
||||||
|
|
||||||
|
_sample->stop( _mgr->get_scheduler() );
|
||||||
|
}
|
||||||
|
|
||||||
|
_active = false;
|
||||||
|
_dt_stop += dt;
|
||||||
|
_dt_play = 0.0;
|
||||||
|
} else {
|
||||||
|
_stopping += dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If the mode is ONCE and the sound is still playing,
|
||||||
|
// we have nothing to do anymore.
|
||||||
|
//
|
||||||
|
if (_active && (_mode == Sound::ONCE)) {
|
||||||
|
|
||||||
|
if (!_sample->is_playing()) {
|
||||||
|
_dt_stop += dt;
|
||||||
|
_dt_play = 0.0;
|
||||||
|
} else {
|
||||||
|
_dt_play += dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update the playing time, cache the current value and
|
||||||
|
// clear the delay timer.
|
||||||
|
//
|
||||||
|
_dt_play += dt;
|
||||||
|
_prev_value = curr_value;
|
||||||
|
_stopping = 0.0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update the volume
|
||||||
|
//
|
||||||
|
int i;
|
||||||
|
int max = _volume.size();
|
||||||
|
double volume = 1.0;
|
||||||
|
double volume_offset = 0.0;
|
||||||
|
|
||||||
|
for(i = 0; i < max; i++) {
|
||||||
|
double v = 1.0;
|
||||||
|
|
||||||
|
if (_volume[i].prop)
|
||||||
|
v = _volume[i].prop->getDoubleValue();
|
||||||
|
|
||||||
|
else if (_volume[i].intern)
|
||||||
|
v = *_volume[i].intern;
|
||||||
|
|
||||||
|
if (_volume[i].fn)
|
||||||
|
v = _volume[i].fn(v);
|
||||||
|
|
||||||
|
v *= _volume[i].factor;
|
||||||
|
|
||||||
|
if (_volume[i].max && (v > _volume[i].max))
|
||||||
|
v = _volume[i].max;
|
||||||
|
|
||||||
|
else if (v < _volume[i].min)
|
||||||
|
v = _volume[i].min;
|
||||||
|
|
||||||
|
if (_volume[i].subtract) // Hack!
|
||||||
|
volume = _volume[i].offset - v;
|
||||||
|
|
||||||
|
else {
|
||||||
|
volume_offset += _volume[i].offset;
|
||||||
|
volume *= v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update the pitch
|
||||||
|
//
|
||||||
|
max = _pitch.size();
|
||||||
|
double pitch = 1.0;
|
||||||
|
double pitch_offset = 0.0;
|
||||||
|
|
||||||
|
for(i = 0; i < max; i++) {
|
||||||
|
double p = 1.0;
|
||||||
|
|
||||||
|
if (_pitch[i].prop)
|
||||||
|
p = _pitch[i].prop->getDoubleValue();
|
||||||
|
|
||||||
|
else if (_pitch[i].intern)
|
||||||
|
p = *_pitch[i].intern;
|
||||||
|
|
||||||
|
if (_pitch[i].fn)
|
||||||
|
p = _pitch[i].fn(p);
|
||||||
|
|
||||||
|
p *= _pitch[i].factor;
|
||||||
|
|
||||||
|
if (_pitch[i].max && (p > _pitch[i].max))
|
||||||
|
p = _pitch[i].max;
|
||||||
|
|
||||||
|
else if (p < _pitch[i].min)
|
||||||
|
p = _pitch[i].min;
|
||||||
|
|
||||||
|
if (_pitch[i].subtract) // Hack!
|
||||||
|
pitch = _pitch[i].offset - p;
|
||||||
|
|
||||||
|
else {
|
||||||
|
pitch_offset += _pitch[i].offset;
|
||||||
|
pitch *= p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Change sample state
|
||||||
|
//
|
||||||
|
_sample->set_pitch( pitch_offset + pitch );
|
||||||
|
_sample->set_volume( volume_offset + volume );
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Do we need to start playing the sample?
|
||||||
|
//
|
||||||
|
if (!_active) {
|
||||||
|
|
||||||
|
if (_mode == Sound::ONCE)
|
||||||
|
_sample->play(_mgr->get_scheduler(), false);
|
||||||
|
|
||||||
|
else
|
||||||
|
_sample->play(_mgr->get_scheduler(), true);
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "Playing audio after " << _dt_stop
|
||||||
|
<< " sec: " << _name);
|
||||||
|
SG_LOG(SG_GENERAL, SG_BULK,
|
||||||
|
"Playing " << ((_mode == ONCE) ? "once" : "looped"));
|
||||||
|
|
||||||
|
_active = true;
|
||||||
|
_dt_stop = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
// sound.hxx -- Sound class implementation
|
||||||
|
//
|
||||||
|
// Started by Erik Hofman, February 2002
|
||||||
|
//
|
||||||
|
// Copyright (C) 2002 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#ifndef _SG_SOUND_HXX
|
||||||
|
#define _SG_SOUND_HXX 1
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/props/condition.hxx>
|
||||||
|
|
||||||
|
#include "soundmgr.hxx"
|
||||||
|
|
||||||
|
static const double MAX_TRANSIT_TIME = 0.1; // 100 ms.
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for handling one sound event.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sound
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Sound();
|
||||||
|
virtual ~Sound();
|
||||||
|
|
||||||
|
virtual void init (SGPropertyNode *, SGPropertyNode *, SoundMgr *,
|
||||||
|
const string &);
|
||||||
|
virtual void update (double dt);
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
enum { MAXPROP=5 };
|
||||||
|
enum { ONCE=0, LOOPED, IN_TRANSIT };
|
||||||
|
enum { LEVEL=0, INVERTED, FLIPFLOP };
|
||||||
|
|
||||||
|
// Sound properties
|
||||||
|
typedef struct {
|
||||||
|
SGPropertyNode * prop;
|
||||||
|
double (*fn)(double);
|
||||||
|
double *intern;
|
||||||
|
double factor;
|
||||||
|
double offset;
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
bool subtract;
|
||||||
|
} _snd_prop;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
SoundMgr * _mgr;
|
||||||
|
SimpleSound * _sample;
|
||||||
|
|
||||||
|
FGCondition * _condition;
|
||||||
|
SGPropertyNode * _property;
|
||||||
|
|
||||||
|
bool _active;
|
||||||
|
string _name;
|
||||||
|
int _mode;
|
||||||
|
double _prev_value;
|
||||||
|
double _dt_play;
|
||||||
|
double _dt_stop;
|
||||||
|
double _stopping; // time after the sound should have stopped.
|
||||||
|
// This is usefull for lost packets in in-trasit mode.
|
||||||
|
|
||||||
|
vector<_snd_prop> _volume;
|
||||||
|
vector<_snd_prop> _pitch;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _SG_SOUND_HXX
|
||||||
@@ -0,0 +1,416 @@
|
|||||||
|
// soundmgr.cxx -- Sound effect management class
|
||||||
|
//
|
||||||
|
// Sound manager initially written by David Findlay
|
||||||
|
// <david_j_findlay@yahoo.com.au> 2001
|
||||||
|
//
|
||||||
|
// C++-ified by Curtis Olson, started March 2001.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
|
#include "soundmgr.hxx"
|
||||||
|
|
||||||
|
#define SOUND_SAFETY_MULT 3
|
||||||
|
#define MAX_SOUND_SAFETY ( 1.0 / SOUND_SAFETY_MULT )
|
||||||
|
|
||||||
|
//
|
||||||
|
// SimpleSound
|
||||||
|
//
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
SimpleSound::SimpleSound( const char *path, const char *file )
|
||||||
|
: sample(NULL),
|
||||||
|
pitch_envelope(NULL),
|
||||||
|
volume_envelope(NULL),
|
||||||
|
pitch(1.0),
|
||||||
|
volume(1.0)
|
||||||
|
{
|
||||||
|
SGPath slfile( path );
|
||||||
|
if ( file )
|
||||||
|
slfile.append( file );
|
||||||
|
|
||||||
|
sample = new slSample ( slfile.c_str() );
|
||||||
|
pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||||
|
volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||||
|
pitch_envelope->setStep ( 0, 0.01, 1.0 );
|
||||||
|
volume_envelope->setStep ( 0, 0.01, 1.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleSound::SimpleSound( unsigned char *buffer, int len )
|
||||||
|
: pitch(1.0),
|
||||||
|
volume(1.0)
|
||||||
|
{
|
||||||
|
sample = new slSample ( buffer, len );
|
||||||
|
pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||||
|
volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||||
|
pitch_envelope->setStep ( 0, 0.01, 1.0 );
|
||||||
|
volume_envelope->setStep ( 0, 0.01, 1.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
SimpleSound::~SimpleSound() {
|
||||||
|
delete pitch_envelope;
|
||||||
|
delete volume_envelope;
|
||||||
|
delete sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleSound::play( slScheduler *sched, bool looped ) {
|
||||||
|
|
||||||
|
// make sure sound isn't already playing
|
||||||
|
if ( sample->getPlayCount() > 0 ) {
|
||||||
|
sched->stopSample(sample);
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( looped ) {
|
||||||
|
sched->loopSample(sample);
|
||||||
|
} else {
|
||||||
|
sched->playSample(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
sched->addSampleEnvelope(sample, 0, 0, pitch_envelope, SL_PITCH_ENVELOPE);
|
||||||
|
sched->addSampleEnvelope(sample, 0, 1, volume_envelope, SL_VOLUME_ENVELOPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleSound::stop( slScheduler *sched, bool quick ) {
|
||||||
|
|
||||||
|
sched->stopSample( sample );
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Sound Manager
|
||||||
|
//
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
SoundMgr::SoundMgr() {
|
||||||
|
audio_sched = new slScheduler( 8000 );
|
||||||
|
if ( audio_sched->notWorking() ) {
|
||||||
|
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
|
||||||
|
} else {
|
||||||
|
audio_sched -> setMaxConcurrent ( 6 );
|
||||||
|
|
||||||
|
audio_mixer = new smMixer;
|
||||||
|
|
||||||
|
SG_LOG( SG_GENERAL, SG_INFO,
|
||||||
|
"Rate = " << audio_sched->getRate()
|
||||||
|
<< " Bps = " << audio_sched->getBps()
|
||||||
|
<< " Stereo = " << audio_sched->getStereo() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
|
||||||
|
SoundMgr::~SoundMgr() {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove the samples from the sample manager.
|
||||||
|
//
|
||||||
|
sample_map_iterator sample_current = samples.begin();
|
||||||
|
sample_map_iterator sample_end = samples.end();
|
||||||
|
for ( ; sample_current != sample_end; ++sample_current ) {
|
||||||
|
sample_ref *sr = sample_current->second;
|
||||||
|
|
||||||
|
audio_sched->stopSample(sr->sample);
|
||||||
|
delete sr->sample;
|
||||||
|
delete sr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove the sounds from the sound manager.
|
||||||
|
//
|
||||||
|
sound_map_iterator sound_current = sounds.begin();
|
||||||
|
sound_map_iterator sound_end = sounds.end();
|
||||||
|
for ( ; sound_current != sound_end; ++sound_current ) {
|
||||||
|
SimpleSound *s = sound_current->second;
|
||||||
|
|
||||||
|
audio_sched->stopSample(s->get_sample());
|
||||||
|
delete s->get_sample();
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete audio_sched;
|
||||||
|
delete audio_mixer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// initialize the sound manager
|
||||||
|
void SoundMgr::init() {
|
||||||
|
safety = MAX_SOUND_SAFETY;
|
||||||
|
|
||||||
|
// audio_mixer -> setMasterVolume ( 80 ) ; /* 80% of max volume. */
|
||||||
|
audio_sched -> setSafetyMargin ( SOUND_SAFETY_MULT * safety ) ;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove the samples from the sample manager.
|
||||||
|
//
|
||||||
|
sample_map_iterator sample_current = samples.begin();
|
||||||
|
sample_map_iterator sample_end = samples.end();
|
||||||
|
for ( ; sample_current != sample_end; ++sample_current ) {
|
||||||
|
sample_ref *sr = sample_current->second;
|
||||||
|
|
||||||
|
audio_sched->stopSample(sr->sample);
|
||||||
|
delete sr->sample;
|
||||||
|
delete sr;
|
||||||
|
}
|
||||||
|
samples.clear();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove the sounds from the sound manager.
|
||||||
|
//
|
||||||
|
sound_map_iterator sound_current = sounds.begin();
|
||||||
|
sound_map_iterator sound_end = sounds.end();
|
||||||
|
for ( ; sound_current != sound_end; ++sound_current ) {
|
||||||
|
SimpleSound *s = sound_current->second;
|
||||||
|
|
||||||
|
audio_sched->stopSample(s->get_sample());
|
||||||
|
delete s->get_sample();
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
sounds.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SoundMgr::bind ()
|
||||||
|
{
|
||||||
|
// no properties yet
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SoundMgr::unbind ()
|
||||||
|
{
|
||||||
|
// no properties yet
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// run the audio scheduler
|
||||||
|
void SoundMgr::update( double dt ) {
|
||||||
|
if ( dt > safety ) {
|
||||||
|
safety = dt;
|
||||||
|
} else {
|
||||||
|
safety = safety * 0.99 + dt * 0.01;
|
||||||
|
}
|
||||||
|
if ( safety > MAX_SOUND_SAFETY ) {
|
||||||
|
safety = MAX_SOUND_SAFETY;
|
||||||
|
}
|
||||||
|
// cout << "safety = " << safety << endl;
|
||||||
|
audio_sched -> setSafetyMargin ( SOUND_SAFETY_MULT * safety ) ;
|
||||||
|
|
||||||
|
if ( !audio_sched->not_working() )
|
||||||
|
audio_sched -> update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SoundMgr::pause ()
|
||||||
|
{
|
||||||
|
audio_sched->pauseSample(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SoundMgr::resume ()
|
||||||
|
{
|
||||||
|
audio_sched->resumeSample(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add a sound effect, return true if successful
|
||||||
|
bool SoundMgr::add( SimpleSound *sound, const string& refname ) {
|
||||||
|
|
||||||
|
sound_map_iterator sound_it = sounds.find( refname );
|
||||||
|
if ( sound_it != sounds.end() ) {
|
||||||
|
// sound already exists
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_map_iterator sample_it = samples.find( refname );
|
||||||
|
if ( sample_it != samples.end() ) {
|
||||||
|
// this sound has existed in the past and it's sample is still
|
||||||
|
// here, delete the sample so we can replace it.
|
||||||
|
samples.erase( sample_it );
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_ref *sr = new sample_ref;
|
||||||
|
|
||||||
|
sr->n=1;
|
||||||
|
sr->sample = sound->get_sample();
|
||||||
|
samples[refname] = sr;
|
||||||
|
|
||||||
|
sounds[refname] = sound;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add a sound from a file, return the sample if successful, else return NULL
|
||||||
|
SimpleSound *SoundMgr::add( const string &refname,
|
||||||
|
const char *path, const char *file ) {
|
||||||
|
SimpleSound *sound;
|
||||||
|
|
||||||
|
SGPath slfile( path );
|
||||||
|
if ( file )
|
||||||
|
slfile.append( file );
|
||||||
|
|
||||||
|
if ( slfile.str().empty() )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sample_map_iterator it = samples.find(slfile.str());
|
||||||
|
if (it == samples.end()) {
|
||||||
|
|
||||||
|
sound = new SimpleSound(slfile.c_str());
|
||||||
|
sounds[refname] = sound;
|
||||||
|
|
||||||
|
sample_ref *sr = new sample_ref;
|
||||||
|
|
||||||
|
sr->n=1;
|
||||||
|
sr->sample = sound->get_sample();
|
||||||
|
samples[slfile.str()] = sr;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
sample_ref *sr = it->second;
|
||||||
|
|
||||||
|
sr->n++;
|
||||||
|
sound =
|
||||||
|
new SimpleSound(sr->sample->getBuffer(), sr->sample->getLength());
|
||||||
|
sounds[refname] = sound;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// remove a sound effect, return true if successful
|
||||||
|
bool SoundMgr::remove( const string &refname ) {
|
||||||
|
|
||||||
|
sound_map_iterator it = sounds.find( refname );
|
||||||
|
if ( it != sounds.end() ) {
|
||||||
|
// first stop the sound from playing (so we don't bomb the
|
||||||
|
// audio scheduler)
|
||||||
|
SimpleSound *sample = it->second;
|
||||||
|
|
||||||
|
// cout << "Playing " << sample->get_sample()->getPlayCount()
|
||||||
|
// << " instances!" << endl;
|
||||||
|
|
||||||
|
audio_sched->stopSample( sample->get_sample() );
|
||||||
|
audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0,
|
||||||
|
NULL,
|
||||||
|
SL_PITCH_ENVELOPE );
|
||||||
|
audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1,
|
||||||
|
NULL,
|
||||||
|
SL_VOLUME_ENVELOPE );
|
||||||
|
|
||||||
|
// must call audio_sched->update() after stopping the sound
|
||||||
|
// but before deleting it.
|
||||||
|
audio_sched -> update();
|
||||||
|
// cout << "Still playing " << sample->get_sample()->getPlayCount()
|
||||||
|
// << " instances!" << endl;
|
||||||
|
|
||||||
|
//
|
||||||
|
// FIXME:
|
||||||
|
// Due to the change in the sound manager, samples live
|
||||||
|
// until the sound manager gets removed.
|
||||||
|
//
|
||||||
|
// delete sample;
|
||||||
|
sounds.erase( it );
|
||||||
|
|
||||||
|
// cout << "sndmgr: removed -> " << refname << endl;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// cout << "sndmgr: failed remove -> " << refname << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return true of the specified sound exists in the sound manager system
|
||||||
|
bool SoundMgr::exists( const string &refname ) {
|
||||||
|
sound_map_iterator it = sounds.find( refname );
|
||||||
|
if ( it != sounds.end() ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return a pointer to the SimpleSound if the specified sound exists
|
||||||
|
// in the sound manager system, otherwise return NULL
|
||||||
|
SimpleSound *SoundMgr::find( const string &refname ) {
|
||||||
|
sound_map_iterator it = sounds.find( refname );
|
||||||
|
if ( it != sounds.end() ) {
|
||||||
|
return it->second;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// tell the scheduler to play the indexed sample in a continuous
|
||||||
|
// loop
|
||||||
|
bool SoundMgr::play_looped( const string &refname ) {
|
||||||
|
SimpleSound *sample;
|
||||||
|
|
||||||
|
if ((sample = find( refname )) == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sample->play(audio_sched, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// tell the scheduler to play the indexed sample once
|
||||||
|
bool SoundMgr::play_once( const string& refname ) {
|
||||||
|
SimpleSound *sample;
|
||||||
|
|
||||||
|
if ((sample = find( refname )) == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sample->play(audio_sched, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return true of the specified sound is currently being played
|
||||||
|
bool SoundMgr::is_playing( const string& refname ) {
|
||||||
|
SimpleSound *sample;
|
||||||
|
|
||||||
|
if ((sample = find( refname )) == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (sample->get_sample()->getPlayCount() > 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// immediate stop playing the sound
|
||||||
|
bool SoundMgr::stop( const string& refname ) {
|
||||||
|
SimpleSound *sample;
|
||||||
|
|
||||||
|
if ((sample = find( refname )) == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
audio_sched->stopSample( sample->get_sample() );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
// soundmgr.hxx -- Sound effect management class
|
||||||
|
//
|
||||||
|
// Sound manager initially written by David Findlay
|
||||||
|
// <david_j_findlay@yahoo.com.au> 2001
|
||||||
|
//
|
||||||
|
// C++-ified by Curtis Olson, started March 2001.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _SG_SOUNDMGR_HXX
|
||||||
|
#define _SG_SOUNDMGR_HXX 1
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/timing/timestamp.hxx>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <plib/sl.h>
|
||||||
|
#include <plib/sm.h>
|
||||||
|
|
||||||
|
SG_USING_STD(map);
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
|
// manages everything we need to know for an individual sound sample
|
||||||
|
class SimpleSound {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
slSample *sample;
|
||||||
|
slEnvelope *pitch_envelope;
|
||||||
|
slEnvelope *volume_envelope;
|
||||||
|
double pitch;
|
||||||
|
double volume;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SimpleSound( const char *path, const char *file = NULL );
|
||||||
|
SimpleSound( unsigned char *buffer, int len );
|
||||||
|
~SimpleSound();
|
||||||
|
|
||||||
|
void play( slScheduler *sched, bool looped );
|
||||||
|
void stop( slScheduler *sched, bool quick = true );
|
||||||
|
|
||||||
|
inline void play_once( slScheduler *sched ) { play( sched, false); }
|
||||||
|
inline void play_looped( slScheduler *sched ) { play( sched, true); }
|
||||||
|
inline bool is_playing( ) {
|
||||||
|
return ( sample->getPlayCount() > 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double get_pitch() const { return pitch; }
|
||||||
|
inline void set_pitch( double p ) {
|
||||||
|
pitch = p;
|
||||||
|
pitch_envelope->setStep( 0, 0.01, pitch );
|
||||||
|
}
|
||||||
|
inline double get_volume() const { return volume; }
|
||||||
|
inline void set_volume( double v ) {
|
||||||
|
volume = v;
|
||||||
|
volume_envelope->setStep( 0, 0.01, volume );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline slSample *get_sample() { return sample; }
|
||||||
|
inline slEnvelope *get_pitch_envelope() { return pitch_envelope; }
|
||||||
|
inline slEnvelope *get_volume_envelope() { return volume_envelope; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int n;
|
||||||
|
slSample *sample;
|
||||||
|
} sample_ref;
|
||||||
|
|
||||||
|
typedef map < string, sample_ref * > sample_map;
|
||||||
|
typedef sample_map::iterator sample_map_iterator;
|
||||||
|
typedef sample_map::const_iterator const_sample_map_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
typedef map < string, SimpleSound * > sound_map;
|
||||||
|
typedef sound_map::iterator sound_map_iterator;
|
||||||
|
typedef sound_map::const_iterator const_sound_map_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
class SoundMgr
|
||||||
|
{
|
||||||
|
|
||||||
|
slScheduler *audio_sched;
|
||||||
|
smMixer *audio_mixer;
|
||||||
|
|
||||||
|
sound_map sounds;
|
||||||
|
sample_map samples;
|
||||||
|
|
||||||
|
double safety;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SoundMgr();
|
||||||
|
~SoundMgr();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (re) initialize the sound manager.
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind properties for the sound manager.
|
||||||
|
*/
|
||||||
|
void bind ();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unbind properties for the sound manager.
|
||||||
|
*/
|
||||||
|
void unbind ();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the audio scheduler.
|
||||||
|
*/
|
||||||
|
void update(double dt);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause all sounds.
|
||||||
|
*/
|
||||||
|
void pause ();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resume all sounds.
|
||||||
|
*/
|
||||||
|
void resume ();
|
||||||
|
|
||||||
|
|
||||||
|
// is audio working?
|
||||||
|
inline bool is_working() const { return !audio_sched->notWorking(); }
|
||||||
|
|
||||||
|
// reinitialize the sound manager
|
||||||
|
inline void reinit() { init(); }
|
||||||
|
|
||||||
|
// add a sound effect, return true if successful
|
||||||
|
bool add( SimpleSound *sound, const string& refname);
|
||||||
|
|
||||||
|
// add a sound file, return the sample if successful, else return NULL
|
||||||
|
SimpleSound *add( const string& refname,
|
||||||
|
const char *path, const char *file = NULL );
|
||||||
|
|
||||||
|
// remove a sound effect, return true if successful
|
||||||
|
bool remove( const string& refname );
|
||||||
|
|
||||||
|
// return true of the specified sound exists in the sound manager system
|
||||||
|
bool exists( const string& refname );
|
||||||
|
|
||||||
|
// return a pointer to the SimpleSound if the specified sound
|
||||||
|
// exists in the sound manager system, otherwise return NULL
|
||||||
|
SimpleSound *find( const string& refname );
|
||||||
|
|
||||||
|
// tell the scheduler to play the indexed sample in a continuous
|
||||||
|
// loop
|
||||||
|
bool play_looped( const string& refname );
|
||||||
|
|
||||||
|
// tell the scheduler to play the indexed sample once
|
||||||
|
bool play_once( const string& refname );
|
||||||
|
|
||||||
|
// return true of the specified sound is currently being played
|
||||||
|
bool is_playing( const string& refname );
|
||||||
|
|
||||||
|
// immediate stop playing the sound
|
||||||
|
bool stop( const string& refname );
|
||||||
|
|
||||||
|
// return the audio scheduler
|
||||||
|
inline slScheduler *get_scheduler( ) { return audio_sched; };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _SG_SOUNDMGR_HXX
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user