]> git.mxchange.org Git - flightgear.git/commitdiff
Erik Hofman:
authorcurt <curt>
Thu, 9 May 2002 04:24:39 +0000 (04:24 +0000)
committercurt <curt>
Thu, 9 May 2002 04:24:39 +0000 (04:24 +0000)
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).

docs-mini/README.xmlsound
src/Sound/fg_fx.cxx
src/Sound/fg_sound.cxx
src/Sound/fg_sound.hxx
src/Sound/soundmgr.cxx
src/Sound/soundmgr.hxx

index b63899951f33b2c623b3a36c6d50e2f568852603..4b9632340eaf2774ed08bd852bc2cf034c4d9c06 100644 (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>
-   <property>/engines/engine/running</property>
+   <condition>
+    <property>/engines/engine/running</property>
+   </condition>
    <volume>
     <property>/engines/engine/mp-osi</property>
     <factor>0.005</factor>
@@ -81,7 +83,7 @@ Configuration description:
  < ... >
        This is the event seperator. The text inside the brackets
        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
        related may have the same name (grouping them together).
@@ -89,7 +91,7 @@ Configuration description:
    <name>
        This defines the name of the event. This name is used internally
        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
        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.
 
        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
        exactly the same sections for everything but property and type.
 
@@ -114,43 +116,21 @@ Configuration description:
    <path>
        This defined th path to the sound file. The path is relative to the
        FlightGear root directory but could be specified absolute.
-   <property>
-       Define which property triggers the event, and reffers to a node
-       in the FlightGear property tree.
-        
-       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.
+   <condition>
+       Define a condition that triggers the event.
+       For a complete description of the FlightGear conditions,
+       please read docs-mini/README.conditions
 
-       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.
+       An event should define either a condition or a property.
  
-       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.
+   <property>
+       Define which property triggers the event, and reffers to a node
+       in the FlightGear property tree. Action is taken when the property
+       is non zero.
 
-       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:
@@ -160,7 +140,9 @@ 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)
 
  
@@ -240,12 +223,12 @@ Calculations are made the following way (for both pitch and volume):
    for (n = 0;  n < max; n++) {
       if (factor < 0)
       {
-         value += offset[n] - abs(factor[n]) * function(property[n]);
+        value += offset[n] - abs(factor[n]) * function(property[n]);
       }
       else
       {
-         value += factor[n] * function(property[n]);
-         offs += offset[n];
+        value += factor[n] * function(property[n]);
+        offs += offset[n];
       }
    }
 
index 2636bc011a43a1fa7a39ed210b7a604b1fcfbc05..0c31746c0ad0c11ef677389d181794241d6a5d02 100644 (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);
    }
 }
 
index 34d8f4874bbd4e02de3527669664877b6b5b2ca2..3701766c1997b3a24f8873795a936dca25bea8f3 100644 (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");
-   if ( !strcmp(mode_str,"looped") ) {
+   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;
-
-   } else if ( !strcmp(type_str, "inverted") ) {
-      _type = FGSound::INVERTED;
+   _property = fgGetNode(node->getStringValue("property"), true);
+   SGPropertyNode *condition = node->getChild("condition");
+   if (condition != NULL)
+      _condition = fgReadCondition(condition);
 
-   } 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,150 +253,129 @@ FGSound::unbind ()
 void
 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 (                                                        // Lisp, anyone?
+         (_condition && !_condition->test()) ||
+         (_property &&
+            (
+               !curr_value ||
+               ( (_mode == FGSound::IN_TRANSIT) && (curr_value == _prev_value) )
+            )
+         )
+      )
+   {
 
-   // 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;
-
-      //
-      // 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.
-      //
+      _active = false;
       if (_sample->is_playing()) {
          SG_LOG(SG_GENERAL, SG_INFO, "Stopping sound: " << _name);
-         _sample->stop( mgr->get_scheduler() );
+         _sample->stop( _mgr->get_scheduler() );
       }
 
-      if ( ((_type == FGSound::RAISE) && !check) ||
-           ((_type == FGSound::FALL) && check) )
-         return;
+      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;
+
+   //
+   // Cache current value;
+   //
+   _prev_value = curr_value;
 
-      //
-      // Update the volume
-      //
-      max = _volume.size();
-      double volume = 1.0;
-      double volume_offset = 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 = _volume[i].prop->getDoubleValue();
+   for(i = 0; i < max; i++) {
+      double v = _volume[i].prop->getDoubleValue();
 
-         if (_volume[i].fn)
-            v = _volume[i].fn(v);
+      if (_volume[i].fn)
+         v = _volume[i].fn(v);
 
-         v *= _volume[i].factor;
+      v *= _volume[i].factor;
 
-         if (!_volume[i].max && (v > _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))
-            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;
-         }
+      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;
+   //
+   // 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();
+   for(i = 0; i < max; i++) {
+      double p = _pitch[i].prop->getDoubleValue();
 
-         if (_pitch[i].fn)
-            p = _pitch[i].fn(p);
+      if (_pitch[i].fn)
+         p = _pitch[i].fn(p);
 
-         p *= _pitch[i].factor;
+      p *= _pitch[i].factor;
 
-         if (!_pitch[i].max && (p > _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))
-            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;
-         }
-      }
+      if (_pitch[i].subtract)                          // Hack!
+         pitch = _pitch[i].offset - p;
 
-      //
-      // Change sample state
-      //
-      _sample->set_pitch( pitch_offset + pitch );
-      _sample->set_volume( volume_offset + volume );
+      else {
+         pitch_offset += _pitch[i].offset;
+         pitch *= p;
+      }
    }
 
    //
-   // Do we need to start playing the sample?
+   // Change sample state
    //
-   if (_active && ((_type == FGSound::LEVEL) || (_type == FGSound::INVERTED)))
-         return;
+   _sample->set_pitch( pitch_offset + pitch );
+   _sample->set_volume( volume_offset + volume );
+
 
    //
-   // This is needed for FGSound::FLIPFLOP and it works for 
-   // FGSound::LEVEl. Doing it this way saves an extra 'if'.
+   // Do we need to start playing the sample?
    //
-   _active = !_active;
+   if (!_active) {
 
-   if (_mode == FGSound::ONCE)
-      _sample->play(mgr->get_scheduler(), false);
-   else
-      _sample->play(mgr->get_scheduler(), true);
+      _active = true;
+      if (_mode == FGSound::ONCE)
+         _sample->play(_mgr->get_scheduler(), false);
 
-   SG_LOG(SG_GENERAL, SG_INFO, "Starting audio playback for: " << _name);
-   SG_LOG(SG_GENERAL, SG_BULK,
-    "Playing " << ((_mode == ONCE) ? "once" : "looped"));
+      else
+         _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"));
+   }
 }
index 37b2d21241c84c77e1bcf0c8917f22c1489901fb..04dda074b9845ccdc33312ec3ecf4149a4b2d81e 100644 (file)
 #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;
 
-  bool _active;
+  SGPropertyNode * _property;
+  double _prev_value;
 
-  int _mode;
-  int _type;
+  bool _active;
   string _name;
-  double _factor;
-  double _offset;
+  int _mode;
 
   vector<_snd_prop> _volume;
   vector<_snd_prop> _pitch;
index 41947bb0f8703172e8f7f129dcaf25fe4433bf0e..fb805428d0037c3b25346ccba52852d4ea6ed65d 100644 (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 );
 }
 
index fbab39fc469ad74194eb000ee7a0d497c8173c5e..a46f31f533fdcd613ddef8a2fa72f2882b5b31a0 100644 (file)
@@ -57,7 +57,6 @@ private:
     slEnvelope *volume_envelope;
     double pitch;
     double volume;
-    int requests;
 
 public: