1 // voiceplayer.hxx -- voice/sound sample player
2 //
3 // Written by Jean-Yves Lefort, started September 2005.
4 //
5 // Copyright (C) 2005, 2006  Jean-Yves Lefort - jylefort@FreeBSD.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
20 
21 
22 #ifndef __SOUND_VOICEPLAYER_HXX
23 #define __SOUND_VOICEPLAYER_HXX
24 
25 #include <assert.h>
26 
27 #include <vector>
28 #include <deque>
29 #include <map>
30 
31 #include <simgear/props/props.hxx>
32 #include <simgear/props/tiedpropertylist.hxx>
33 
34 class SGSampleGroup;
35 class SGSoundSample;
36 
37 #include <Main/globals.hxx>
38 
39 #ifdef _MSC_VER
40 #  pragma warning( push )
41 #  pragma warning( disable: 4355 )
42 #endif
43 
44 /////////////////////////////////////////////////////////////////////////////
45 // FGVoicePlayer /////////////////////////////////////////////////////
46 /////////////////////////////////////////////////////////////////////////////
47 
48 class FGVoicePlayer
49 {
50 public:
51 
52     /////////////////////////////////////////////////////////////////////////////
53     // MK::RawValueMethodsData /////////////////////////////////////////////
54     /////////////////////////////////////////////////////////////////////////////
55 
56     template <class C, class VT, class DT>
57     class RawValueMethodsData : public SGRawValue<VT>
58     {
59     public:
60       typedef VT (C::*getter_t) (DT) const;
61       typedef void (C::*setter_t) (DT, VT);
62 
RawValueMethodsData(C & obj,DT data,getter_t getter=0,setter_t setter=0)63       RawValueMethodsData (C &obj, DT data, getter_t getter = 0, setter_t setter = 0)
64         : _obj(obj), _data(data), _getter(getter), _setter(setter) {}
65 
getValue() const66       virtual VT getValue () const
67       {
68         if (_getter)
69       return (_obj.*_getter)(_data);
70         else
71       return SGRawValue<VT>::DefaultValue();
72       }
setValue(VT value)73       virtual bool setValue (VT value)
74       {
75         if (_setter)
76       {
77         (_obj.*_setter)(_data, value);
78         return true;
79       }
80         else
81       return false;
82       }
clone() const83       virtual SGRawValue<VT> *clone () const
84       {
85         return new RawValueMethodsData<C,VT,DT>(_obj, _data, _getter, _setter);
86       }
87 
88     private:
89       C       &_obj;
90       DT      _data;
91       getter_t    _getter;
92       setter_t    _setter;
93     };
94 
95     class PropertiesHandler : public simgear::TiedPropertyList
96     {
97     public:
98 
99       template <class T>
tie(SGPropertyNode * node,const SGRawValue<T> & raw_value)100       inline void tie (SGPropertyNode *node, const SGRawValue<T> &raw_value)
101       {
102           Tie(node,raw_value);
103       }
104 
105       template <class T>
tie(SGPropertyNode * node,const char * relative_path,const SGRawValue<T> & raw_value)106       inline void tie (SGPropertyNode *node,
107                const char *relative_path,
108                const SGRawValue<T> &raw_value)
109       {
110         Tie(node->getNode(relative_path, true),raw_value);
111       }
112 
PropertiesHandler()113       PropertiesHandler() {};
114 
unbind()115       void unbind () {Untie();}
116     };
117 
118   ///////////////////////////////////////////////////////////////////////////
119   // FGVoicePlayer::Voice ////////////////////////////////////////////
120   ///////////////////////////////////////////////////////////////////////////
121 
122   class Voice
123   {
124   public:
125 
126     /////////////////////////////////////////////////////////////////////////
127     // FGVoicePlayer::Voice::Element ////////////////////////////////////////
128     /////////////////////////////////////////////////////////////////////////
129 
130     class Element
131     {
132     public:
133         bool silence;
134 
~Element()135         virtual ~Element() {}
play(float volume)136         virtual inline void play (float volume) {}
stop()137         virtual inline void stop () {}
138         virtual bool is_playing () = 0;
set_volume(float volume)139         virtual inline void set_volume (float volume) {}
140     };
141 
142     /////////////////////////////////////////////////////////////////////////
143     // FGVoicePlayer::Voice::SampleElement ///////////////////////////
144     /////////////////////////////////////////////////////////////////////////
145 
146     class SampleElement : public Element
147     {
148         SGSharedPtr<SGSoundSample>  _sample;
149         float               _volume;
150 
151     public:
152         SampleElement (SGSharedPtr<SGSoundSample> sample, float volume = 1.0);
153 
154         virtual void play (float volume);
155         virtual void stop ();
156         virtual bool is_playing ();
157         virtual void set_volume (float volume);
158     };
159 
160     /////////////////////////////////////////////////////////////////////////
161     // FGVoicePlayer::Voice::SilenceElement //////////////////////////
162     /////////////////////////////////////////////////////////////////////////
163 
164     class SilenceElement : public Element
165     {
166         double _duration;
167         double start_time;
168 
169     public:
SilenceElement(double duration)170         inline SilenceElement (double duration)
171           : _duration(duration) { silence = true; }
172 
play(float volume)173         virtual inline void play (float volume) { start_time = globals->get_sim_time_sec(); }
is_playing()174         virtual inline bool is_playing () { return globals->get_sim_time_sec() - start_time < _duration; }
175     };
176 
177     /////////////////////////////////////////////////////////////////////////
178     // FGVoicePlayer::Voice (continued) //////////////////////////////
179     /////////////////////////////////////////////////////////////////////////
180 
181     Element *element;
182 
Voice(FGVoicePlayer * _player)183     inline Voice (FGVoicePlayer *_player)
184       : element(NULL), player(_player), volume(1.0) {}
185 
186     virtual ~Voice ();
187 
append(Element * _element)188     inline void append (Element *_element) { elements.push_back(_element); }
189 
190     void play ();
191     void stop (bool now);
192     void set_volume (float _volume);
193     void volume_changed ();
194     void update ();
195 
196   private:
197       FGVoicePlayer *player;
198 
199       float volume;
200 
201       std::vector<Element *>         elements;
202       std::vector<Element *>::iterator   iter;
203 
get_volume() const204       inline float get_volume () const { return player->volume * player->speaker.volume * volume; }
205   };
206 
207   ///////////////////////////////////////////////////////////////////////////
208   // FGVoicePlayer (continued) ///////////////////////////////////////
209   ///////////////////////////////////////////////////////////////////////////
210 
211   struct
212   {
213     float volume;
214   } conf;
215 
216   float volume;
217 
218   Voice *voice;
219   Voice *next_voice;
220   bool paused;
221   std::string dev_name;
222   std::string dir_prefix;
223 
224   FGVoicePlayer (PropertiesHandler* properties_handler, std::string _dev_name);
225 
226   virtual ~FGVoicePlayer ();
227 
228   void init ();
229   void pause();
230   void resume();
is_playing()231   bool is_playing() { return (voice!=NULL);}
232 
233   enum
234   {
235     PLAY_NOW      = 1 << 0,
236     PLAY_LOOPED   = 1 << 1
237   };
238   void play (Voice *_voice, unsigned int flags = 0);
239 
240   enum
241   {
242     STOP_NOW      = 1 << 0
243   };
244   void stop (unsigned int flags = 0);
245 
246   void set_volume (float _volume);
247   void update ();
248 
249   void bind (SGPropertyNode *node, const char* default_dir_prefix);
250 
251 public:
252 
253   ///////////////////////////////////////////////////////////////////////////
254   // FGVoicePlayer::Speaker //////////////////////////////////////////
255   ///////////////////////////////////////////////////////////////////////////
256 
257   class Speaker
258   {
259     FGVoicePlayer *player;
260     PropertiesHandler* properties_handler;
261 
262     double    pitch;
263 
264     template <class T>
tie(SGPropertyNode * node,const char * name,T * ptr)265     inline void tie (SGPropertyNode *node, const char *name, T *ptr)
266     {
267     properties_handler->tie
268       (node, (std::string("speaker/") + name).c_str(),
269      RawValueMethodsData<FGVoicePlayer::Speaker,T,T*>
270      (*this, ptr,
271       &FGVoicePlayer::Speaker::get_property,
272       &FGVoicePlayer::Speaker::set_property));
273     }
274 
275   public:
276     template <class T>
set_property(T * ptr,T value)277     inline void set_property (T *ptr, T value) { *ptr = value; update_configuration(); }
278 
279     template <class T>
get_property(T * ptr) const280     inline T get_property (T *ptr) const { return *ptr; }
281 
282     float volume;
283 
Speaker(FGVoicePlayer * _player,PropertiesHandler * _properties_handler)284     inline Speaker (FGVoicePlayer *_player,PropertiesHandler* _properties_handler)
285   : player(_player),
286     properties_handler(_properties_handler),
287     pitch(1),
288     volume(1)
289     {
290     }
291 
292     void bind (SGPropertyNode *node);
293     void update_configuration ();
294   };
295 
296 protected:
297   ///////////////////////////////////////////////////////////////////////////
298   // FGVoicePlayer (continued) ///////////////////////////////////////
299   ///////////////////////////////////////////////////////////////////////////
300 
301   SGSharedPtr<SGSampleGroup> _sgr;
302   Speaker speaker;
303 
304   std::map< std::string, SGSharedPtr<SGSoundSample> >   samples;
305   std::vector<Voice *>         _voices;
306 
307   bool looped;
308   bool next_looped;
309 
310   SGSoundSample *get_sample (const char *name);
311 
append(Voice * voice,Voice::Element * element)312   inline void append (Voice *voice, Voice::Element *element) { voice->append(element); }
313   void append (Voice *voice, const char *sample_name);
append(Voice * voice,double silence)314   inline void append (Voice *voice, double silence) { voice->append(new Voice::SilenceElement(silence)); }
315 
make_voice(Voice ** voice)316   inline void make_voice (Voice **voice) { *voice = new Voice(this); _voices.push_back(*voice); }
317 
318   template <class T1>
make_voice(Voice ** voice,T1 e1)319   inline void make_voice (Voice **voice, T1 e1) { make_voice(voice); append(*voice, e1); }
320   template <class T1, class T2>
make_voice(Voice ** voice,T1 e1,T2 e2)321   inline void make_voice (Voice **voice, T1 e1, T2 e2) { make_voice(voice, e1); append(*voice, e2); }
322   template <class T1, class T2, class T3>
make_voice(Voice ** voice,T1 e1,T2 e2,T3 e3)323   inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3) { make_voice(voice, e1, e2); append(*voice, e3); }
324   template <class T1, class T2, class T3, class T4>
make_voice(Voice ** voice,T1 e1,T2 e2,T3 e3,T4 e4)325   inline void make_voice (Voice **voice, T1 e1, T2 e2, T3 e3, T4 e4) { make_voice(voice, e1, e2, e3); append(*voice, e4); }
326 };
327 
328 #endif // __SOUND_VOICEPLAYER_HXX
329