1
0
Fork 0

Erik Hofman:

I changed the sound code to let it use FGCondition. This changes the
code and configuration files rather drastically. Furthermore I've added
an in-transit mode which plays the sound only when the tied property is
changing.

Changes:

Code:
* Added condition support to trigger an event
* Removed the <type> section from the main event definition
   (this could be done using conditions)
* Removed the abillity to use several events with the same name,
   instead it is required to use conditions.
* Updated the README.xmlsound

Base package:
* Changed the configuration files accordingly.
* Changed flaps and gear to use the new in-stransit mode.
* Changed the flps.wav file so it can be looped.
* Created a new gear.wav file (whcih can be looped)
   and a gear-lck.wav file for gear locking sound.

IMPORTANT:
To change existing configuration files to the new ones, it is important
to pack events with the same name together into one singel event, using
the condition specification. Also, when using special types (inverted,
flip-flop, raise or fall) these should be changed to a conditions also.
For more information, please look at
FLightGear/docs-mini/README.xmlsound and the supplied aircraft
configuration files located under FlightGear/Aircraft (espesially
c172/c172-sound.xml and c310/c310-sound.xml).
This commit is contained in:
curt 2002-05-09 04:24:39 +00:00
parent 93e0274eb8
commit 1c513868b7
6 changed files with 175 additions and 269 deletions

View file

@ -1,5 +1,5 @@
Users Guide to FlightGear sound configuration
Version 0.7.10, Mar 02 2002
Version 0.7.11, apr 27 2002
Author: Erik Hofman <erik@ehofman.com>
This document is an attempt to describe the configuration of
@ -44,7 +44,9 @@ A limited sound configuration file would look something like this:
<name>engine</name>
<path>Sounds/wasp.wav</path>
<mode>looped</mode>
<condition>
<property>/engines/engine/running</property>
</condition>
<volume>
<property>/engines/engine/mp-osi</property>
<factor>0.005</factor>
@ -115,42 +117,20 @@ Configuration description:
This defined th path to the sound file. The path is relative to the
FlightGear root directory but could be specified absolute.
<condition>
Define a condition that triggers the event.
For a complete description of the FlightGear conditions,
please read docs-mini/README.conditions
An event should define either a condition or a property.
<property>
Define which property triggers the event, and reffers to a node
in the FlightGear property tree.
in the FlightGear property tree. Action is taken when the property
is non zero.
The value is converted to an integer value (anything less than 0.5 is
is considered to be 0) and handled if it were a boolean value
(0 = false, anything else = true).
The triger depends on the value of <type>.
<type>
This specifies how the event is triggered. When an event is triggered
the sample will start playing. Since the effects scheduler can have
multiple events controll a single sound event, it depends on the
situation if an event actually stops playing the sound.
Basically the following is true:
The first event requesting to start playback, triggers playback.
The last event requesting to stop playback, will stop playback.
There are multiple options:
level: events are active if the value is true.
this is the default behaviour.
inverted: events are active if the value is false.
flipflop: events are triggered on state changes.
this is only usefull for samples which are played
once.
raise: start playing at the raise of the event.
explicitly stop playing when the event turns false.
fall: start playing at the fall of the event.
explicitly stop playing when the event turns true.
A more sophisticated mechanism to trigger the event is described
in <condition>
<mode>
This defines how the sample should be played:
@ -161,6 +141,8 @@ Configuration description:
looped: the sample plays continuesly,
until the event turns false.
in-transit: the sample plays continuesly,
while the property is changing its value.
<volume> / <pitch>
Volume or Pitch definition. Currently there may be up to 5
@ -183,10 +165,12 @@ Configuration description:
this is the default.
ln: convert the property value to a natural logarithmic
value before scaling it.
value before scaling it. Anything below 1 will return
zero.
log: convert the property value to a true logarithmic
value before scaling it.
value before scaling it. Anything below 1 will return
zero.
inv: inverse lineair handling (1/x).
@ -211,7 +195,6 @@ Configuration description:
will be truncated to this value.
<max>
Maximum allowed value.
This is usefull if sounds gets to loud. Anything higher will be
truncated to this value.
@ -227,7 +210,7 @@ Default values are:
type: lin
factor: 1.0
offset: 0.0 for volume, 1.0 for pitch
min: 0.0 (don't check)
min: 0.0
max: 0.0 (don't check)

View file

@ -52,7 +52,7 @@ FGFX::~FGFX ()
void
FGFX::init()
{
const SGPropertyNode * node = fgGetNode("/sim/sound", true);
SGPropertyNode * node = fgGetNode("/sim/sound", true);
int i;
string path_str = node->getStringValue("path");
@ -77,13 +77,10 @@ FGFX::init()
node = root.getNode("fx");
for (i = 0; i < node->nChildren(); i++) {
FGSound * sound;
sound = new FGSound(node->getChild(i));
_sound.push_back(sound);
}
FGSound *sound = new FGSound();
sound->init(node->getChild(i));
for (i = 0; i < (int)_sound.size(); i++ ) {
_sound[i]->init();
_sound.push_back(sound);
}
}

View file

@ -41,8 +41,8 @@
static double _fg_inv(double v) { return (v == 0) ? 1e99 : 1/v; };
static double _fg_abs(double v) { return (v >= 0) ? v : -v; };
static double _fg_sqrt(double v) { return (v < 0) ? sqrt(-v) : sqrt(v); };
static double _fg_log10(double v) { return (v < 1) ? 0 : log10(v+1); };
static double _fg_log(double v) { return (v < 1) ? 0 : log(v+1); };
static double _fg_log10(double v) { return (v < 1) ? 0 : log10(v); };
static double _fg_log(double v) { return (v < 1) ? 0 : log(v); };
// static double _fg_sqr(double v) { return pow(v, 2); };
// static double _fg_pow3(double v) { return pow(v, 3); };
@ -61,44 +61,40 @@ static const struct {
{"", NULL}
};
FGSound::FGSound(const SGPropertyNode * node)
: _node(node),
FGSound::FGSound()
: _condition(NULL),
_property(NULL),
_sample(NULL),
_active(false),
_mode(FGSound::ONCE),
_type(FGSound::LEVEL),
_name(""),
_factor(1.0)
_prev_value(0),
_name("")
{
}
FGSound::~FGSound()
{
delete _condition;
delete _sample;
}
void
FGSound::init()
FGSound::init(SGPropertyNode *node)
{
_property = fgGetNode(_node->getStringValue("property"), true);
//
// set global sound properties
//
_name = _node->getStringValue("name");
if ((_factor = _node->getDoubleValue("factor")) == 0.0)
_factor = 1.0;
_offset = _node->getDoubleValue("offset");
_name = node->getStringValue("name");
SG_LOG(SG_GENERAL, SG_INFO, "Loading sound information for: " << _name );
const char *mode_str = _node->getStringValue("mode");
const char *mode_str = node->getStringValue("mode");
if ( !strcmp(mode_str, "looped") ) {
_mode = FGSound::LOOPED;
} else if ( !strcmp(mode_str, "in-transit") ) {
_mode = FGSound::IN_TRANSIT;
} else {
_mode = FGSound::ONCE;
@ -106,41 +102,21 @@ FGSound::init()
SG_LOG(SG_GENERAL,SG_INFO, " Unknown sound mode, default to 'once'");
}
const char *type_str = _node->getStringValue("type");
if ( !strcmp(type_str, "flipflop") ) {
_type = FGSound::FLIPFLOP;
_property = fgGetNode(node->getStringValue("property"), true);
SGPropertyNode *condition = node->getChild("condition");
if (condition != NULL)
_condition = fgReadCondition(condition);
} else if ( !strcmp(type_str, "inverted") ) {
_type = FGSound::INVERTED;
} else if ( !strcmp(type_str, "raise") ) {
_type = FGSound::RAISE;
} else if ( !strcmp(type_str, "fall") ) {
_type = FGSound::FALL;
} else {
_type = FGSound::LEVEL;
if ( strcmp(type_str, "") )
SG_LOG(SG_GENERAL,SG_INFO, " Unknown sound type, default to 'level'");
}
#if 0
//
// set position properties
//
_pos.dist = _node->getDoubleValue("dist");
_pos.hor = _node->getDoubleValue("pos_hor");
_pos.vert = _node->getDoubleValue("pos_vert");
#endif
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<const SGPropertyNode *> kids = _node->getChildren("volume");
vector<SGPropertyNode *> kids = node->getChildren("volume");
for (i = 0; (i < kids.size()) && (i < FGSound::MAXPROP); i++) {
_snd_prop volume;
@ -199,7 +175,7 @@ FGSound::init()
// set pitch properties
//
float p = 0.0;
kids = _node->getChildren("pitch");
kids = node->getChildren("pitch");
for (i = 0; (i < kids.size()) && (i < FGSound::MAXPROP); i++) {
_snd_prop pitch;
@ -256,9 +232,9 @@ FGSound::init()
//
// Initialize the sample
//
FGSoundMgr * mgr = globals->get_soundmgr();
if ((_sample = mgr->find(_name)) == NULL)
_sample = mgr->add(_name, _node->getStringValue("path"));
_mgr = globals->get_soundmgr();
if ((_sample = _mgr->find(_name)) == NULL)
_sample = _mgr->add(_name, node->getStringValue("path"));
_sample->set_volume(v);
_sample->set_pitch(p);
@ -277,71 +253,52 @@ FGSound::unbind ()
void
FGSound::update (int dt)
{
FGSoundMgr * mgr = globals->get_soundmgr();
//
// Do we have something to do?
//
// if (!_property)
// return;
if ((_type == FGSound::LEVEL) || (_type == FGSound::INVERTED)) {
//
// use an integer to get false when: -1 < check < 1
//
bool check = (int)(_offset + _property->getDoubleValue() * _factor);
if (_type == FGSound::INVERTED)
check = !check;
double curr_value = 0.0;
//
// If the state changes to false, stop playing.
//
if (!check) {
if (_active) {
SG_LOG(SG_GENERAL, SG_INFO, "Stopping sound: " << _name);
_sample->stop( mgr->get_scheduler(), false );
if (_property)
curr_value = _property->getDoubleValue();
if ( // Lisp, anyone?
(_condition && !_condition->test()) ||
(_property &&
(
!curr_value ||
( (_mode == FGSound::IN_TRANSIT) && (curr_value == _prev_value) )
)
)
)
{
_active = false;
if (_sample->is_playing()) {
SG_LOG(SG_GENERAL, SG_INFO, "Stopping sound: " << _name);
_sample->stop( _mgr->get_scheduler() );
}
return;
}
//
// If the sound is already playing we have nothing to do.
// If the mode is ONCE and the sound is still playing,
// we have nothing to do anymore.
//
if (_active && (_mode == FGSound::ONCE))
return;
} else { // FLIPFLOP, RAISE, FALL
bool check = (int)(_offset + _property->getDoubleValue() * _factor);
if (check == _active)
return;
//
// Check for state changes.
// If the state changed, and the sound is still playing: stop playing.
// Cache current value;
//
if (_sample->is_playing()) {
SG_LOG(SG_GENERAL, SG_INFO, "Stopping sound: " << _name);
_sample->stop( mgr->get_scheduler() );
}
if ( ((_type == FGSound::RAISE) && !check) ||
((_type == FGSound::FALL) && check) )
return;
}
{
int i, max;
_prev_value = curr_value;
//
// Update the volume
//
max = _volume.size();
int i;
int max = _volume.size();
double volume = 1.0;
double volume_offset = 0.0;
@ -353,14 +310,15 @@ FGSound::update (int dt)
v *= _volume[i].factor;
if (!_volume[i].max && (v > _volume[i].max))
if (_volume[i].max && (v > _volume[i].max))
v = _volume[i].max;
else if (!_volume[i].min && (v < _volume[i].min))
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;
@ -382,14 +340,15 @@ FGSound::update (int dt)
p *= _pitch[i].factor;
if (!_pitch[i].max && (p > _pitch[i].max))
if (_pitch[i].max && (p > _pitch[i].max))
p = _pitch[i].max;
else if (!_pitch[i].min && (p < _pitch[i].min))
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;
@ -401,26 +360,22 @@ FGSound::update (int dt)
//
_sample->set_pitch( pitch_offset + pitch );
_sample->set_volume( volume_offset + volume );
}
//
// Do we need to start playing the sample?
//
if (_active && ((_type == FGSound::LEVEL) || (_type == FGSound::INVERTED)))
return;
//
// This is needed for FGSound::FLIPFLOP and it works for
// FGSound::LEVEl. Doing it this way saves an extra 'if'.
//
_active = !_active;
if (!_active) {
_active = true;
if (_mode == FGSound::ONCE)
_sample->play(mgr->get_scheduler(), false);
_sample->play(_mgr->get_scheduler(), false);
else
_sample->play(mgr->get_scheduler(), true);
_sample->play(_mgr->get_scheduler(), true);
SG_LOG(SG_GENERAL, SG_INFO, "Starting audio playback for: " << _name);
SG_LOG(SG_GENERAL, SG_BULK,
"Playing " << ((_mode == ONCE) ? "once" : "looped"));
}
}

View file

@ -34,18 +34,18 @@
#include "soundmgr.hxx"
/**
* Class for handling one sound.
* Class for handling one sound event.
*
*/
class FGSound : public FGSubsystem
class FGSound
{
public:
FGSound(const SGPropertyNode *);
FGSound();
virtual ~FGSound();
virtual void init ();
virtual void init (SGPropertyNode *);
virtual void bind ();
virtual void unbind ();
virtual void update (int dt);
@ -53,13 +53,13 @@ public:
protected:
enum { MAXPROP=5 };
enum { ONCE=0, LOOPED };
enum { LEVEL=0, INVERTED, FLIPFLOP, RAISE, FALL };
enum { ONCE=0, LOOPED, IN_TRANSIT };
enum { LEVEL=0, INVERTED, FLIPFLOP };
// Sound properties
typedef struct {
const SGPropertyNode * prop;
SGPropertyNode * prop;
double (*fn)(double);
double factor;
double offset;
@ -68,30 +68,18 @@ protected:
bool subtract;
} _snd_prop;
#if 0
// Sound source (distance, horizontal position in degrees and
// vertical position in degrees)
typedef struct {
float dist;
float hor;
float vert;
} _pos_prop;
#endif
private:
const SGPropertyNode * _node;
FGSoundMgr * _mgr;
FGSimpleSound * _sample;
const SGPropertyNode * _property;
FGCondition * _condition;
SGPropertyNode * _property;
double _prev_value;
bool _active;
int _mode;
int _type;
string _name;
double _factor;
double _offset;
int _mode;
vector<_snd_prop> _volume;
vector<_snd_prop> _pitch;

View file

@ -41,8 +41,7 @@
// constructor
FGSimpleSound::FGSimpleSound( string file )
: pitch(1.0),
volume(1.0),
requests(0)
volume(1.0)
{
SGPath slfile( globals->get_fg_root() );
slfile.append( file );
@ -55,8 +54,7 @@ FGSimpleSound::FGSimpleSound( string file )
FGSimpleSound::FGSimpleSound( unsigned char *buffer, int len )
: pitch(1.0),
volume(1.0),
requests(0)
volume(1.0)
{
sample = new slSample ( buffer, len );
pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
@ -74,14 +72,12 @@ FGSimpleSound::~FGSimpleSound() {
void FGSimpleSound::play( slScheduler *sched, bool looped ) {
requests++;
// make sure sound isn't already playing
if ( sample->getPlayCount() > 0 ) {
return;
sched->stopSample(sample);
// return;
}
// sched->stopSample(sample);
if ( looped ) {
sched->loopSample(sample);
} else {
@ -94,18 +90,6 @@ void FGSimpleSound::play( slScheduler *sched, bool looped ) {
void FGSimpleSound::stop( slScheduler *sched, bool quick ) {
if ( quick ) {
requests = 0;
} else {
if ( --requests < 0 ) {
requests = 0;
}
}
if ( requests > 0 ) {
return;
}
sched->stopSample( sample );
}

View file

@ -57,7 +57,6 @@ private:
slEnvelope *volume_envelope;
double pitch;
double volume;
int requests;
public: