From dd7c88b8cb7bfd84dec3ce7dd0699a5652288b2a Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Wed, 29 Dec 2010 21:57:49 +0100 Subject: [PATCH] Make voiceplayer independent - former mk-viii voiceplayer is now an independent FGVoicePlayer - voiceplayer still sits in mk-viii module for now - add option to configure location/prefix of voice samples - add pause/resume to voiceplayer --- src/Instrumentation/mk_viii.cxx | 196 ++++++---- src/Instrumentation/mk_viii.hxx | 633 +++++++++++++++++--------------- 2 files changed, 450 insertions(+), 379 deletions(-) diff --git a/src/Instrumentation/mk_viii.cxx b/src/Instrumentation/mk_viii.cxx index 8fb871a4a..065dc232d 100644 --- a/src/Instrumentation/mk_viii.cxx +++ b/src/Instrumentation/mk_viii.cxx @@ -210,17 +210,6 @@ MK_VIII::PropertiesHandler::init () mk_node(vs) = fgGetNode("/velocities/vertical-speed-fps", true); } -void -MK_VIII::PropertiesHandler::unbind () -{ - vector::iterator iter; - - for (iter = tied_properties.begin(); iter != tied_properties.end(); iter++) - (*iter)->untie(); - - tied_properties.clear(); -} - /////////////////////////////////////////////////////////////////////////////// // PowerHandler /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -1858,7 +1847,8 @@ MK_VIII::IOHandler::tie_input (SGPropertyNode *node, bool *input, bool *feed) { - mk->properties_handler.tie(node, (string("inputs/discretes/") + name).c_str(), RawValueMethodsData(*this, input, &MK_VIII::IOHandler::get_discrete_input, &MK_VIII::IOHandler::set_discrete_input)); + mk->properties_handler.tie(node, (string("inputs/discretes/") + name).c_str(), + FGVoicePlayer::RawValueMethodsData(*this, input, &MK_VIII::IOHandler::get_discrete_input, &MK_VIII::IOHandler::set_discrete_input)); if (feed) mk->properties_handler.tie(node, (string("input-feeders/discretes/") + name).c_str(), SGRawValuePointer(feed)); } @@ -2144,11 +2134,22 @@ MK_VIII::IOHandler::set_present_status (bool value) /////////////////////////////////////////////////////////////////////////////// -// VoicePlayer //////////////////////////////////////////////////////////////// +// FGVoicePlayer ////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void -MK_VIII::VoicePlayer::Speaker::bind (SGPropertyNode *node) +FGVoicePlayer::PropertiesHandler::unbind () +{ + vector::iterator iter; + + for (iter = tied_properties.begin(); iter != tied_properties.end(); iter++) + (*iter)->untie(); + + tied_properties.clear(); +} + +void +FGVoicePlayer::Speaker::bind (SGPropertyNode *node) { // uses xmlsound property names tie(node, "volume", &volume); @@ -2156,7 +2157,7 @@ MK_VIII::VoicePlayer::Speaker::bind (SGPropertyNode *node) } void -MK_VIII::VoicePlayer::Speaker::update_configuration () +FGVoicePlayer::Speaker::update_configuration () { map< string, SGSharedPtr >::iterator iter; for (iter = player->samples.begin(); iter != player->samples.end(); iter++) @@ -2170,7 +2171,7 @@ MK_VIII::VoicePlayer::Speaker::update_configuration () player->voice->volume_changed(); } -MK_VIII::VoicePlayer::Voice::~Voice () +FGVoicePlayer::Voice::~Voice () { for (iter = elements.begin(); iter != elements.end(); iter++) delete *iter; // we owned the element @@ -2178,7 +2179,7 @@ MK_VIII::VoicePlayer::Voice::~Voice () } void -MK_VIII::VoicePlayer::Voice::play () +FGVoicePlayer::Voice::play () { iter = elements.begin(); element = *iter; @@ -2187,7 +2188,7 @@ MK_VIII::VoicePlayer::Voice::play () } void -MK_VIII::VoicePlayer::Voice::stop (bool now) +FGVoicePlayer::Voice::stop (bool now) { if (element) { @@ -2202,21 +2203,21 @@ MK_VIII::VoicePlayer::Voice::stop (bool now) } void -MK_VIII::VoicePlayer::Voice::set_volume (float _volume) +FGVoicePlayer::Voice::set_volume (float _volume) { volume = _volume; volume_changed(); } void -MK_VIII::VoicePlayer::Voice::volume_changed () +FGVoicePlayer::Voice::volume_changed () { if (element) element->set_volume(get_volume()); } void -MK_VIII::VoicePlayer::Voice::update () +FGVoicePlayer::Voice::update () { if (element) { @@ -2233,7 +2234,7 @@ MK_VIII::VoicePlayer::Voice::update () } } -MK_VIII::VoicePlayer::~VoicePlayer () +FGVoicePlayer::~FGVoicePlayer () { vector::iterator iter1; for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++) @@ -2243,85 +2244,80 @@ MK_VIII::VoicePlayer::~VoicePlayer () } void -MK_VIII::VoicePlayer::init () +FGVoicePlayer::bind (SGPropertyNode *node, const char* default_dir_prefix) { -#define STDPAUSE 0.75 // [SPEC] 6.4.4: "the standard 0.75 second delay" + 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(); - - make_voice(&voices.application_data_base_failed, "application-data-base-failed"); - make_voice(&voices.bank_angle, "bank-angle"); - make_voice(&voices.bank_angle_bank_angle, "bank-angle", "bank-angle"); - make_voice(&voices.bank_angle_bank_angle_3, "bank-angle", "bank-angle", 3.0); - make_voice(&voices.bank_angle_inop, "bank-angle-inop"); - make_voice(&voices.bank_angle_pause_bank_angle, "bank-angle", STDPAUSE, "bank-angle"); - make_voice(&voices.bank_angle_pause_bank_angle_3, "bank-angle", STDPAUSE, "bank-angle", 3.0); - make_voice(&voices.callouts_inop, "callouts-inop"); - make_voice(&voices.configuration_type_invalid, "configuration-type-invalid"); - make_voice(&voices.dont_sink, "dont-sink"); - make_voice(&voices.dont_sink_pause_dont_sink, "dont-sink", STDPAUSE, "dont-sink"); - make_voice(&voices.five_hundred_above, "500-above"); - make_voice(&voices.glideslope, "glideslope"); - make_voice(&voices.glideslope_inop, "glideslope-inop"); - make_voice(&voices.gpws_inop, "gpws-inop"); - make_voice(&voices.hard_glideslope, "glideslope", "glideslope", 3.0); - make_voice(&voices.minimums, "minimums"); - make_voice(&voices.minimums_minimums, "minimums", "minimums"); - make_voice(&voices.pull_up, "pull-up"); - make_voice(&voices.sink_rate, "sink-rate"); - make_voice(&voices.sink_rate_pause_sink_rate, "sink-rate", STDPAUSE, "sink-rate"); - make_voice(&voices.soft_glideslope, new Voice::SampleElement(get_sample("glideslope"), modify_amplitude(1.0, -6))); - make_voice(&voices.terrain, "terrain"); - make_voice(&voices.terrain_pause_terrain, "terrain", STDPAUSE, "terrain"); - make_voice(&voices.too_low_flaps, "too-low-flaps"); - make_voice(&voices.too_low_gear, "too-low-gear"); - make_voice(&voices.too_low_terrain, "too-low-terrain"); - - for (unsigned i = 0; i < n_altitude_callouts; i++) - { - std::ostringstream name; - name << "altitude-" << mk->mode6_handler.altitude_callout_definitions[i]; - make_voice(&voices.altitude_callouts[i], name.str().c_str()); - } - speaker.update_configuration(); } -SGSoundSample * -MK_VIII::VoicePlayer::get_sample (const char *name) +void +FGVoicePlayer::pause() { - std::ostringstream refname; - refname << mk->name << "[" << mk->num << "]" << "/" << name; + if (paused) + return; - SGSoundSample *sample = _sgr->find(refname.str()); + 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 = "Sounds/mk-viii/" + string(name) + ".wav"; + 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 MK VIII sound sample \"" + filename + "\": " + e.getFormattedMessage()); + SG_LOG(SG_INSTR, SG_ALERT, "Error loading sound sample \"" + filename + "\": " + e.getFormattedMessage()); exit(1); } - _sgr->add(sample, refname.str()); - samples[refname.str()] = sample; + _sgr->add(sample, refname); + samples[refname] = sample; } return sample; } void -MK_VIII::VoicePlayer::play (Voice *_voice, unsigned int flags) +FGVoicePlayer::play (Voice *_voice, unsigned int flags) { if (!_voice) return; - if (test_bits(flags, PLAY_NOW) || ! voice || voice->element->silence) + if (test_bits(flags, PLAY_NOW) || ! voice || + (voice->element && voice->element->silence)) { if (voice) voice->stop(true); @@ -2332,7 +2328,8 @@ MK_VIII::VoicePlayer::play (Voice *_voice, unsigned int flags) next_voice = NULL; next_looped = false; - voice->play(); + if (!paused) + voice->play(); } else { @@ -2342,7 +2339,7 @@ MK_VIII::VoicePlayer::play (Voice *_voice, unsigned int flags) } void -MK_VIII::VoicePlayer::stop (unsigned int flags) +FGVoicePlayer::stop (unsigned int flags) { if (voice) { @@ -2356,7 +2353,7 @@ MK_VIII::VoicePlayer::stop (unsigned int flags) } void -MK_VIII::VoicePlayer::set_volume (float _volume) +FGVoicePlayer::set_volume (float _volume) { volume = _volume; if (voice) @@ -2364,7 +2361,7 @@ MK_VIII::VoicePlayer::set_volume (float _volume) } void -MK_VIII::VoicePlayer::update () +FGVoicePlayer::update () { if (voice) { @@ -2396,6 +2393,53 @@ MK_VIII::VoicePlayer::update () } } +/////////////////////////////////////////////////////////////////////////////// +// MK_VIII::VoicePlayer /////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +void +MK_VIII::VoicePlayer::init () +{ + FGVoicePlayer::init(); + +#define STDPAUSE 0.75 // [SPEC] 6.4.4: "the standard 0.75 second delay" + make_voice(&voices.application_data_base_failed, "application-data-base-failed"); + make_voice(&voices.bank_angle, "bank-angle"); + make_voice(&voices.bank_angle_bank_angle, "bank-angle", "bank-angle"); + make_voice(&voices.bank_angle_bank_angle_3, "bank-angle", "bank-angle", 3.0); + make_voice(&voices.bank_angle_inop, "bank-angle-inop"); + make_voice(&voices.bank_angle_pause_bank_angle, "bank-angle", STDPAUSE, "bank-angle"); + make_voice(&voices.bank_angle_pause_bank_angle_3, "bank-angle", STDPAUSE, "bank-angle", 3.0); + make_voice(&voices.callouts_inop, "callouts-inop"); + make_voice(&voices.configuration_type_invalid, "configuration-type-invalid"); + make_voice(&voices.dont_sink, "dont-sink"); + make_voice(&voices.dont_sink_pause_dont_sink, "dont-sink", STDPAUSE, "dont-sink"); + make_voice(&voices.five_hundred_above, "500-above"); + make_voice(&voices.glideslope, "glideslope"); + make_voice(&voices.glideslope_inop, "glideslope-inop"); + make_voice(&voices.gpws_inop, "gpws-inop"); + make_voice(&voices.hard_glideslope, "glideslope", "glideslope", 3.0); + make_voice(&voices.minimums, "minimums"); + make_voice(&voices.minimums_minimums, "minimums", "minimums"); + make_voice(&voices.pull_up, "pull-up"); + make_voice(&voices.sink_rate, "sink-rate"); + make_voice(&voices.sink_rate_pause_sink_rate, "sink-rate", STDPAUSE, "sink-rate"); + make_voice(&voices.soft_glideslope, new Voice::SampleElement(get_sample("glideslope"), modify_amplitude(1.0, -6))); + make_voice(&voices.terrain, "terrain"); + make_voice(&voices.terrain_pause_terrain, "terrain", STDPAUSE, "terrain"); + make_voice(&voices.too_low_flaps, "too-low-flaps"); + make_voice(&voices.too_low_gear, "too-low-gear"); + make_voice(&voices.too_low_terrain, "too-low-terrain"); + + for (unsigned i = 0; i < n_altitude_callouts; i++) + { + std::ostringstream name; + name << "altitude-" << MK_VIII::Mode6Handler::altitude_callout_definitions[i]; + make_voice(&voices.altitude_callouts[i], name.str().c_str()); + } + speaker.update_configuration(); +} + /////////////////////////////////////////////////////////////////////////////// // SelfTestHandler //////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -4949,7 +4993,7 @@ MK_VIII::bind () configuration_module.bind(node); power_handler.bind(node); io_handler.bind(node); - voice_player.bind(node); + voice_player.bind(node, "Sounds/mk-viii/"); } void diff --git a/src/Instrumentation/mk_viii.hxx b/src/Instrumentation/mk_viii.hxx index e37fc972b..053b53d05 100644 --- a/src/Instrumentation/mk_viii.hxx +++ b/src/Instrumentation/mk_viii.hxx @@ -47,6 +47,295 @@ class SGSampleGroup; # 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: + vector tied_properties; + + template + inline void tie (SGPropertyNode *node, const SGRawValue &raw_value) + { + node->tie(raw_value); + tied_properties.push_back(node); + } + + 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 (); + }; + + /////////////////////////////////////////////////////////////////////////// + // 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 //////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -56,49 +345,6 @@ class MK_VIII : public SGSubsystem // keep in sync with Mode6Handler::altitude_callout_definitions[] static const unsigned n_altitude_callouts = 11; - ///////////////////////////////////////////////////////////////////////////// - // MK_VIII::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; - }; - ///////////////////////////////////////////////////////////////////////////// // MK_VIII::Parameter /////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// @@ -184,12 +430,10 @@ class MK_VIII : public SGSubsystem // MK_VIII::PropertiesHandler /////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// - class PropertiesHandler + class PropertiesHandler : public FGVoicePlayer::PropertiesHandler { MK_VIII *mk; - vector tied_properties; - public: struct { @@ -225,27 +469,11 @@ class MK_VIII : public SGSubsystem } external_properties; inline PropertiesHandler (MK_VIII *device) - : mk(device) {} + : FGVoicePlayer::PropertiesHandler(), mk(device) {} - template - inline void tie (SGPropertyNode *node, const SGRawValue &raw_value) - { - node->tie(raw_value); - tied_properties.push_back(node); - } - - template - inline void tie (SGPropertyNode *node, - const char *relative_path, - const SGRawValue &raw_value) - { - tie(node->getNode(relative_path, true), raw_value); - } - - PropertiesHandler() {}; + PropertiesHandler() : FGVoicePlayer::PropertiesHandler() {} void init (); - void unbind (); }; public: @@ -716,250 +944,49 @@ public: bool *get_lamp_output (Lamp lamp); }; - - ///////////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer ///////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - - class VoicePlayer + + class VoicePlayer : public FGVoicePlayer { public: + VoicePlayer (MK_VIII *device) : + FGVoicePlayer(&device->properties_handler, "mk-viii") + {} - /////////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer::Voice //////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// + ~VoicePlayer() {} + void init (); - class Voice - { - public: - - ///////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer::Voice::Element //////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////// - - class Element + struct { - 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) {} - }; - - ///////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer::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); } - }; - - ///////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer::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; } - }; - - ///////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer::Voice (continued) ////////////////////////////// - ///////////////////////////////////////////////////////////////////////// - - Element *element; - - inline Voice (VoicePlayer *_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: - VoicePlayer *player; - - float volume; - - vector elements; - vector::iterator iter; - - inline float get_volume () const { return player->volume * player->speaker.volume * volume; } - }; - - /////////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer (continued) /////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - - struct - { - float volume; - } conf; - - float volume; - - Voice *voice; - Voice *next_voice; - - struct - { - Voice *application_data_base_failed; - Voice *bank_angle; - Voice *bank_angle_bank_angle; - Voice *bank_angle_bank_angle_3; - Voice *bank_angle_inop; - Voice *bank_angle_pause_bank_angle; - Voice *bank_angle_pause_bank_angle_3; - Voice *callouts_inop; - Voice *configuration_type_invalid; - Voice *dont_sink; - Voice *dont_sink_pause_dont_sink; - Voice *five_hundred_above; - Voice *glideslope; - Voice *glideslope_inop; - Voice *gpws_inop; - Voice *hard_glideslope; - Voice *minimums; - Voice *minimums_minimums; - Voice *pull_up; - Voice *sink_rate; - Voice *sink_rate_pause_sink_rate; - Voice *soft_glideslope; - Voice *terrain; - Voice *terrain_pause_terrain; - Voice *too_low_flaps; - Voice *too_low_gear; - Voice *too_low_terrain; - Voice *altitude_callouts[n_altitude_callouts]; - } voices; - - inline VoicePlayer (MK_VIII *device) - : voice(NULL), next_voice(NULL), mk(device), speaker(this) {} - - ~VoicePlayer (); - - void init (); - - 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 (); - - inline void bind (SGPropertyNode *node) { speaker.bind(node); } - - public: - - /////////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer::Speaker ////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - - class Speaker - { - VoicePlayer *player; - - double pitch; - - template - inline void tie (SGPropertyNode *node, const char *name, T *ptr) - { - player->mk->properties_handler.tie - (node, (string("speaker/") + name).c_str(), - RawValueMethodsData - (*this, ptr, - &MK_VIII::VoicePlayer::Speaker::get_property, - &MK_VIII::VoicePlayer::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 (VoicePlayer *_player) - : player(_player), - pitch(1), - volume(1) - { - } - - void bind (SGPropertyNode *node); - void update_configuration (); - }; - - private: - /////////////////////////////////////////////////////////////////////////// - // MK_VIII::VoicePlayer (continued) /////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - - MK_VIII *mk; - - 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); } + Voice *application_data_base_failed; + Voice *bank_angle; + Voice *bank_angle_bank_angle; + Voice *bank_angle_bank_angle_3; + Voice *bank_angle_inop; + Voice *bank_angle_pause_bank_angle; + Voice *bank_angle_pause_bank_angle_3; + Voice *callouts_inop; + Voice *configuration_type_invalid; + Voice *dont_sink; + Voice *dont_sink_pause_dont_sink; + Voice *five_hundred_above; + Voice *glideslope; + Voice *glideslope_inop; + Voice *gpws_inop; + Voice *hard_glideslope; + Voice *minimums; + Voice *minimums_minimums; + Voice *pull_up; + Voice *sink_rate; + Voice *sink_rate_pause_sink_rate; + Voice *soft_glideslope; + Voice *terrain; + Voice *terrain_pause_terrain; + Voice *too_low_flaps; + Voice *too_low_gear; + Voice *too_low_terrain; + Voice *altitude_callouts[n_altitude_callouts]; + } voices; + }; private: