]> git.mxchange.org Git - flightgear.git/commitdiff
Cut&paste voiceplayer into a separate module.
authorThorstenB <brehmt@gmail.com>
Wed, 9 Mar 2011 22:49:25 +0000 (23:49 +0100)
committerThorstenB <brehmt@gmail.com>
Wed, 9 Mar 2011 22:49:25 +0000 (23:49 +0100)
GPWS and TCAS are now completely separate - but use the same voice player.

projects/VC8/FlightGearLib.vcproj
projects/VC90/FlightGear/FlightGear.vcproj
src/Instrumentation/mk_viii.cxx
src/Instrumentation/mk_viii.hxx
src/Instrumentation/tcas.cxx
src/Instrumentation/tcas.hxx
src/Sound/CMakeLists.txt
src/Sound/Makefile.am
src/Sound/sample_queue.hxx
src/Sound/voiceplayer.cxx [new file with mode: 0644]
src/Sound/voiceplayer.hxx [new file with mode: 0644]

index d2ee910604f30c9f72bea5f2432f88a23f57b030..51b010a13e3f65185c7ddde93f090a4be7539eab 100644 (file)
                        <File\r
                                RelativePath="..\..\src\sound\voice.hxx"\r
                                >\r
+                       </File>
+                       <File\r
+                               RelativePath="..\..\src\sound\voiceplayer.hxx"\r
+                               >\r
                        </File>\r
                        <File\r
                                RelativePath="..\..\src\fdm\yasim\Wing.hpp"\r
                        <File\r
                                RelativePath="..\..\src\sound\voice.cxx"\r
                                >\r
+                       </File>
+                       <File\r
+                               RelativePath="..\..\src\sound\voiceplayer.cxx"\r
+                               >\r
                        </File>\r
                        <File\r
                                RelativePath="..\..\src\fdm\yasim\Wing.cpp"\r
index bd43cad18115ee60dd5a2935f32775676621512f..01b17255be378e6d189ca30682bb98332064a630 100644 (file)
                        <File\r
                                RelativePath="..\..\..\src\Sound\voice.hxx"\r
                                >\r
+                       </File>
+                       <File\r
+                               RelativePath="..\..\..\src\Sound\voiceplayer.cxx"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\Sound\voiceplayer.hxx"\r
+                               >\r
                        </File>\r
                </Filter>\r
                <Filter\r
index bafa5b0695043399b1f0e09992b4f1ffa2e3f4e8..68fa0a6c76d3568286869eb4eaf2f4bd9c9687cf 100644 (file)
@@ -2133,255 +2133,6 @@ MK_VIII::IOHandler::set_present_status (bool value)
 }
 
 
-///////////////////////////////////////////////////////////////////////////////
-// FGVoicePlayer //////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-void
-FGVoicePlayer::Speaker::bind (SGPropertyNode *node)
-{
-  // uses xmlsound property names
-  tie(node, "volume", &volume);
-  tie(node, "pitch", &pitch);
-}
-
-void
-FGVoicePlayer::Speaker::update_configuration ()
-{
-  map< string, SGSharedPtr<SGSoundSample> >::iterator iter;
-  for (iter = player->samples.begin(); iter != player->samples.end(); iter++)
-    {
-      SGSoundSample *sample = (*iter).second;
-
-      sample->set_pitch(pitch);
-    }
-
-  if (player->voice)
-    player->voice->volume_changed();
-}
-
-FGVoicePlayer::Voice::~Voice ()
-{
-  for (iter = elements.begin(); iter != elements.end(); iter++)
-    delete *iter;              // we owned the element
-  elements.clear();
-}
-
-void
-FGVoicePlayer::Voice::play ()
-{
-  iter = elements.begin();
-  element = *iter;
-
-  element->play(get_volume());
-}
-
-void
-FGVoicePlayer::Voice::stop (bool now)
-{
-  if (element)
-    {
-      if (now || element->silence)
-       {
-         element->stop();
-         element = NULL;
-       }
-      else
-       iter = elements.end() - 1; // stop after the current element finishes
-    }
-}
-
-void
-FGVoicePlayer::Voice::set_volume (float _volume)
-{
-  volume = _volume;
-  volume_changed();
-}
-
-void
-FGVoicePlayer::Voice::volume_changed ()
-{
-  if (element)
-    element->set_volume(get_volume());
-}
-
-void
-FGVoicePlayer::Voice::update ()
-{
-  if (element)
-    {
-      if (! element->is_playing())
-       {
-         if (++iter == elements.end())
-           element = NULL;
-         else
-           {
-             element = *iter;
-             element->play(get_volume());
-           }
-       }
-    }
-}
-
-FGVoicePlayer::~FGVoicePlayer ()
-{
-  vector<Voice *>::iterator iter1;
-  for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++)
-    delete *iter1;
-  _voices.clear();
-  samples.clear();
-}
-
-void
-FGVoicePlayer::bind (SGPropertyNode *node, const char* default_dir_prefix)
-{
-  dir_prefix = node->getStringValue("voice/file-prefix", default_dir_prefix);
-  speaker.bind(node);
-}
-
-void
-FGVoicePlayer::init ()
-{
-  SGSoundMgr *smgr = globals->get_soundmgr();
-  _sgr = smgr->find("avionics", true);
-  _sgr->tie_to_listener();
-  speaker.update_configuration();
-}
-
-void
-FGVoicePlayer::pause()
-{
-    if (paused)
-        return;
-
-    paused = true;
-    if (voice)
-    {
-        voice->stop(true);
-    }
-}
-
-void
-FGVoicePlayer::resume()
-{
-    if (!paused)
-        return;
-    paused = false;
-    if (voice)
-    {
-        voice->play();
-    }
-}
-
-SGSoundSample *
-FGVoicePlayer::get_sample (const char *name)
-{
-  string refname;
-  refname = dev_name + "/" + dir_prefix + name;
-
-  SGSoundSample *sample = _sgr->find(refname);
-  if (! sample)
-    {
-      string filename = dir_prefix + string(name) + ".wav";
-      try
-       {
-         sample = new SGSoundSample(filename.c_str(), SGPath());
-       }
-      catch (const sg_exception &e)
-       {
-         SG_LOG(SG_INSTR, SG_ALERT, "Error loading sound sample \"" + filename + "\": " + e.getFormattedMessage());
-         exit(1);
-       }
-
-      _sgr->add(sample, refname);
-      samples[refname] = sample;
-    }
-
-  return sample;
-}
-
-void
-FGVoicePlayer::play (Voice *_voice, unsigned int flags)
-{
-  if (!_voice)
-      return;
-  if (test_bits(flags, PLAY_NOW) || ! voice ||
-      (voice->element && voice->element->silence))
-    {
-      if (voice)
-       voice->stop(true);
-
-      voice = _voice;
-      looped = test_bits(flags, PLAY_LOOPED);
-
-      next_voice = NULL;
-      next_looped = false;
-
-      if (!paused)
-          voice->play();
-    }
-  else
-    {
-      next_voice = _voice;
-      next_looped = test_bits(flags, PLAY_LOOPED);
-    }
-}
-
-void
-FGVoicePlayer::stop (unsigned int flags)
-{
-  if (voice)
-    {
-      voice->stop(test_bits(flags, STOP_NOW));
-      if (voice->element)
-       looped = false;
-      else
-       voice = NULL;
-      next_voice = NULL;
-    }
-}
-
-void
-FGVoicePlayer::set_volume (float _volume)
-{
-  volume = _volume;
-  if (voice)
-    voice->volume_changed();
-}
-
-void
-FGVoicePlayer::update ()
-{
-  if (voice)
-    {
-      voice->update();
-
-      if (next_voice)
-       {
-         if (! voice->element || voice->element->silence)
-           {
-             voice = next_voice;
-             looped = next_looped;
-
-             next_voice = NULL;
-             next_looped = false;
-
-             voice->play();
-           }
-       }
-      else
-       {
-         if (! voice->element)
-           {
-             if (looped)
-               voice->play();
-             else
-               voice = NULL;
-           }
-       }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // MK_VIII::VoicePlayer ///////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
index 3dbd9ce04ce91b2a161ed08c8bc38e0fe3bc4015..b761ae2a97583b79e788d549a71fa7bf9df58d40 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <simgear/props/props.hxx>
 #include <simgear/props/tiedpropertylist.hxx>
-#include <simgear/sound/sample_openal.hxx>
 #include <simgear/structure/subsystem_mgr.hxx>
 using std::vector;
 using std::deque;
@@ -41,298 +40,13 @@ class SGSampleGroup;
 #include <Airports/runways.hxx>
 #include <Airports/simple.hxx>
 #include <Main/globals.hxx>
+#include <Sound/voiceplayer.hxx>
 
 #ifdef _MSC_VER
 #  pragma warning( push )
 #  pragma warning( disable: 4355 )
 #endif
 
-/////////////////////////////////////////////////////////////////////////////
-// FGVoicePlayer /////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////////////
-
-class FGVoicePlayer
-{
-public:
-
-    /////////////////////////////////////////////////////////////////////////////
-    // MK::RawValueMethodsData /////////////////////////////////////////////
-    /////////////////////////////////////////////////////////////////////////////
-
-    template <class C, class VT, class DT>
-    class RawValueMethodsData : public SGRawValue<VT>
-    {
-    public:
-      typedef VT (C::*getter_t) (DT) const;
-      typedef void (C::*setter_t) (DT, VT);
-
-      RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
-        : _obj(obj), _data(data), _getter(getter), _setter(setter) {}
-
-      virtual VT getValue () const
-      {
-        if (_getter)
-      return (_obj.*_getter)(_data);
-        else
-      return SGRawValue<VT>::DefaultValue();
-      }
-      virtual bool setValue (VT value)
-      {
-        if (_setter)
-      {
-        (_obj.*_setter)(_data, value);
-        return true;
-      }
-        else
-      return false;
-      }
-      virtual SGRawValue<VT> *clone () const 
-      {
-        return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
-      }
-
-    private:
-      C       &_obj;
-      DT      _data;
-      getter_t    _getter;
-      setter_t    _setter;
-    };
-    
-    class PropertiesHandler : public simgear::TiedPropertyList
-    {
-    public:
-
-      template <class T>
-      inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
-      {
-          Tie(node,raw_value);
-      }
-
-      template <class T>
-      inline void tie (SGPropertyNode *node,
-               const char *relative_path,
-               const SGRawValue<T> &raw_value)
-      {
-        Tie(node->getNode(relative_path, true),raw_value);
-      }
-
-      PropertiesHandler() {};
-
-      void unbind () {Untie();}
-    };
-
-  ///////////////////////////////////////////////////////////////////////////
-  // FGVoicePlayer::Voice ////////////////////////////////////////////
-  ///////////////////////////////////////////////////////////////////////////
-
-  class Voice
-  {
-  public:
-
-    /////////////////////////////////////////////////////////////////////////
-    // FGVoicePlayer::Voice::Element ////////////////////////////////////////
-    /////////////////////////////////////////////////////////////////////////
-
-    class Element
-    {
-    public:
-        bool silence;
-
-        virtual inline void play (float volume) {}
-        virtual inline void stop () {}
-        virtual bool is_playing () = 0;
-        virtual inline void set_volume (float volume) {}
-    };
-
-    /////////////////////////////////////////////////////////////////////////
-    // FGVoicePlayer::Voice::SampleElement ///////////////////////////
-    /////////////////////////////////////////////////////////////////////////
-
-    class SampleElement : public Element
-    {
-        SGSharedPtr<SGSoundSample>  _sample;
-        float               _volume;
-
-    public:
-        inline SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0)
-          : _sample(sample), _volume(volume) { silence = false; }
-
-        virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
-        virtual inline void stop () { if (_sample) _sample->stop(); }
-        virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
-        virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
-    };
-
-    /////////////////////////////////////////////////////////////////////////
-    // FGVoicePlayer::Voice::SilenceElement //////////////////////////
-    /////////////////////////////////////////////////////////////////////////
-
-    class SilenceElement : public Element
-    {
-        double _duration;
-        double start_time;
-
-    public:
-        inline SilenceElement (double duration)
-          : _duration(duration) { silence = true; }
-
-        virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
-        virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
-    };
-
-    /////////////////////////////////////////////////////////////////////////
-    // FGVoicePlayer::Voice (continued) //////////////////////////////
-    /////////////////////////////////////////////////////////////////////////
-
-    Element *element;
-
-    inline Voice (FGVoicePlayer *_player)
-      : element(NULL), player(_player), volume(1.0) {}
-
-    ~Voice ();
-
-    inline void append (Element *_element) { elements.push_back(_element); }
-
-    void play ();
-    void stop (bool now);
-    void set_volume (float _volume);
-    void volume_changed ();
-    void update ();
-
-  private:
-      FGVoicePlayer *player;
-
-      float volume;
-
-      vector<Element *>         elements;
-      vector<Element *>::iterator   iter;
-
-      inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
-  };
-
-  ///////////////////////////////////////////////////////////////////////////
-  // FGVoicePlayer (continued) ///////////////////////////////////////
-  ///////////////////////////////////////////////////////////////////////////
-
-  struct
-  {
-    float volume;
-  } conf;
-
-  float volume;
-
-  Voice *voice;
-  Voice *next_voice;
-  bool paused;
-  string dev_name;
-  string dir_prefix;
-
-  inline FGVoicePlayer (PropertiesHandler* properties_handler, string _dev_name)
-    : volume(1.0), voice(NULL), next_voice(NULL), paused(false),
-      dev_name(_dev_name), dir_prefix(""),
-      speaker(this,properties_handler) {}
-
-  ~FGVoicePlayer ();
-
-  void init ();
-  void pause();
-  void resume();
-  bool is_playing() { return (voice!=NULL);}
-
-  enum
-  {
-    PLAY_NOW      = 1 << 0,
-    PLAY_LOOPED   = 1 << 1
-  };
-  void play (Voice *_voice, unsigned int flags = 0);
-
-  enum
-  {
-    STOP_NOW      = 1 << 0
-  };
-  void stop (unsigned int flags = 0);
-
-  void set_volume (float _volume);
-  void update ();
-
-  void bind (SGPropertyNode *node, const char* default_dir_prefix);
-
-public:
-
-  ///////////////////////////////////////////////////////////////////////////
-  // FGVoicePlayer::Speaker //////////////////////////////////////////
-  ///////////////////////////////////////////////////////////////////////////
-
-  class Speaker
-  {
-    FGVoicePlayer *player;
-    PropertiesHandler* properties_handler;
-
-    double    pitch;
-
-    template <class T>
-    inline void tie (SGPropertyNode *node, const char *name, T *ptr)
-    {
-    properties_handler->tie
-    (node, (string("speaker/") + name).c_str(),
-     RawValueMethodsData<FGVoicePlayer::Speaker,T,T*>
-     (*this, ptr,
-      &FGVoicePlayer::Speaker::get_property,
-      &FGVoicePlayer::Speaker::set_property));
-    }
-
-  public:
-    template <class T>
-    inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
-
-    template <class T>
-    inline T get_property (T *ptr) const { return *ptr; }
-
-    float volume;
-
-    inline Speaker (FGVoicePlayer *_player,PropertiesHandler* _properties_handler)
-  : player(_player),
-    properties_handler(_properties_handler),
-    pitch(1),
-    volume(1)
-    {
-    }
-
-    void bind (SGPropertyNode *node);
-    void update_configuration ();
-  };
-
-protected:
-  ///////////////////////////////////////////////////////////////////////////
-  // FGVoicePlayer (continued) ///////////////////////////////////////
-  ///////////////////////////////////////////////////////////////////////////
-
-  SGSharedPtr<SGSampleGroup> _sgr;
-  Speaker speaker;
-
-  map< string, SGSharedPtr<SGSoundSample> >   samples;
-  vector<Voice *>         _voices;
-
-  bool looped;
-  bool next_looped;
-
-  SGSoundSample *get_sample (const char *name);
-
-  inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
-  inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
-  inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
-
-  inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
-
-  template <class T1>
-  inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
-  template <class T1, class T2>
-  inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
-  template <class T1, class T2, class T3>
-  inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
-  template <class T1, class T2, class T3, class T4>
-  inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
-};
 
 ///////////////////////////////////////////////////////////////////////////////
 // MK_VIII ////////////////////////////////////////////////////////////////////
index dbab3164ddf9c97ed504a9c053539f10ef9bf505..f6b84862d6f482c2e37a39ff1d353826c6417cfa 100644 (file)
 #include <simgear/sg_inlines.h>
 #include <simgear/debug/logstream.hxx>
 #include <simgear/math/sg_geodesy.hxx>
-#include <simgear/math/sg_random.h>
-#include <simgear/misc/sg_path.hxx>
 #include <simgear/sound/soundmgr_openal.hxx>
 #include <simgear/structure/exception.hxx>
 
@@ -115,7 +113,6 @@ using std::string;
 
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
-#include <AIModel/submodel.hxx>
 #include "instrument_mgr.hxx"
 #include "tcas.hxx"
 
index 2288a7dbeb438b2f2c5ca031a64a1280ce90ad02..952297fd090cfd7382e661e66c4a4ebc6d3818d5 100644 (file)
@@ -28,9 +28,8 @@
 #include <map>
 
 #include <simgear/props/props.hxx>
-#include <simgear/sound/sample_openal.hxx>
 #include <simgear/structure/subsystem_mgr.hxx>
-#include "mk_viii.hxx" // FGVoicePlayer only
+#include <Sound/voiceplayer.hxx>
 
 using std::vector;
 using std::deque;
index 5d498c24dd854f22a62a018154203bbc64356b55..f147287626883cffe181ec237c53f255b0f46a54 100644 (file)
@@ -6,6 +6,7 @@ set(SOURCES
        morse.cxx
        sample_queue.cxx
        voice.cxx
+       voiceplayer.cxx
        )
        
 flightgear_component(Sound "${SOURCES}")
\ No newline at end of file
index 1512dd36943dead850dcc07bd357cb83397d644c..4cd2df9e2a3b12c146d5fbb21424b4512a068e09 100644 (file)
@@ -5,6 +5,7 @@ libSound_a_SOURCES = \
        fg_fx.cxx fg_fx.hxx \
        morse.cxx morse.hxx \
        voice.cxx voice.hxx \
-       sample_queue.cxx sample_queue.hxx
+       sample_queue.cxx sample_queue.hxx \
+       voiceplayer.cxx voiceplayer.hxx
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
index 6bbc076ceb87b84f44d464a9c80576100f77a89a..3f51104eec2c40ddb41effcb1dba1d09879f0f87 100644 (file)
@@ -39,8 +39,8 @@ class SGSoundSample;
  *
  *    This modules maintains a queue of 'message' audio files.  These
  *    are played sequentially with no overlap until the queue is finished.
- *    This second mechanims is useful for things like tutorial messages or
- *    background atc chatter.
+ *    This second mechanisms is useful for things like tutorial messages or
+ *    background ATC chatter.
  */
 class FGSampleQueue : public SGSampleGroup
 {
diff --git a/src/Sound/voiceplayer.cxx b/src/Sound/voiceplayer.cxx
new file mode 100644 (file)
index 0000000..1a839cf
--- /dev/null
@@ -0,0 +1,314 @@
+// voiceplayer.cxx -- voice/sound sample player
+//
+// Written by Jean-Yves Lefort, started September 2005.
+//
+// Copyright (C) 2005, 2006  Jean-Yves Lefort - jylefort@FreeBSD.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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+#  pragma warning( disable: 4355 )
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+#include <string>
+#include <sstream>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/sound/soundmgr_openal.hxx>
+#include <simgear/structure/exception.hxx>
+
+using std::string;
+
+#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H
+#  include <Include/version.h>
+#else
+#  include <Include/no_version.h>
+#endif
+
+#include "voiceplayer.hxx"
+
+///////////////////////////////////////////////////////////////////////////////
+// constants //////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// helpers ////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+#define ADD_VOICE(Var,Sample,Twice) \
+    { make_voice(&Var);append(Var,Sample);\
+      if (Twice) append(Var,Sample); }
+
+#define test_bits(_bits, _test) (((_bits) & (_test)) != 0)
+
+///////////////////////////////////////////////////////////////////////////////
+// FGVoicePlayer //////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+void
+FGVoicePlayer::Speaker::bind (SGPropertyNode *node)
+{
+    // uses xmlsound property names
+    tie(node, "volume", &volume);
+    tie(node, "pitch", &pitch);
+}
+
+void
+FGVoicePlayer::Speaker::update_configuration ()
+{
+    map< string, SGSharedPtr<SGSoundSample> >::iterator iter;
+    for (iter = player->samples.begin(); iter != player->samples.end(); iter++)
+    {
+        SGSoundSample *sample = (*iter).second;
+
+        sample->set_pitch(pitch);
+    }
+
+    if (player->voice)
+        player->voice->volume_changed();
+}
+
+FGVoicePlayer::Voice::~Voice ()
+{
+    for (iter = elements.begin(); iter != elements.end(); iter++)
+        delete *iter;       // we owned the element
+    elements.clear();
+}
+
+void
+FGVoicePlayer::Voice::play ()
+{
+    iter = elements.begin();
+    element = *iter;
+
+    element->play(get_volume());
+}
+
+void
+FGVoicePlayer::Voice::stop (bool now)
+{
+    if (element)
+    {
+        if (now || element->silence)
+        {
+            element->stop();
+            element = NULL;
+        }
+        else
+            iter = elements.end() - 1; // stop after the current element finishes
+    }
+}
+
+void
+FGVoicePlayer::Voice::set_volume (float _volume)
+{
+    volume = _volume;
+    volume_changed();
+}
+
+void
+FGVoicePlayer::Voice::volume_changed ()
+{
+    if (element)
+        element->set_volume(get_volume());
+}
+
+void
+FGVoicePlayer::Voice::update ()
+{
+    if (element)
+    {
+        if (! element->is_playing())
+        {
+            if (++iter == elements.end())
+                element = NULL;
+            else
+            {
+                element = *iter;
+                element->play(get_volume());
+            }
+        }
+    }
+}
+
+FGVoicePlayer::~FGVoicePlayer ()
+{
+    vector<Voice *>::iterator iter1;
+    for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++)
+        delete *iter1;
+    _voices.clear();
+    samples.clear();
+}
+
+void
+FGVoicePlayer::bind (SGPropertyNode *node, const char* default_dir_prefix)
+{
+    dir_prefix = node->getStringValue("voice/file-prefix", default_dir_prefix);
+    speaker.bind(node);
+}
+
+void
+FGVoicePlayer::init ()
+{
+    SGSoundMgr *smgr = globals->get_soundmgr();
+    _sgr = smgr->find("avionics", true);
+    _sgr->tie_to_listener();
+    speaker.update_configuration();
+}
+
+void
+FGVoicePlayer::pause()
+{
+    if (paused)
+        return;
+
+    paused = true;
+    if (voice)
+    {
+        voice->stop(true);
+    }
+}
+
+void
+FGVoicePlayer::resume()
+{
+    if (!paused)
+        return;
+    paused = false;
+    if (voice)
+    {
+        voice->play();
+    }
+}
+
+SGSoundSample *
+FGVoicePlayer::get_sample (const char *name)
+{
+    string refname;
+    refname = dev_name + "/" + dir_prefix + name;
+
+    SGSoundSample *sample = _sgr->find(refname);
+    if (! sample)
+    {
+        string filename = dir_prefix + string(name) + ".wav";
+        try
+        {
+            sample = new SGSoundSample(filename.c_str(), SGPath());
+        }
+        catch (const sg_exception &e)
+        {
+            SG_LOG(SG_INSTR, SG_ALERT, "Error loading sound sample \"" + filename + "\": " + e.getFormattedMessage());
+            exit(1);
+        }
+
+        _sgr->add(sample, refname);
+        samples[refname] = sample;
+    }
+
+    return sample;
+}
+
+void
+FGVoicePlayer::play (Voice *_voice, unsigned int flags)
+{
+    if (!_voice)
+        return;
+    if (test_bits(flags, PLAY_NOW) || ! voice ||
+            (voice->element && voice->element->silence))
+    {
+        if (voice)
+            voice->stop(true);
+
+        voice = _voice;
+        looped = test_bits(flags, PLAY_LOOPED);
+
+        next_voice = NULL;
+        next_looped = false;
+
+        if (!paused)
+            voice->play();
+    }
+    else
+    {
+        next_voice = _voice;
+        next_looped = test_bits(flags, PLAY_LOOPED);
+    }
+}
+
+void
+FGVoicePlayer::stop (unsigned int flags)
+{
+    if (voice)
+    {
+        voice->stop(test_bits(flags, STOP_NOW));
+        if (voice->element)
+            looped = false;
+        else
+            voice = NULL;
+        next_voice = NULL;
+    }
+}
+
+void
+FGVoicePlayer::set_volume (float _volume)
+{
+    volume = _volume;
+    if (voice)
+        voice->volume_changed();
+}
+
+void
+FGVoicePlayer::update ()
+{
+    if (voice)
+    {
+        voice->update();
+
+        if (next_voice)
+        {
+            if (! voice->element || voice->element->silence)
+            {
+                voice = next_voice;
+                looped = next_looped;
+
+                next_voice = NULL;
+                next_looped = false;
+
+                voice->play();
+            }
+        }
+        else
+        {
+            if (! voice->element)
+            {
+                if (looped)
+                    voice->play();
+                else
+                    voice = NULL;
+            }
+        }
+    }
+}
diff --git a/src/Sound/voiceplayer.hxx b/src/Sound/voiceplayer.hxx
new file mode 100644 (file)
index 0000000..762b9a3
--- /dev/null
@@ -0,0 +1,334 @@
+// voiceplayer.hxx -- voice/sound sample player
+//
+// Written by Jean-Yves Lefort, started September 2005.
+//
+// Copyright (C) 2005, 2006  Jean-Yves Lefort - jylefort@FreeBSD.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.
+
+
+#ifndef __SOUND_VOICEPLAYER_HXX
+#define __SOUND_VOICEPLAYER_HXX
+
+#include <assert.h>
+
+#include <vector>
+#include <deque>
+#include <map>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/tiedpropertylist.hxx>
+#include <simgear/sound/sample_openal.hxx>
+using std::vector;
+using std::deque;
+using std::map;
+
+class SGSampleGroup;
+
+#include <Main/globals.hxx>
+
+#ifdef _MSC_VER
+#  pragma warning( push )
+#  pragma warning( disable: 4355 )
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// FGVoicePlayer /////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+class FGVoicePlayer
+{
+public:
+
+    /////////////////////////////////////////////////////////////////////////////
+    // MK::RawValueMethodsData /////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////////
+
+    template <class C, class VT, class DT>
+    class RawValueMethodsData : public SGRawValue<VT>
+    {
+    public:
+      typedef VT (C::*getter_t) (DT) const;
+      typedef void (C::*setter_t) (DT, VT);
+
+      RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
+        : _obj(obj), _data(data), _getter(getter), _setter(setter) {}
+
+      virtual VT getValue () const
+      {
+        if (_getter)
+      return (_obj.*_getter)(_data);
+        else
+      return SGRawValue<VT>::DefaultValue();
+      }
+      virtual bool setValue (VT value)
+      {
+        if (_setter)
+      {
+        (_obj.*_setter)(_data, value);
+        return true;
+      }
+        else
+      return false;
+      }
+      virtual SGRawValue<VT> *clone () const 
+      {
+        return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
+      }
+
+    private:
+      C       &_obj;
+      DT      _data;
+      getter_t    _getter;
+      setter_t    _setter;
+    };
+    
+    class PropertiesHandler : public simgear::TiedPropertyList
+    {
+    public:
+
+      template <class T>
+      inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
+      {
+          Tie(node,raw_value);
+      }
+
+      template <class T>
+      inline void tie (SGPropertyNode *node,
+               const char *relative_path,
+               const SGRawValue<T> &raw_value)
+      {
+        Tie(node->getNode(relative_path, true),raw_value);
+      }
+
+      PropertiesHandler() {};
+
+      void unbind () {Untie();}
+    };
+
+  ///////////////////////////////////////////////////////////////////////////
+  // FGVoicePlayer::Voice ////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////
+
+  class Voice
+  {
+  public:
+
+    /////////////////////////////////////////////////////////////////////////
+    // FGVoicePlayer::Voice::Element ////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////
+
+    class Element
+    {
+    public:
+        bool silence;
+
+        virtual inline void play (float volume) {}
+        virtual inline void stop () {}
+        virtual bool is_playing () = 0;
+        virtual inline void set_volume (float volume) {}
+    };
+
+    /////////////////////////////////////////////////////////////////////////
+    // FGVoicePlayer::Voice::SampleElement ///////////////////////////
+    /////////////////////////////////////////////////////////////////////////
+
+    class SampleElement : public Element
+    {
+        SGSharedPtr<SGSoundSample>  _sample;
+        float               _volume;
+
+    public:
+        inline SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0)
+          : _sample(sample), _volume(volume) { silence = false; }
+
+        virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
+        virtual inline void stop () { if (_sample) _sample->stop(); }
+        virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
+        virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
+    };
+
+    /////////////////////////////////////////////////////////////////////////
+    // FGVoicePlayer::Voice::SilenceElement //////////////////////////
+    /////////////////////////////////////////////////////////////////////////
+
+    class SilenceElement : public Element
+    {
+        double _duration;
+        double start_time;
+
+    public:
+        inline SilenceElement (double duration)
+          : _duration(duration) { silence = true; }
+
+        virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
+        virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
+    };
+
+    /////////////////////////////////////////////////////////////////////////
+    // FGVoicePlayer::Voice (continued) //////////////////////////////
+    /////////////////////////////////////////////////////////////////////////
+
+    Element *element;
+
+    inline Voice (FGVoicePlayer *_player)
+      : element(NULL), player(_player), volume(1.0) {}
+
+    ~Voice ();
+
+    inline void append (Element *_element) { elements.push_back(_element); }
+
+    void play ();
+    void stop (bool now);
+    void set_volume (float _volume);
+    void volume_changed ();
+    void update ();
+
+  private:
+      FGVoicePlayer *player;
+
+      float volume;
+
+      vector<Element *>         elements;
+      vector<Element *>::iterator   iter;
+
+      inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
+  };
+
+  ///////////////////////////////////////////////////////////////////////////
+  // FGVoicePlayer (continued) ///////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////
+
+  struct
+  {
+    float volume;
+  } conf;
+
+  float volume;
+
+  Voice *voice;
+  Voice *next_voice;
+  bool paused;
+  string dev_name;
+  string dir_prefix;
+
+  inline FGVoicePlayer (PropertiesHandler* properties_handler, string _dev_name)
+    : volume(1.0), voice(NULL), next_voice(NULL), paused(false),
+      dev_name(_dev_name), dir_prefix(""),
+      speaker(this,properties_handler) {}
+
+  ~FGVoicePlayer ();
+
+  void init ();
+  void pause();
+  void resume();
+  bool is_playing() { return (voice!=NULL);}
+
+  enum
+  {
+    PLAY_NOW      = 1 << 0,
+    PLAY_LOOPED   = 1 << 1
+  };
+  void play (Voice *_voice, unsigned int flags = 0);
+
+  enum
+  {
+    STOP_NOW      = 1 << 0
+  };
+  void stop (unsigned int flags = 0);
+
+  void set_volume (float _volume);
+  void update ();
+
+  void bind (SGPropertyNode *node, const char* default_dir_prefix);
+
+public:
+
+  ///////////////////////////////////////////////////////////////////////////
+  // FGVoicePlayer::Speaker //////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////
+
+  class Speaker
+  {
+    FGVoicePlayer *player;
+    PropertiesHandler* properties_handler;
+
+    double    pitch;
+
+    template <class T>
+    inline void tie (SGPropertyNode *node, const char *name, T *ptr)
+    {
+    properties_handler->tie
+    (node, (string("speaker/") + name).c_str(),
+     RawValueMethodsData<FGVoicePlayer::Speaker,T,T*>
+     (*this, ptr,
+      &FGVoicePlayer::Speaker::get_property,
+      &FGVoicePlayer::Speaker::set_property));
+    }
+
+  public:
+    template <class T>
+    inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
+
+    template <class T>
+    inline T get_property (T *ptr) const { return *ptr; }
+
+    float volume;
+
+    inline Speaker (FGVoicePlayer *_player,PropertiesHandler* _properties_handler)
+  : player(_player),
+    properties_handler(_properties_handler),
+    pitch(1),
+    volume(1)
+    {
+    }
+
+    void bind (SGPropertyNode *node);
+    void update_configuration ();
+  };
+
+protected:
+  ///////////////////////////////////////////////////////////////////////////
+  // FGVoicePlayer (continued) ///////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////
+
+  SGSharedPtr<SGSampleGroup> _sgr;
+  Speaker speaker;
+
+  map< string, SGSharedPtr<SGSoundSample> >   samples;
+  vector<Voice *>         _voices;
+
+  bool looped;
+  bool next_looped;
+
+  SGSoundSample *get_sample (const char *name);
+
+  inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
+  inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
+  inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
+
+  inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
+
+  template <class T1>
+  inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
+  template <class T1, class T2>
+  inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
+  template <class T1, class T2, class T3>
+  inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
+  template <class T1, class T2, class T3, class T4>
+  inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
+};
+
+#endif // __SOUND_VOICEPLAYER_HXX