1
0
Fork 0

Cut&paste voiceplayer into a separate module.

GPWS and TCAS are now completely separate - but use the same voice player.
This commit is contained in:
ThorstenB 2011-03-09 23:49:25 +01:00
parent 59f2328551
commit badec14d27
11 changed files with 671 additions and 544 deletions

View file

@ -1811,6 +1811,10 @@
<File
RelativePath="..\..\src\sound\voice.hxx"
>
</File>
<File
RelativePath="..\..\src\sound\voiceplayer.hxx"
>
</File>
<File
RelativePath="..\..\src\fdm\yasim\Wing.hpp"
@ -3561,6 +3565,10 @@
<File
RelativePath="..\..\src\sound\voice.cxx"
>
</File>
<File
RelativePath="..\..\src\sound\voiceplayer.cxx"
>
</File>
<File
RelativePath="..\..\src\fdm\yasim\Wing.cpp"

View file

@ -3220,6 +3220,14 @@
<File
RelativePath="..\..\..\src\Sound\voice.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Sound\voiceplayer.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Sound\voiceplayer.hxx"
>
</File>
</Filter>
<Filter

View file

@ -2133,255 +2133,6 @@ MK_VIII::IOHandler::set_present_status (bool value)
}
///////////////////////////////////////////////////////////////////////////////
// FGVoicePlayer //////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void
FGVoicePlayer::Speaker::bind (SGPropertyNode *node)
{
// uses xmlsound property names
tie(node, "volume", &volume);
tie(node, "pitch", &pitch);
}
void
FGVoicePlayer::Speaker::update_configuration ()
{
map< string, SGSharedPtr<SGSoundSample> >::iterator iter;
for (iter = player->samples.begin(); iter != player->samples.end(); iter++)
{
SGSoundSample *sample = (*iter).second;
sample->set_pitch(pitch);
}
if (player->voice)
player->voice->volume_changed();
}
FGVoicePlayer::Voice::~Voice ()
{
for (iter = elements.begin(); iter != elements.end(); iter++)
delete *iter; // we owned the element
elements.clear();
}
void
FGVoicePlayer::Voice::play ()
{
iter = elements.begin();
element = *iter;
element->play(get_volume());
}
void
FGVoicePlayer::Voice::stop (bool now)
{
if (element)
{
if (now || element->silence)
{
element->stop();
element = NULL;
}
else
iter = elements.end() - 1; // stop after the current element finishes
}
}
void
FGVoicePlayer::Voice::set_volume (float _volume)
{
volume = _volume;
volume_changed();
}
void
FGVoicePlayer::Voice::volume_changed ()
{
if (element)
element->set_volume(get_volume());
}
void
FGVoicePlayer::Voice::update ()
{
if (element)
{
if (! element->is_playing())
{
if (++iter == elements.end())
element = NULL;
else
{
element = *iter;
element->play(get_volume());
}
}
}
}
FGVoicePlayer::~FGVoicePlayer ()
{
vector<Voice *>::iterator iter1;
for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++)
delete *iter1;
_voices.clear();
samples.clear();
}
void
FGVoicePlayer::bind (SGPropertyNode *node, const char* default_dir_prefix)
{
dir_prefix = node->getStringValue("voice/file-prefix", default_dir_prefix);
speaker.bind(node);
}
void
FGVoicePlayer::init ()
{
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
speaker.update_configuration();
}
void
FGVoicePlayer::pause()
{
if (paused)
return;
paused = true;
if (voice)
{
voice->stop(true);
}
}
void
FGVoicePlayer::resume()
{
if (!paused)
return;
paused = false;
if (voice)
{
voice->play();
}
}
SGSoundSample *
FGVoicePlayer::get_sample (const char *name)
{
string refname;
refname = dev_name + "/" + dir_prefix + name;
SGSoundSample *sample = _sgr->find(refname);
if (! sample)
{
string filename = dir_prefix + string(name) + ".wav";
try
{
sample = new SGSoundSample(filename.c_str(), SGPath());
}
catch (const sg_exception &e)
{
SG_LOG(SG_INSTR, SG_ALERT, "Error loading sound sample \"" + filename + "\": " + e.getFormattedMessage());
exit(1);
}
_sgr->add(sample, refname);
samples[refname] = sample;
}
return sample;
}
void
FGVoicePlayer::play (Voice *_voice, unsigned int flags)
{
if (!_voice)
return;
if (test_bits(flags, PLAY_NOW) || ! voice ||
(voice->element && voice->element->silence))
{
if (voice)
voice->stop(true);
voice = _voice;
looped = test_bits(flags, PLAY_LOOPED);
next_voice = NULL;
next_looped = false;
if (!paused)
voice->play();
}
else
{
next_voice = _voice;
next_looped = test_bits(flags, PLAY_LOOPED);
}
}
void
FGVoicePlayer::stop (unsigned int flags)
{
if (voice)
{
voice->stop(test_bits(flags, STOP_NOW));
if (voice->element)
looped = false;
else
voice = NULL;
next_voice = NULL;
}
}
void
FGVoicePlayer::set_volume (float _volume)
{
volume = _volume;
if (voice)
voice->volume_changed();
}
void
FGVoicePlayer::update ()
{
if (voice)
{
voice->update();
if (next_voice)
{
if (! voice->element || voice->element->silence)
{
voice = next_voice;
looped = next_looped;
next_voice = NULL;
next_looped = false;
voice->play();
}
}
else
{
if (! voice->element)
{
if (looped)
voice->play();
else
voice = NULL;
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// MK_VIII::VoicePlayer ///////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View file

@ -30,7 +30,6 @@
#include <simgear/props/props.hxx>
#include <simgear/props/tiedpropertylist.hxx>
#include <simgear/sound/sample_openal.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
using std::vector;
using std::deque;
@ -41,298 +40,13 @@ class SGSampleGroup;
#include <Airports/runways.hxx>
#include <Airports/simple.hxx>
#include <Main/globals.hxx>
#include <Sound/voiceplayer.hxx>
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable: 4355 )
#endif
/////////////////////////////////////////////////////////////////////////////
// FGVoicePlayer /////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class FGVoicePlayer
{
public:
/////////////////////////////////////////////////////////////////////////////
// MK::RawValueMethodsData /////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
template <class C, class VT, class DT>
class RawValueMethodsData : public SGRawValue<VT>
{
public:
typedef VT (C::*getter_t) (DT) const;
typedef void (C::*setter_t) (DT, VT);
RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
: _obj(obj), _data(data), _getter(getter), _setter(setter) {}
virtual VT getValue () const
{
if (_getter)
return (_obj.*_getter)(_data);
else
return SGRawValue<VT>::DefaultValue();
}
virtual bool setValue (VT value)
{
if (_setter)
{
(_obj.*_setter)(_data, value);
return true;
}
else
return false;
}
virtual SGRawValue<VT> *clone () const
{
return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
}
private:
C &_obj;
DT _data;
getter_t _getter;
setter_t _setter;
};
class PropertiesHandler : public simgear::TiedPropertyList
{
public:
template <class T>
inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
{
Tie(node,raw_value);
}
template <class T>
inline void tie (SGPropertyNode *node,
const char *relative_path,
const SGRawValue<T> &raw_value)
{
Tie(node->getNode(relative_path, true),raw_value);
}
PropertiesHandler() {};
void unbind () {Untie();}
};
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class Voice
{
public:
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::Element ////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
class Element
{
public:
bool silence;
virtual inline void play (float volume) {}
virtual inline void stop () {}
virtual bool is_playing () = 0;
virtual inline void set_volume (float volume) {}
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::SampleElement ///////////////////////////
/////////////////////////////////////////////////////////////////////////
class SampleElement : public Element
{
SGSharedPtr<SGSoundSample> _sample;
float _volume;
public:
inline SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0)
: _sample(sample), _volume(volume) { silence = false; }
virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
virtual inline void stop () { if (_sample) _sample->stop(); }
virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::SilenceElement //////////////////////////
/////////////////////////////////////////////////////////////////////////
class SilenceElement : public Element
{
double _duration;
double start_time;
public:
inline SilenceElement (double duration)
: _duration(duration) { silence = true; }
virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice (continued) //////////////////////////////
/////////////////////////////////////////////////////////////////////////
Element *element;
inline Voice (FGVoicePlayer *_player)
: element(NULL), player(_player), volume(1.0) {}
~Voice ();
inline void append (Element *_element) { elements.push_back(_element); }
void play ();
void stop (bool now);
void set_volume (float _volume);
void volume_changed ();
void update ();
private:
FGVoicePlayer *player;
float volume;
vector<Element *> elements;
vector<Element *>::iterator iter;
inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
};
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer (continued) ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
struct
{
float volume;
} conf;
float volume;
Voice *voice;
Voice *next_voice;
bool paused;
string dev_name;
string dir_prefix;
inline FGVoicePlayer (PropertiesHandler* properties_handler, string _dev_name)
: volume(1.0), voice(NULL), next_voice(NULL), paused(false),
dev_name(_dev_name), dir_prefix(""),
speaker(this,properties_handler) {}
~FGVoicePlayer ();
void init ();
void pause();
void resume();
bool is_playing() { return (voice!=NULL);}
enum
{
PLAY_NOW = 1 << 0,
PLAY_LOOPED = 1 << 1
};
void play (Voice *_voice, unsigned int flags = 0);
enum
{
STOP_NOW = 1 << 0
};
void stop (unsigned int flags = 0);
void set_volume (float _volume);
void update ();
void bind (SGPropertyNode *node, const char* default_dir_prefix);
public:
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Speaker //////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class Speaker
{
FGVoicePlayer *player;
PropertiesHandler* properties_handler;
double pitch;
template <class T>
inline void tie (SGPropertyNode *node, const char *name, T *ptr)
{
properties_handler->tie
(node, (string("speaker/") + name).c_str(),
RawValueMethodsData<FGVoicePlayer::Speaker,T,T*>
(*this, ptr,
&FGVoicePlayer::Speaker::get_property,
&FGVoicePlayer::Speaker::set_property));
}
public:
template <class T>
inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
template <class T>
inline T get_property (T *ptr) const { return *ptr; }
float volume;
inline Speaker (FGVoicePlayer *_player,PropertiesHandler* _properties_handler)
: player(_player),
properties_handler(_properties_handler),
pitch(1),
volume(1)
{
}
void bind (SGPropertyNode *node);
void update_configuration ();
};
protected:
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer (continued) ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
SGSharedPtr<SGSampleGroup> _sgr;
Speaker speaker;
map< string, SGSharedPtr<SGSoundSample> > samples;
vector<Voice *> _voices;
bool looped;
bool next_looped;
SGSoundSample *get_sample (const char *name);
inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
template <class T1>
inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
template <class T1, class T2>
inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
template <class T1, class T2, class T3>
inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
template <class T1, class T2, class T3, class T4>
inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
};
///////////////////////////////////////////////////////////////////////////////
// MK_VIII ////////////////////////////////////////////////////////////////////

View file

@ -100,8 +100,6 @@
#include <simgear/sg_inlines.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/misc/sg_path.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/structure/exception.hxx>
@ -115,7 +113,6 @@ using std::string;
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <AIModel/submodel.hxx>
#include "instrument_mgr.hxx"
#include "tcas.hxx"

View file

@ -28,9 +28,8 @@
#include <map>
#include <simgear/props/props.hxx>
#include <simgear/sound/sample_openal.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include "mk_viii.hxx" // FGVoicePlayer only
#include <Sound/voiceplayer.hxx>
using std::vector;
using std::deque;

View file

@ -6,6 +6,7 @@ set(SOURCES
morse.cxx
sample_queue.cxx
voice.cxx
voiceplayer.cxx
)
flightgear_component(Sound "${SOURCES}")

View file

@ -5,6 +5,7 @@ libSound_a_SOURCES = \
fg_fx.cxx fg_fx.hxx \
morse.cxx morse.hxx \
voice.cxx voice.hxx \
sample_queue.cxx sample_queue.hxx
sample_queue.cxx sample_queue.hxx \
voiceplayer.cxx voiceplayer.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

View file

@ -39,8 +39,8 @@ class SGSoundSample;
*
* This modules maintains a queue of 'message' audio files. These
* are played sequentially with no overlap until the queue is finished.
* This second mechanims is useful for things like tutorial messages or
* background atc chatter.
* This second mechanisms is useful for things like tutorial messages or
* background ATC chatter.
*/
class FGSampleQueue : public SGSampleGroup
{

314
src/Sound/voiceplayer.cxx Normal file
View file

@ -0,0 +1,314 @@
// voiceplayer.cxx -- voice/sound sample player
//
// Written by Jean-Yves Lefort, started September 2005.
//
// Copyright (C) 2005, 2006 Jean-Yves Lefort - jylefort@FreeBSD.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
///////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma warning( disable: 4355 )
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <string>
#include <sstream>
#include <simgear/debug/logstream.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/structure/exception.hxx>
using std::string;
#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H
# include <Include/version.h>
#else
# include <Include/no_version.h>
#endif
#include "voiceplayer.hxx"
///////////////////////////////////////////////////////////////////////////////
// constants //////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// helpers ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define ADD_VOICE(Var,Sample,Twice) \
{ make_voice(&Var);append(Var,Sample);\
if (Twice) append(Var,Sample); }
#define test_bits(_bits, _test) (((_bits) & (_test)) != 0)
///////////////////////////////////////////////////////////////////////////////
// FGVoicePlayer //////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void
FGVoicePlayer::Speaker::bind (SGPropertyNode *node)
{
// uses xmlsound property names
tie(node, "volume", &volume);
tie(node, "pitch", &pitch);
}
void
FGVoicePlayer::Speaker::update_configuration ()
{
map< string, SGSharedPtr<SGSoundSample> >::iterator iter;
for (iter = player->samples.begin(); iter != player->samples.end(); iter++)
{
SGSoundSample *sample = (*iter).second;
sample->set_pitch(pitch);
}
if (player->voice)
player->voice->volume_changed();
}
FGVoicePlayer::Voice::~Voice ()
{
for (iter = elements.begin(); iter != elements.end(); iter++)
delete *iter; // we owned the element
elements.clear();
}
void
FGVoicePlayer::Voice::play ()
{
iter = elements.begin();
element = *iter;
element->play(get_volume());
}
void
FGVoicePlayer::Voice::stop (bool now)
{
if (element)
{
if (now || element->silence)
{
element->stop();
element = NULL;
}
else
iter = elements.end() - 1; // stop after the current element finishes
}
}
void
FGVoicePlayer::Voice::set_volume (float _volume)
{
volume = _volume;
volume_changed();
}
void
FGVoicePlayer::Voice::volume_changed ()
{
if (element)
element->set_volume(get_volume());
}
void
FGVoicePlayer::Voice::update ()
{
if (element)
{
if (! element->is_playing())
{
if (++iter == elements.end())
element = NULL;
else
{
element = *iter;
element->play(get_volume());
}
}
}
}
FGVoicePlayer::~FGVoicePlayer ()
{
vector<Voice *>::iterator iter1;
for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++)
delete *iter1;
_voices.clear();
samples.clear();
}
void
FGVoicePlayer::bind (SGPropertyNode *node, const char* default_dir_prefix)
{
dir_prefix = node->getStringValue("voice/file-prefix", default_dir_prefix);
speaker.bind(node);
}
void
FGVoicePlayer::init ()
{
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
speaker.update_configuration();
}
void
FGVoicePlayer::pause()
{
if (paused)
return;
paused = true;
if (voice)
{
voice->stop(true);
}
}
void
FGVoicePlayer::resume()
{
if (!paused)
return;
paused = false;
if (voice)
{
voice->play();
}
}
SGSoundSample *
FGVoicePlayer::get_sample (const char *name)
{
string refname;
refname = dev_name + "/" + dir_prefix + name;
SGSoundSample *sample = _sgr->find(refname);
if (! sample)
{
string filename = dir_prefix + string(name) + ".wav";
try
{
sample = new SGSoundSample(filename.c_str(), SGPath());
}
catch (const sg_exception &e)
{
SG_LOG(SG_INSTR, SG_ALERT, "Error loading sound sample \"" + filename + "\": " + e.getFormattedMessage());
exit(1);
}
_sgr->add(sample, refname);
samples[refname] = sample;
}
return sample;
}
void
FGVoicePlayer::play (Voice *_voice, unsigned int flags)
{
if (!_voice)
return;
if (test_bits(flags, PLAY_NOW) || ! voice ||
(voice->element && voice->element->silence))
{
if (voice)
voice->stop(true);
voice = _voice;
looped = test_bits(flags, PLAY_LOOPED);
next_voice = NULL;
next_looped = false;
if (!paused)
voice->play();
}
else
{
next_voice = _voice;
next_looped = test_bits(flags, PLAY_LOOPED);
}
}
void
FGVoicePlayer::stop (unsigned int flags)
{
if (voice)
{
voice->stop(test_bits(flags, STOP_NOW));
if (voice->element)
looped = false;
else
voice = NULL;
next_voice = NULL;
}
}
void
FGVoicePlayer::set_volume (float _volume)
{
volume = _volume;
if (voice)
voice->volume_changed();
}
void
FGVoicePlayer::update ()
{
if (voice)
{
voice->update();
if (next_voice)
{
if (! voice->element || voice->element->silence)
{
voice = next_voice;
looped = next_looped;
next_voice = NULL;
next_looped = false;
voice->play();
}
}
else
{
if (! voice->element)
{
if (looped)
voice->play();
else
voice = NULL;
}
}
}
}

334
src/Sound/voiceplayer.hxx Normal file
View file

@ -0,0 +1,334 @@
// voiceplayer.hxx -- voice/sound sample player
//
// Written by Jean-Yves Lefort, started September 2005.
//
// Copyright (C) 2005, 2006 Jean-Yves Lefort - jylefort@FreeBSD.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#ifndef __SOUND_VOICEPLAYER_HXX
#define __SOUND_VOICEPLAYER_HXX
#include <assert.h>
#include <vector>
#include <deque>
#include <map>
#include <simgear/props/props.hxx>
#include <simgear/props/tiedpropertylist.hxx>
#include <simgear/sound/sample_openal.hxx>
using std::vector;
using std::deque;
using std::map;
class SGSampleGroup;
#include <Main/globals.hxx>
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable: 4355 )
#endif
/////////////////////////////////////////////////////////////////////////////
// FGVoicePlayer /////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
class FGVoicePlayer
{
public:
/////////////////////////////////////////////////////////////////////////////
// MK::RawValueMethodsData /////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
template <class C, class VT, class DT>
class RawValueMethodsData : public SGRawValue<VT>
{
public:
typedef VT (C::*getter_t) (DT) const;
typedef void (C::*setter_t) (DT, VT);
RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
: _obj(obj), _data(data), _getter(getter), _setter(setter) {}
virtual VT getValue () const
{
if (_getter)
return (_obj.*_getter)(_data);
else
return SGRawValue<VT>::DefaultValue();
}
virtual bool setValue (VT value)
{
if (_setter)
{
(_obj.*_setter)(_data, value);
return true;
}
else
return false;
}
virtual SGRawValue<VT> *clone () const
{
return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
}
private:
C &_obj;
DT _data;
getter_t _getter;
setter_t _setter;
};
class PropertiesHandler : public simgear::TiedPropertyList
{
public:
template <class T>
inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
{
Tie(node,raw_value);
}
template <class T>
inline void tie (SGPropertyNode *node,
const char *relative_path,
const SGRawValue<T> &raw_value)
{
Tie(node->getNode(relative_path, true),raw_value);
}
PropertiesHandler() {};
void unbind () {Untie();}
};
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class Voice
{
public:
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::Element ////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
class Element
{
public:
bool silence;
virtual inline void play (float volume) {}
virtual inline void stop () {}
virtual bool is_playing () = 0;
virtual inline void set_volume (float volume) {}
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::SampleElement ///////////////////////////
/////////////////////////////////////////////////////////////////////////
class SampleElement : public Element
{
SGSharedPtr<SGSoundSample> _sample;
float _volume;
public:
inline SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0)
: _sample(sample), _volume(volume) { silence = false; }
virtual inline void play (float volume) { if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); } }
virtual inline void stop () { if (_sample) _sample->stop(); }
virtual inline bool is_playing () { return _sample ? _sample->is_playing() : false; }
virtual inline void set_volume (float volume) { if (_sample) _sample->set_volume(volume * _volume); }
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice::SilenceElement //////////////////////////
/////////////////////////////////////////////////////////////////////////
class SilenceElement : public Element
{
double _duration;
double start_time;
public:
inline SilenceElement (double duration)
: _duration(duration) { silence = true; }
virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
};
/////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Voice (continued) //////////////////////////////
/////////////////////////////////////////////////////////////////////////
Element *element;
inline Voice (FGVoicePlayer *_player)
: element(NULL), player(_player), volume(1.0) {}
~Voice ();
inline void append (Element *_element) { elements.push_back(_element); }
void play ();
void stop (bool now);
void set_volume (float _volume);
void volume_changed ();
void update ();
private:
FGVoicePlayer *player;
float volume;
vector<Element *> elements;
vector<Element *>::iterator iter;
inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
};
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer (continued) ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
struct
{
float volume;
} conf;
float volume;
Voice *voice;
Voice *next_voice;
bool paused;
string dev_name;
string dir_prefix;
inline FGVoicePlayer (PropertiesHandler* properties_handler, string _dev_name)
: volume(1.0), voice(NULL), next_voice(NULL), paused(false),
dev_name(_dev_name), dir_prefix(""),
speaker(this,properties_handler) {}
~FGVoicePlayer ();
void init ();
void pause();
void resume();
bool is_playing() { return (voice!=NULL);}
enum
{
PLAY_NOW = 1 << 0,
PLAY_LOOPED = 1 << 1
};
void play (Voice *_voice, unsigned int flags = 0);
enum
{
STOP_NOW = 1 << 0
};
void stop (unsigned int flags = 0);
void set_volume (float _volume);
void update ();
void bind (SGPropertyNode *node, const char* default_dir_prefix);
public:
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer::Speaker //////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
class Speaker
{
FGVoicePlayer *player;
PropertiesHandler* properties_handler;
double pitch;
template <class T>
inline void tie (SGPropertyNode *node, const char *name, T *ptr)
{
properties_handler->tie
(node, (string("speaker/") + name).c_str(),
RawValueMethodsData<FGVoicePlayer::Speaker,T,T*>
(*this, ptr,
&FGVoicePlayer::Speaker::get_property,
&FGVoicePlayer::Speaker::set_property));
}
public:
template <class T>
inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
template <class T>
inline T get_property (T *ptr) const { return *ptr; }
float volume;
inline Speaker (FGVoicePlayer *_player,PropertiesHandler* _properties_handler)
: player(_player),
properties_handler(_properties_handler),
pitch(1),
volume(1)
{
}
void bind (SGPropertyNode *node);
void update_configuration ();
};
protected:
///////////////////////////////////////////////////////////////////////////
// FGVoicePlayer (continued) ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
SGSharedPtr<SGSampleGroup> _sgr;
Speaker speaker;
map< string, SGSharedPtr<SGSoundSample> > samples;
vector<Voice *> _voices;
bool looped;
bool next_looped;
SGSoundSample *get_sample (const char *name);
inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
inline void append (Voice *voice, const char *sample_name) { voice->append(new Voice::SampleElement(get_sample(sample_name))); }
inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
template <class T1>
inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
template <class T1, class T2>
inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
template <class T1, class T2, class T3>
inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
template <class T1, class T2, class T3, class T4>
inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
};
#endif // __SOUND_VOICEPLAYER_HXX