diff --git a/projects/VC8/FlightGearLib.vcproj b/projects/VC8/FlightGearLib.vcproj index d2ee91060..51b010a13 100644 --- a/projects/VC8/FlightGearLib.vcproj +++ b/projects/VC8/FlightGearLib.vcproj @@ -1811,6 +1811,10 @@ + + + + + + + + >::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::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 /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// diff --git a/src/Instrumentation/mk_viii.hxx b/src/Instrumentation/mk_viii.hxx index 3dbd9ce04..b761ae2a9 100644 --- a/src/Instrumentation/mk_viii.hxx +++ b/src/Instrumentation/mk_viii.hxx @@ -30,7 +30,6 @@ #include #include -#include #include using std::vector; using std::deque; @@ -41,298 +40,13 @@ class SGSampleGroup; #include #include #include
+#include #ifdef _MSC_VER # pragma warning( push ) # pragma warning( disable: 4355 ) #endif -///////////////////////////////////////////////////////////////////////////// -// FGVoicePlayer ///////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -class FGVoicePlayer -{ -public: - - ///////////////////////////////////////////////////////////////////////////// - // MK::RawValueMethodsData ///////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - - template - class RawValueMethodsData : public SGRawValue - { - 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::DefaultValue(); - } - virtual bool setValue (VT value) - { - if (_setter) - { - (_obj.*_setter)(_data, value); - return true; - } - else - return false; - } - virtual SGRawValue *clone () const - { - return new RawValueMethodsData(_obj, _data, _getter, _setter); - } - - private: - C &_obj; - DT _data; - getter_t _getter; - setter_t _setter; - }; - - class PropertiesHandler : public simgear::TiedPropertyList - { - public: - - template - inline void tie (SGPropertyNode *node, const SGRawValue &raw_value) - { - Tie(node,raw_value); - } - - template - inline void tie (SGPropertyNode *node, - const char *relative_path, - const SGRawValue &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 _sample; - float _volume; - - public: - inline SampleElement (SGSharedPtr 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 elements; - vector::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 - inline void tie (SGPropertyNode *node, const char *name, T *ptr) - { - properties_handler->tie - (node, (string("speaker/") + name).c_str(), - RawValueMethodsData - (*this, ptr, - &FGVoicePlayer::Speaker::get_property, - &FGVoicePlayer::Speaker::set_property)); - } - - public: - template - inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); } - - template - 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 _sgr; - Speaker speaker; - - map< string, SGSharedPtr > samples; - vector _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 - inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); } - template - inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); } - template - inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); } - template - 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 //////////////////////////////////////////////////////////////////// diff --git a/src/Instrumentation/tcas.cxx b/src/Instrumentation/tcas.cxx index dbab3164d..f6b84862d 100644 --- a/src/Instrumentation/tcas.cxx +++ b/src/Instrumentation/tcas.cxx @@ -100,8 +100,6 @@ #include #include #include -#include -#include #include #include @@ -115,7 +113,6 @@ using std::string; #include
#include
-#include #include "instrument_mgr.hxx" #include "tcas.hxx" diff --git a/src/Instrumentation/tcas.hxx b/src/Instrumentation/tcas.hxx index 2288a7dbe..952297fd0 100644 --- a/src/Instrumentation/tcas.hxx +++ b/src/Instrumentation/tcas.hxx @@ -28,9 +28,8 @@ #include #include -#include #include -#include "mk_viii.hxx" // FGVoicePlayer only +#include using std::vector; using std::deque; diff --git a/src/Sound/CMakeLists.txt b/src/Sound/CMakeLists.txt index 5d498c24d..f14728762 100644 --- a/src/Sound/CMakeLists.txt +++ b/src/Sound/CMakeLists.txt @@ -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 diff --git a/src/Sound/Makefile.am b/src/Sound/Makefile.am index 1512dd369..4cd2df9e2 100644 --- a/src/Sound/Makefile.am +++ b/src/Sound/Makefile.am @@ -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 diff --git a/src/Sound/sample_queue.hxx b/src/Sound/sample_queue.hxx index 6bbc076ce..3f51104ee 100644 --- a/src/Sound/sample_queue.hxx +++ b/src/Sound/sample_queue.hxx @@ -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 index 000000000..1a839cf3a --- /dev/null +++ b/src/Sound/voiceplayer.cxx @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +using std::string; + +#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H +# include +#else +# include +#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 >::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::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 index 000000000..762b9a36d --- /dev/null +++ b/src/Sound/voiceplayer.hxx @@ -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 + +#include +#include +#include + +#include +#include +#include +using std::vector; +using std::deque; +using std::map; + +class SGSampleGroup; + +#include
+ +#ifdef _MSC_VER +# pragma warning( push ) +# pragma warning( disable: 4355 ) +#endif + +///////////////////////////////////////////////////////////////////////////// +// FGVoicePlayer ///////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +class FGVoicePlayer +{ +public: + + ///////////////////////////////////////////////////////////////////////////// + // MK::RawValueMethodsData ///////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + + template + class RawValueMethodsData : public SGRawValue + { + 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::DefaultValue(); + } + virtual bool setValue (VT value) + { + if (_setter) + { + (_obj.*_setter)(_data, value); + return true; + } + else + return false; + } + virtual SGRawValue *clone () const + { + return new RawValueMethodsData(_obj, _data, _getter, _setter); + } + + private: + C &_obj; + DT _data; + getter_t _getter; + setter_t _setter; + }; + + class PropertiesHandler : public simgear::TiedPropertyList + { + public: + + template + inline void tie (SGPropertyNode *node, const SGRawValue &raw_value) + { + Tie(node,raw_value); + } + + template + inline void tie (SGPropertyNode *node, + const char *relative_path, + const SGRawValue &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 _sample; + float _volume; + + public: + inline SampleElement (SGSharedPtr 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 elements; + vector::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 + inline void tie (SGPropertyNode *node, const char *name, T *ptr) + { + properties_handler->tie + (node, (string("speaker/") + name).c_str(), + RawValueMethodsData + (*this, ptr, + &FGVoicePlayer::Speaker::get_property, + &FGVoicePlayer::Speaker::set_property)); + } + + public: + template + inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); } + + template + 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 _sgr; + Speaker speaker; + + map< string, SGSharedPtr > samples; + vector _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 + inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); } + template + inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); } + template + inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); } + template + 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