GPWS and TCAS are now completely separate - but use the same voice player.
<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
<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
}
-///////////////////////////////////////////////////////////////////////////////
-// 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 ///////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#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;
#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 ////////////////////////////////////////////////////////////////////
#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>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
-#include <AIModel/submodel.hxx>
#include "instrument_mgr.hxx"
#include "tcas.hxx"
#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;
morse.cxx
sample_queue.cxx
voice.cxx
+ voiceplayer.cxx
)
flightgear_component(Sound "${SOURCES}")
\ No newline at end of file
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
*
* 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
{
--- /dev/null
+// 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;
+ }
+ }
+ }
+}
--- /dev/null
+// 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