]> git.mxchange.org Git - flightgear.git/blobdiff - src/Sound/fg_sound.cxx
Patch from Julian Foad:
[flightgear.git] / src / Sound / fg_sound.cxx
index 3701766c1997b3a24f8873795a936dca25bea8f3..5af54d59f78d1ffa1160f4b6288c4a88316cf75f 100644 (file)
@@ -1,4 +1,4 @@
-// fg_sound.hxx -- Sound class implementation
+// fg_sound.cxx -- Sound class implementation
 //
 // Started by Erik Hofman, February 2002
 // (Reuses some code from  fg_fx.cxx created by David Megginson)
 #include <string.h>
 
 #include <simgear/debug/logstream.hxx>
+#include <simgear/math/sg_random.h>
 
 #include <Main/fg_props.hxx>
 
 #include "fg_sound.hxx"
 
 
-// static double _fg_lin(double v)   { return 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_sqrt(double v)  { return (v < 0) ? sqrt(-v) : sqrt(v); };
-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); };
+// static double _fg_lin(double v)   { return 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_sqrt(double v)  { return (v < 0) ? sqrt(-v) : sqrt(v); }
+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); }
 
 static const struct {
        char *name;
@@ -62,18 +63,26 @@ static const struct {
 };
 
 FGSound::FGSound()
-  : _condition(NULL),
+  : _sample(NULL),
+    _active(false),
+    _condition(NULL),
     _property(NULL),
-    _sample(NULL),
-    _mode(FGSound::ONCE),
+    _dt_play(0.0),
+    _dt_stop(0.0),
     _prev_value(0),
-    _name("")
+    _name(""),
+    _mode(FGSound::ONCE)    
 {
 }
 
 FGSound::~FGSound()
 {
-   delete _condition;
+   if (_property)
+      delete _property;
+
+   if (_condition)
+      delete _condition;
+
    delete _sample;
 }
 
@@ -85,10 +94,10 @@ FGSound::init(SGPropertyNode *node)
    // set global sound properties
    //
    
-   _name = node->getStringValue("name");
+   _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;
 
@@ -102,7 +111,7 @@ FGSound::init(SGPropertyNode *node)
          SG_LOG(SG_GENERAL,SG_INFO, "  Unknown sound mode, default to 'once'");
    }
 
-   _property = fgGetNode(node->getStringValue("property"), true);
+   _property = fgGetNode(node->getStringValue("property", ""), true);
    SGPropertyNode *condition = node->getChild("condition");
    if (condition != NULL)
       _condition = fgReadCondition(condition);
@@ -116,25 +125,28 @@ FGSound::init(SGPropertyNode *node)
    //
    unsigned int i;
    float v = 0.0;
-   vector<SGPropertyNode *> kids = node->getChildren("volume");
+   vector<SGPropertyNode_ptr> kids = node->getChildren("volume");
    for (i = 0; (i < kids.size()) && (i < FGSound::MAXPROP); i++) {
-      _snd_prop volume;
+      _snd_prop volume = {NULL, NULL, NULL, 1.0, 0.0, 0.0, 0.0, false};
 
-      volume.prop = fgGetNode(kids[i]->getStringValue("property"), true);
+      if (strcmp(kids[i]->getStringValue("property"), ""))
+         volume.prop = fgGetNode(kids[i]->getStringValue("property", ""), true);
 
-      if ((volume.factor = kids[i]->getDoubleValue("factor")) == 0.0)
-         volume.factor = 1.0;
+      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;
+      else if (!strcmp(intern_str, "random"))
+         volume.intern = &_random;
 
-      else 
+      if ((volume.factor = kids[i]->getDoubleValue("factor", 1.0)) != 0.0)
          if (volume.factor < 0.0) {
             volume.factor = -volume.factor;
             volume.subtract = true;
+         }
 
-         } else
-            volume.subtract = false;
-
-      volume.fn = NULL;
-      const char *type_str = kids[i]->getStringValue("type");
+      const char *type_str = kids[i]->getStringValue("type", "");
       if ( strcmp(type_str, "") ) {
 
          for (int j=0; __fg_snd_fn[j].fn; j++)
@@ -148,23 +160,17 @@ FGSound::init(SGPropertyNode *node)
                    "  Unknown volume type, default to 'lin'");
       }
 
-      volume.offset = kids[i]->getDoubleValue("offset");
+      volume.offset = kids[i]->getDoubleValue("offset", 0.0);
 
-      if ((volume.min = kids[i]->getDoubleValue("min")) < 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.min = 0.0;
-      }
-
-      volume.max = kids[i]->getDoubleValue("max");
-      if (volume.max && (volume.max < volume.min) ) {
+      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.max = 0.0;
-      }
-
       _volume.push_back(volume);
       v += volume.offset;
 
@@ -177,23 +183,24 @@ FGSound::init(SGPropertyNode *node)
    float p = 0.0;
    kids = node->getChildren("pitch");
    for (i = 0; (i < kids.size()) && (i < FGSound::MAXPROP); i++) {
-      _snd_prop pitch;
+      _snd_prop pitch = {NULL, NULL, NULL, 1.0, 1.0, 0.0, 0.0, false};
 
-      pitch.prop = fgGetNode(kids[i]->getStringValue("property"), true);
+      if (strcmp(kids[i]->getStringValue("property", ""), ""))
+         pitch.prop = fgGetNode(kids[i]->getStringValue("property", ""), true);
 
-      if ((pitch.factor = kids[i]->getDoubleValue("factor")) == 0.0)
-         pitch.factor = 1.0;
+      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;
 
-      else
+      if ((pitch.factor = kids[i]->getDoubleValue("factor", 1.0)) != 0.0)
          if (pitch.factor < 0.0) {
             pitch.factor = -pitch.factor;
             pitch.subtract = true;
+         }
 
-         } else
-            pitch.subtract = false;
-
-      pitch.fn = NULL;
-      const char *type_str = kids[i]->getStringValue("type");
+      const char *type_str = kids[i]->getStringValue("type", "");
       if ( strcmp(type_str, "") ) {
 
          for (int j=0; __fg_snd_fn[j].fn; j++) 
@@ -207,24 +214,17 @@ FGSound::init(SGPropertyNode *node)
                    "  Unknown pitch type, default to 'lin'");
       }
      
-      if ((pitch.offset = kids[i]->getDoubleValue("offset")) == 0.0)
-         pitch.offset = 1.0;
+      pitch.offset = kids[i]->getDoubleValue("offset", 1.0);
 
-      if ((pitch.min = kids[i]->getDoubleValue("min")) < 0.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.min = 0.0;
-      }
-
-      pitch.max = kids[i]->getDoubleValue("max");
-      if (pitch.max && (pitch.max < pitch.min) ) {
+      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.max = 0.0;
-      }
-
       _pitch.push_back(pitch);
       p += pitch.offset;
    }
@@ -234,7 +234,7 @@ FGSound::init(SGPropertyNode *node)
    //
    _mgr = globals->get_soundmgr();
    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_pitch(p);
@@ -251,7 +251,7 @@ FGSound::unbind ()
 }
 
 void
-FGSound::update (int dt)
+FGSound::update (double dt)
 {
    double curr_value = 0.0;
 
@@ -263,7 +263,7 @@ FGSound::update (int dt)
 
    if (                                                        // Lisp, anyone?
          (_condition && !_condition->test()) ||
-         (_property &&
+         (!_condition && _property &&
             (
                !curr_value ||
                ( (_mode == FGSound::IN_TRANSIT) && (curr_value == _prev_value) )
@@ -273,8 +273,12 @@ FGSound::update (int dt)
    {
 
       _active = false;
+      _dt_stop += dt;
+      _dt_play = 0.0;
+
       if (_sample->is_playing()) {
-         SG_LOG(SG_GENERAL, SG_INFO, "Stopping sound: " << _name);
+         SG_LOG(SG_GENERAL, SG_INFO, "Stopping audio after " << _dt_play
+                                      << " sec: " << _name );
          _sample->stop( _mgr->get_scheduler() );
       }
 
@@ -286,13 +290,24 @@ FGSound::update (int dt)
    // If the mode is ONCE and the sound is still playing,
    //  we have nothing to do anymore.
    //
-   if (_active && (_mode == FGSound::ONCE))
+   if (_active && (_mode == FGSound::ONCE)) {
+
+      if (!_sample->is_playing()) {
+         _dt_stop += dt;
+         _dt_play = 0.0;
+
+      } else
+         _dt_play += dt;
+
       return;
+   }
 
    //
-   // Cache current value;
+   // Update playtime, cache the current value and feed the random number
    //
+    _dt_play += dt;
    _prev_value = curr_value;
+   _random = sg_random();
 
    //
    // Update the volume
@@ -303,7 +318,13 @@ FGSound::update (int dt)
    double volume_offset = 0.0;
 
    for(i = 0; i < max; i++) {
-      double v = _volume[i].prop->getDoubleValue();
+      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);
@@ -333,7 +354,13 @@ FGSound::update (int dt)
    double pitch_offset = 0.0;
 
    for(i = 0; i < max; i++) {
-      double p = _pitch[i].prop->getDoubleValue();
+      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);
@@ -367,15 +394,18 @@ FGSound::update (int dt)
    //
    if (!_active) {
 
-      _active = true;
       if (_mode == FGSound::ONCE)
          _sample->play(_mgr->get_scheduler(), false);
 
       else
          _sample->play(_mgr->get_scheduler(), true);
 
-      SG_LOG(SG_GENERAL, SG_INFO, "Starting audio playback for: " << _name);
+      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;
    }
 }