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:
parent
93e0274eb8
commit
1c513868b7
6 changed files with 175 additions and 269 deletions
|
@ -1,5 +1,5 @@
|
||||||
Users Guide to FlightGear sound configuration
|
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>
|
Author: Erik Hofman <erik@ehofman.com>
|
||||||
|
|
||||||
This document is an attempt to describe the configuration of
|
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>
|
<name>engine</name>
|
||||||
<path>Sounds/wasp.wav</path>
|
<path>Sounds/wasp.wav</path>
|
||||||
<mode>looped</mode>
|
<mode>looped</mode>
|
||||||
<property>/engines/engine/running</property>
|
<condition>
|
||||||
|
<property>/engines/engine/running</property>
|
||||||
|
</condition>
|
||||||
<volume>
|
<volume>
|
||||||
<property>/engines/engine/mp-osi</property>
|
<property>/engines/engine/mp-osi</property>
|
||||||
<factor>0.005</factor>
|
<factor>0.005</factor>
|
||||||
|
@ -81,7 +83,7 @@ Configuration description:
|
||||||
< ... >
|
< ... >
|
||||||
This is the event seperator. The text inside the brackets
|
This is the event seperator. The text inside the brackets
|
||||||
can be anything. Bit it is adviced to give it a meaningfull name
|
can be anything. Bit it is adviced to give it a meaningfull name
|
||||||
like: crank, engine, rumble, gear, squeal, flap, wind or stall
|
like: crank, engine, rumble, gear, squeal, flap, wind or stall
|
||||||
|
|
||||||
The value can be defined multiple times, thus anything which is
|
The value can be defined multiple times, thus anything which is
|
||||||
related may have the same name (grouping them together).
|
related may have the same name (grouping them together).
|
||||||
|
@ -89,7 +91,7 @@ Configuration description:
|
||||||
<name>
|
<name>
|
||||||
This defines the name of the event. This name is used internally
|
This defines the name of the event. This name is used internally
|
||||||
and, although it can me defined multiple times in the same file,
|
and, although it can me defined multiple times in the same file,
|
||||||
should normally have an unique value.
|
should normally have an unique value.
|
||||||
|
|
||||||
Multiple definitions of the same name will allow multiple sections
|
Multiple definitions of the same name will allow multiple sections
|
||||||
to interfere in the starting and stopping of the sample.
|
to interfere in the starting and stopping of the sample.
|
||||||
|
@ -104,7 +106,7 @@ Configuration description:
|
||||||
Using the type "fall" will stop playback when the event turns true.
|
Using the type "fall" will stop playback when the event turns true.
|
||||||
|
|
||||||
IMPORTANT:
|
IMPORTANT:
|
||||||
If the trigger is used for anything else but stopping the sound
|
If the trigger is used for anything else but stopping the sound
|
||||||
at a certain event, all sections with the same name *should* have
|
at a certain event, all sections with the same name *should* have
|
||||||
exactly the same sections for everything but property and type.
|
exactly the same sections for everything but property and type.
|
||||||
|
|
||||||
|
@ -115,42 +117,20 @@ Configuration description:
|
||||||
This defined th path to the sound file. The path is relative to the
|
This defined th path to the sound file. The path is relative to the
|
||||||
FlightGear root directory but could be specified absolute.
|
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>
|
<property>
|
||||||
Define which property triggers the event, and reffers to a node
|
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
|
A more sophisticated mechanism to trigger the event is described
|
||||||
is considered to be 0) and handled if it were a boolean value
|
in <condition>
|
||||||
(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.
|
|
||||||
|
|
||||||
<mode>
|
<mode>
|
||||||
This defines how the sample should be played:
|
This defines how the sample should be played:
|
||||||
|
@ -161,6 +141,8 @@ Configuration description:
|
||||||
looped: the sample plays continuesly,
|
looped: the sample plays continuesly,
|
||||||
until the event turns false.
|
until the event turns false.
|
||||||
|
|
||||||
|
in-transit: the sample plays continuesly,
|
||||||
|
while the property is changing its value.
|
||||||
|
|
||||||
<volume> / <pitch>
|
<volume> / <pitch>
|
||||||
Volume or Pitch definition. Currently there may be up to 5
|
Volume or Pitch definition. Currently there may be up to 5
|
||||||
|
@ -183,10 +165,12 @@ Configuration description:
|
||||||
this is the default.
|
this is the default.
|
||||||
|
|
||||||
ln: convert the property value to a natural logarithmic
|
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
|
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).
|
inv: inverse lineair handling (1/x).
|
||||||
|
|
||||||
|
@ -211,7 +195,6 @@ Configuration description:
|
||||||
will be truncated to this value.
|
will be truncated to this value.
|
||||||
|
|
||||||
<max>
|
<max>
|
||||||
|
|
||||||
Maximum allowed value.
|
Maximum allowed value.
|
||||||
This is usefull if sounds gets to loud. Anything higher will be
|
This is usefull if sounds gets to loud. Anything higher will be
|
||||||
truncated to this value.
|
truncated to this value.
|
||||||
|
@ -227,7 +210,7 @@ Default values are:
|
||||||
type: lin
|
type: lin
|
||||||
factor: 1.0
|
factor: 1.0
|
||||||
offset: 0.0 for volume, 1.0 for pitch
|
offset: 0.0 for volume, 1.0 for pitch
|
||||||
min: 0.0 (don't check)
|
min: 0.0
|
||||||
max: 0.0 (don't check)
|
max: 0.0 (don't check)
|
||||||
|
|
||||||
|
|
||||||
|
@ -240,12 +223,12 @@ Calculations are made the following way (for both pitch and volume):
|
||||||
for (n = 0; n < max; n++) {
|
for (n = 0; n < max; n++) {
|
||||||
if (factor < 0)
|
if (factor < 0)
|
||||||
{
|
{
|
||||||
value += offset[n] - abs(factor[n]) * function(property[n]);
|
value += offset[n] - abs(factor[n]) * function(property[n]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
value += factor[n] * function(property[n]);
|
value += factor[n] * function(property[n]);
|
||||||
offs += offset[n];
|
offs += offset[n];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ FGFX::~FGFX ()
|
||||||
void
|
void
|
||||||
FGFX::init()
|
FGFX::init()
|
||||||
{
|
{
|
||||||
const SGPropertyNode * node = fgGetNode("/sim/sound", true);
|
SGPropertyNode * node = fgGetNode("/sim/sound", true);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
string path_str = node->getStringValue("path");
|
string path_str = node->getStringValue("path");
|
||||||
|
@ -77,13 +77,10 @@ FGFX::init()
|
||||||
|
|
||||||
node = root.getNode("fx");
|
node = root.getNode("fx");
|
||||||
for (i = 0; i < node->nChildren(); i++) {
|
for (i = 0; i < node->nChildren(); i++) {
|
||||||
FGSound * sound;
|
FGSound *sound = new FGSound();
|
||||||
sound = new FGSound(node->getChild(i));
|
sound->init(node->getChild(i));
|
||||||
_sound.push_back(sound);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < (int)_sound.size(); i++ ) {
|
_sound.push_back(sound);
|
||||||
_sound[i]->init();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@
|
||||||
static double _fg_inv(double v) { return (v == 0) ? 1e99 : 1/v; };
|
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_abs(double v) { return (v >= 0) ? v : -v; };
|
||||||
static double _fg_sqrt(double v) { return (v < 0) ? sqrt(-v) : sqrt(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_log10(double v) { return (v < 1) ? 0 : log10(v); };
|
||||||
static double _fg_log(double v) { return (v < 1) ? 0 : log(v+1); };
|
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_sqr(double v) { return pow(v, 2); };
|
||||||
// static double _fg_pow3(double v) { return pow(v, 3); };
|
// static double _fg_pow3(double v) { return pow(v, 3); };
|
||||||
|
|
||||||
|
@ -61,44 +61,40 @@ static const struct {
|
||||||
{"", NULL}
|
{"", NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
FGSound::FGSound(const SGPropertyNode * node)
|
FGSound::FGSound()
|
||||||
: _node(node),
|
: _condition(NULL),
|
||||||
|
_property(NULL),
|
||||||
_sample(NULL),
|
_sample(NULL),
|
||||||
_active(false),
|
|
||||||
_mode(FGSound::ONCE),
|
_mode(FGSound::ONCE),
|
||||||
_type(FGSound::LEVEL),
|
_prev_value(0),
|
||||||
_name(""),
|
_name("")
|
||||||
_factor(1.0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FGSound::~FGSound()
|
FGSound::~FGSound()
|
||||||
{
|
{
|
||||||
|
delete _condition;
|
||||||
delete _sample;
|
delete _sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FGSound::init()
|
FGSound::init(SGPropertyNode *node)
|
||||||
{
|
{
|
||||||
|
|
||||||
_property = fgGetNode(_node->getStringValue("property"), true);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// set global sound properties
|
// 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 );
|
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") ) {
|
if ( !strcmp(mode_str, "looped") ) {
|
||||||
_mode = FGSound::LOOPED;
|
_mode = FGSound::LOOPED;
|
||||||
|
|
||||||
|
} else if ( !strcmp(mode_str, "in-transit") ) {
|
||||||
|
_mode = FGSound::IN_TRANSIT;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_mode = FGSound::ONCE;
|
_mode = FGSound::ONCE;
|
||||||
|
|
||||||
|
@ -106,41 +102,21 @@ FGSound::init()
|
||||||
SG_LOG(SG_GENERAL,SG_INFO, " Unknown sound mode, default to 'once'");
|
SG_LOG(SG_GENERAL,SG_INFO, " Unknown sound mode, default to 'once'");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *type_str = _node->getStringValue("type");
|
_property = fgGetNode(node->getStringValue("property"), true);
|
||||||
if ( !strcmp(type_str, "flipflop") ) {
|
SGPropertyNode *condition = node->getChild("condition");
|
||||||
_type = FGSound::FLIPFLOP;
|
if (condition != NULL)
|
||||||
|
_condition = fgReadCondition(condition);
|
||||||
|
|
||||||
} else if ( !strcmp(type_str, "inverted") ) {
|
if (!_property && !_condition)
|
||||||
_type = FGSound::INVERTED;
|
SG_LOG(SG_GENERAL, SG_WARN,
|
||||||
|
" Neither a condition nor a property specified");
|
||||||
} 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
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// set volume properties
|
// set volume properties
|
||||||
//
|
//
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
float v = 0.0;
|
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++) {
|
for (i = 0; (i < kids.size()) && (i < FGSound::MAXPROP); i++) {
|
||||||
_snd_prop volume;
|
_snd_prop volume;
|
||||||
|
|
||||||
|
@ -199,7 +175,7 @@ FGSound::init()
|
||||||
// set pitch properties
|
// set pitch properties
|
||||||
//
|
//
|
||||||
float p = 0.0;
|
float p = 0.0;
|
||||||
kids = _node->getChildren("pitch");
|
kids = node->getChildren("pitch");
|
||||||
for (i = 0; (i < kids.size()) && (i < FGSound::MAXPROP); i++) {
|
for (i = 0; (i < kids.size()) && (i < FGSound::MAXPROP); i++) {
|
||||||
_snd_prop pitch;
|
_snd_prop pitch;
|
||||||
|
|
||||||
|
@ -256,9 +232,9 @@ FGSound::init()
|
||||||
//
|
//
|
||||||
// Initialize the sample
|
// Initialize the sample
|
||||||
//
|
//
|
||||||
FGSoundMgr * mgr = globals->get_soundmgr();
|
_mgr = globals->get_soundmgr();
|
||||||
if ((_sample = mgr->find(_name)) == NULL)
|
if ((_sample = _mgr->find(_name)) == NULL)
|
||||||
_sample = mgr->add(_name, _node->getStringValue("path"));
|
_sample = _mgr->add(_name, node->getStringValue("path"));
|
||||||
|
|
||||||
_sample->set_volume(v);
|
_sample->set_volume(v);
|
||||||
_sample->set_pitch(p);
|
_sample->set_pitch(p);
|
||||||
|
@ -277,150 +253,129 @@ FGSound::unbind ()
|
||||||
void
|
void
|
||||||
FGSound::update (int dt)
|
FGSound::update (int dt)
|
||||||
{
|
{
|
||||||
FGSoundMgr * mgr = globals->get_soundmgr();
|
double curr_value = 0.0;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Do we have something to do?
|
// If the state changes to false, stop playing.
|
||||||
//
|
//
|
||||||
|
if (_property)
|
||||||
|
curr_value = _property->getDoubleValue();
|
||||||
|
|
||||||
// if (!_property)
|
if ( // Lisp, anyone?
|
||||||
// return;
|
(_condition && !_condition->test()) ||
|
||||||
|
(_property &&
|
||||||
|
(
|
||||||
|
!curr_value ||
|
||||||
|
( (_mode == FGSound::IN_TRANSIT) && (curr_value == _prev_value) )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
if ((_type == FGSound::LEVEL) || (_type == FGSound::INVERTED)) {
|
_active = false;
|
||||||
|
|
||||||
//
|
|
||||||
// use an integer to get false when: -1 < check < 1
|
|
||||||
//
|
|
||||||
bool check = (int)(_offset + _property->getDoubleValue() * _factor);
|
|
||||||
if (_type == FGSound::INVERTED)
|
|
||||||
check = !check;
|
|
||||||
|
|
||||||
//
|
|
||||||
// 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 );
|
|
||||||
_active = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// If the sound is already playing we have nothing to do.
|
|
||||||
//
|
|
||||||
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.
|
|
||||||
//
|
|
||||||
if (_sample->is_playing()) {
|
if (_sample->is_playing()) {
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Stopping sound: " << _name);
|
SG_LOG(SG_GENERAL, SG_INFO, "Stopping sound: " << _name);
|
||||||
_sample->stop( mgr->get_scheduler() );
|
_sample->stop( _mgr->get_scheduler() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ((_type == FGSound::RAISE) && !check) ||
|
return;
|
||||||
((_type == FGSound::FALL) && check) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
//
|
||||||
int i, max;
|
// If the mode is ONCE and the sound is still playing,
|
||||||
|
// we have nothing to do anymore.
|
||||||
|
//
|
||||||
|
if (_active && (_mode == FGSound::ONCE))
|
||||||
|
return;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Update the volume
|
// Cache current value;
|
||||||
//
|
//
|
||||||
max = _volume.size();
|
_prev_value = curr_value;
|
||||||
double volume = 1.0;
|
|
||||||
double volume_offset = 0.0;
|
|
||||||
|
|
||||||
for(i = 0; i < max; i++) {
|
//
|
||||||
double v = _volume[i].prop->getDoubleValue();
|
// Update the volume
|
||||||
|
//
|
||||||
|
int i;
|
||||||
|
int max = _volume.size();
|
||||||
|
double volume = 1.0;
|
||||||
|
double volume_offset = 0.0;
|
||||||
|
|
||||||
if (_volume[i].fn)
|
for(i = 0; i < max; i++) {
|
||||||
v = _volume[i].fn(v);
|
double v = _volume[i].prop->getDoubleValue();
|
||||||
|
|
||||||
v *= _volume[i].factor;
|
if (_volume[i].fn)
|
||||||
|
v = _volume[i].fn(v);
|
||||||
|
|
||||||
if (!_volume[i].max && (v > _volume[i].max))
|
v *= _volume[i].factor;
|
||||||
v = _volume[i].max;
|
|
||||||
|
|
||||||
else if (!_volume[i].min && (v < _volume[i].min))
|
if (_volume[i].max && (v > _volume[i].max))
|
||||||
v = _volume[i].min;
|
v = _volume[i].max;
|
||||||
|
|
||||||
if (_volume[i].subtract) // Hack!
|
else if (v < _volume[i].min)
|
||||||
volume = _volume[i].offset - v;
|
v = _volume[i].min;
|
||||||
else {
|
|
||||||
volume_offset += _volume[i].offset;
|
if (_volume[i].subtract) // Hack!
|
||||||
volume *= v;
|
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 = _pitch[i].prop->getDoubleValue();
|
|
||||||
|
|
||||||
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 (!_pitch[i].min && (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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update the pitch
|
||||||
|
//
|
||||||
|
max = _pitch.size();
|
||||||
|
double pitch = 1.0;
|
||||||
|
double pitch_offset = 0.0;
|
||||||
|
|
||||||
|
for(i = 0; i < max; i++) {
|
||||||
|
double p = _pitch[i].prop->getDoubleValue();
|
||||||
|
|
||||||
|
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?
|
// Do we need to start playing the sample?
|
||||||
//
|
//
|
||||||
if (_active && ((_type == FGSound::LEVEL) || (_type == FGSound::INVERTED)))
|
if (!_active) {
|
||||||
return;
|
|
||||||
|
|
||||||
//
|
_active = true;
|
||||||
// This is needed for FGSound::FLIPFLOP and it works for
|
if (_mode == FGSound::ONCE)
|
||||||
// FGSound::LEVEl. Doing it this way saves an extra 'if'.
|
_sample->play(_mgr->get_scheduler(), false);
|
||||||
//
|
|
||||||
_active = !_active;
|
|
||||||
|
|
||||||
if (_mode == FGSound::ONCE)
|
else
|
||||||
_sample->play(mgr->get_scheduler(), false);
|
_sample->play(_mgr->get_scheduler(), true);
|
||||||
else
|
|
||||||
_sample->play(mgr->get_scheduler(), true);
|
|
||||||
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Starting audio playback for: " << _name);
|
SG_LOG(SG_GENERAL, SG_INFO, "Starting audio playback for: " << _name);
|
||||||
SG_LOG(SG_GENERAL, SG_BULK,
|
SG_LOG(SG_GENERAL, SG_BULK,
|
||||||
"Playing " << ((_mode == ONCE) ? "once" : "looped"));
|
"Playing " << ((_mode == ONCE) ? "once" : "looped"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,18 +34,18 @@
|
||||||
#include "soundmgr.hxx"
|
#include "soundmgr.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for handling one sound.
|
* Class for handling one sound event.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class FGSound : public FGSubsystem
|
class FGSound
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FGSound(const SGPropertyNode *);
|
FGSound();
|
||||||
virtual ~FGSound();
|
virtual ~FGSound();
|
||||||
|
|
||||||
virtual void init ();
|
virtual void init (SGPropertyNode *);
|
||||||
virtual void bind ();
|
virtual void bind ();
|
||||||
virtual void unbind ();
|
virtual void unbind ();
|
||||||
virtual void update (int dt);
|
virtual void update (int dt);
|
||||||
|
@ -53,13 +53,13 @@ public:
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
enum { MAXPROP=5 };
|
enum { MAXPROP=5 };
|
||||||
enum { ONCE=0, LOOPED };
|
enum { ONCE=0, LOOPED, IN_TRANSIT };
|
||||||
enum { LEVEL=0, INVERTED, FLIPFLOP, RAISE, FALL };
|
enum { LEVEL=0, INVERTED, FLIPFLOP };
|
||||||
|
|
||||||
|
|
||||||
// Sound properties
|
// Sound properties
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const SGPropertyNode * prop;
|
SGPropertyNode * prop;
|
||||||
double (*fn)(double);
|
double (*fn)(double);
|
||||||
double factor;
|
double factor;
|
||||||
double offset;
|
double offset;
|
||||||
|
@ -68,30 +68,18 @@ protected:
|
||||||
bool subtract;
|
bool subtract;
|
||||||
} _snd_prop;
|
} _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:
|
private:
|
||||||
|
|
||||||
const SGPropertyNode * _node;
|
FGSoundMgr * _mgr;
|
||||||
|
|
||||||
FGSimpleSound * _sample;
|
FGSimpleSound * _sample;
|
||||||
const SGPropertyNode * _property;
|
FGCondition * _condition;
|
||||||
|
|
||||||
|
SGPropertyNode * _property;
|
||||||
|
double _prev_value;
|
||||||
|
|
||||||
bool _active;
|
bool _active;
|
||||||
|
|
||||||
int _mode;
|
|
||||||
int _type;
|
|
||||||
string _name;
|
string _name;
|
||||||
double _factor;
|
int _mode;
|
||||||
double _offset;
|
|
||||||
|
|
||||||
vector<_snd_prop> _volume;
|
vector<_snd_prop> _volume;
|
||||||
vector<_snd_prop> _pitch;
|
vector<_snd_prop> _pitch;
|
||||||
|
|
|
@ -41,8 +41,7 @@
|
||||||
// constructor
|
// constructor
|
||||||
FGSimpleSound::FGSimpleSound( string file )
|
FGSimpleSound::FGSimpleSound( string file )
|
||||||
: pitch(1.0),
|
: pitch(1.0),
|
||||||
volume(1.0),
|
volume(1.0)
|
||||||
requests(0)
|
|
||||||
{
|
{
|
||||||
SGPath slfile( globals->get_fg_root() );
|
SGPath slfile( globals->get_fg_root() );
|
||||||
slfile.append( file );
|
slfile.append( file );
|
||||||
|
@ -55,8 +54,7 @@ FGSimpleSound::FGSimpleSound( string file )
|
||||||
|
|
||||||
FGSimpleSound::FGSimpleSound( unsigned char *buffer, int len )
|
FGSimpleSound::FGSimpleSound( unsigned char *buffer, int len )
|
||||||
: pitch(1.0),
|
: pitch(1.0),
|
||||||
volume(1.0),
|
volume(1.0)
|
||||||
requests(0)
|
|
||||||
{
|
{
|
||||||
sample = new slSample ( buffer, len );
|
sample = new slSample ( buffer, len );
|
||||||
pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||||
|
@ -74,14 +72,12 @@ FGSimpleSound::~FGSimpleSound() {
|
||||||
|
|
||||||
void FGSimpleSound::play( slScheduler *sched, bool looped ) {
|
void FGSimpleSound::play( slScheduler *sched, bool looped ) {
|
||||||
|
|
||||||
requests++;
|
|
||||||
|
|
||||||
// make sure sound isn't already playing
|
// make sure sound isn't already playing
|
||||||
if ( sample->getPlayCount() > 0 ) {
|
if ( sample->getPlayCount() > 0 ) {
|
||||||
return;
|
sched->stopSample(sample);
|
||||||
|
// return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sched->stopSample(sample);
|
|
||||||
if ( looped ) {
|
if ( looped ) {
|
||||||
sched->loopSample(sample);
|
sched->loopSample(sample);
|
||||||
} else {
|
} else {
|
||||||
|
@ -94,18 +90,6 @@ void FGSimpleSound::play( slScheduler *sched, bool looped ) {
|
||||||
|
|
||||||
void FGSimpleSound::stop( slScheduler *sched, bool quick ) {
|
void FGSimpleSound::stop( slScheduler *sched, bool quick ) {
|
||||||
|
|
||||||
if ( quick ) {
|
|
||||||
requests = 0;
|
|
||||||
} else {
|
|
||||||
if ( --requests < 0 ) {
|
|
||||||
requests = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( requests > 0 ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sched->stopSample( sample );
|
sched->stopSample( sample );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,6 @@ private:
|
||||||
slEnvelope *volume_envelope;
|
slEnvelope *volume_envelope;
|
||||||
double pitch;
|
double pitch;
|
||||||
double volume;
|
double volume;
|
||||||
int requests;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue