]> git.mxchange.org Git - flightgear.git/blob - src/Sound/voiceplayer.cxx
Make FGVoicePlayer.hxx not require sample_openal.hxx
[flightgear.git] / src / Sound / voiceplayer.cxx
1 // voiceplayer.cxx -- 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
23 #ifdef _MSC_VER
24 #  pragma warning( disable: 4355 )
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31 #include "voiceplayer.hxx"
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <math.h>
37
38 #include <string>
39 #include <sstream>
40
41 #include <simgear/debug/logstream.hxx>
42 #include <simgear/sound/soundmgr_openal.hxx>
43 #include <simgear/sound/sample_group.hxx>
44 #include <simgear/structure/exception.hxx>
45
46 using std::string;
47 using std::map;
48 using std::vector;
49
50 ///////////////////////////////////////////////////////////////////////////////
51 // constants //////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////////////////
53
54
55 ///////////////////////////////////////////////////////////////////////////////
56 // helpers ////////////////////////////////////////////////////////////////////
57 ///////////////////////////////////////////////////////////////////////////////
58 #define ADD_VOICE(Var,Sample,Twice) \
59     { make_voice(&Var);append(Var,Sample);\
60       if (Twice) append(Var,Sample); }
61
62 #define test_bits(_bits, _test) (((_bits) & (_test)) != 0)
63
64 /////////////////////////////////////////////////////////////////////////
65 // FGVoicePlayer::Voice::SampleElement ///////////////////////////
66 /////////////////////////////////////////////////////////////////////////
67
68 void FGVoicePlayer::Voice::SampleElement::play (float volume)
69 {
70   if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); }
71 }
72
73 void FGVoicePlayer::Voice::SampleElement::stop ()
74 {
75   if (_sample) _sample->stop();
76 }
77
78 bool FGVoicePlayer::Voice::SampleElement::is_playing ()
79 {
80   return _sample ? _sample->is_playing() : false;
81 }
82
83 void FGVoicePlayer::Voice::SampleElement::set_volume (float volume)
84 {
85   if (_sample) _sample->set_volume(volume * _volume);
86 }
87
88 ///////////////////////////////////////////////////////////////////////////////
89 // FGVoicePlayer //////////////////////////////////////////////////////////////
90 ///////////////////////////////////////////////////////////////////////////////
91
92 void
93 FGVoicePlayer::Speaker::bind (SGPropertyNode *node)
94 {
95     // uses xmlsound property names
96     tie(node, "volume", &volume);
97     tie(node, "pitch", &pitch);
98 }
99
100 void
101 FGVoicePlayer::Speaker::update_configuration ()
102 {
103     map< string, SGSharedPtr<SGSoundSample> >::iterator iter;
104     for (iter = player->samples.begin(); iter != player->samples.end(); iter++)
105     {
106         SGSoundSample *sample = (*iter).second;
107
108         sample->set_pitch(pitch);
109     }
110
111     if (player->voice)
112         player->voice->volume_changed();
113 }
114
115 FGVoicePlayer::Voice::~Voice ()
116 {
117     for (iter = elements.begin(); iter != elements.end(); iter++)
118         delete *iter;       // we owned the element
119     elements.clear();
120 }
121
122 void
123 FGVoicePlayer::Voice::play ()
124 {
125     iter = elements.begin();
126     element = *iter;
127
128     element->play(get_volume());
129 }
130
131 void
132 FGVoicePlayer::Voice::stop (bool now)
133 {
134     if (element)
135     {
136         if (now || element->silence)
137         {
138             element->stop();
139             element = NULL;
140         }
141         else
142             iter = elements.end() - 1; // stop after the current element finishes
143     }
144 }
145
146 void
147 FGVoicePlayer::Voice::set_volume (float _volume)
148 {
149     volume = _volume;
150     volume_changed();
151 }
152
153 void
154 FGVoicePlayer::Voice::volume_changed ()
155 {
156     if (element)
157         element->set_volume(get_volume());
158 }
159
160 void
161 FGVoicePlayer::Voice::update ()
162 {
163     if (element)
164     {
165         if (! element->is_playing())
166         {
167             if (++iter == elements.end())
168                 element = NULL;
169             else
170             {
171                 element = *iter;
172                 element->play(get_volume());
173             }
174         }
175     }
176 }
177
178 FGVoicePlayer::FGVoicePlayer (PropertiesHandler* properties_handler, string _dev_name)
179 : volume(1.0), voice(NULL), next_voice(NULL), paused(false),
180 dev_name(_dev_name), dir_prefix(""),
181 speaker(this,properties_handler)
182 {}
183
184 FGVoicePlayer::~FGVoicePlayer ()
185 {
186     vector<Voice *>::iterator iter1;
187     for (iter1 = _voices.begin(); iter1 != _voices.end(); iter1++)
188         delete *iter1;
189     _voices.clear();
190     samples.clear();
191 }
192
193 void
194 FGVoicePlayer::bind (SGPropertyNode *node, const char* default_dir_prefix)
195 {
196     dir_prefix = node->getStringValue("voice/file-prefix", default_dir_prefix);
197     speaker.bind(node);
198 }
199
200 void
201 FGVoicePlayer::init ()
202 {
203     SGSoundMgr *smgr = globals->get_soundmgr();
204     _sgr = smgr->find("avionics", true);
205     _sgr->tie_to_listener();
206     speaker.update_configuration();
207 }
208
209 void
210 FGVoicePlayer::pause()
211 {
212     if (paused)
213         return;
214
215     paused = true;
216     if (voice)
217     {
218         voice->stop(true);
219     }
220 }
221
222 void
223 FGVoicePlayer::resume()
224 {
225     if (!paused)
226         return;
227     paused = false;
228     if (voice)
229     {
230         voice->play();
231     }
232 }
233
234 SGSoundSample *
235 FGVoicePlayer::get_sample (const char *name)
236 {
237     string refname;
238     refname = dev_name + "/" + dir_prefix + name;
239
240     SGSoundSample *sample = _sgr->find(refname);
241     if (! sample)
242     {
243         string filename = dir_prefix + string(name) + ".wav";
244         try
245         {
246             sample = new SGSoundSample(filename.c_str(), SGPath());
247         }
248         catch (const sg_exception &e)
249         {
250             SG_LOG(SG_SOUND, SG_ALERT, "Error loading sound sample \"" + filename + "\": " + e.getFormattedMessage());
251             exit(1);
252         }
253
254         _sgr->add(sample, refname);
255         samples[refname] = sample;
256     }
257
258     return sample;
259 }
260
261 void
262 FGVoicePlayer::play (Voice *_voice, unsigned int flags)
263 {
264     if (!_voice)
265         return;
266     if (test_bits(flags, PLAY_NOW) || ! voice ||
267             (voice->element && voice->element->silence))
268     {
269         if (voice)
270             voice->stop(true);
271
272         voice = _voice;
273         looped = test_bits(flags, PLAY_LOOPED);
274
275         next_voice = NULL;
276         next_looped = false;
277
278         if (!paused)
279             voice->play();
280     }
281     else
282     {
283         next_voice = _voice;
284         next_looped = test_bits(flags, PLAY_LOOPED);
285     }
286 }
287
288 void
289 FGVoicePlayer::stop (unsigned int flags)
290 {
291     if (voice)
292     {
293         voice->stop(test_bits(flags, STOP_NOW));
294         if (voice->element)
295             looped = false;
296         else
297             voice = NULL;
298         next_voice = NULL;
299     }
300 }
301
302 void
303 FGVoicePlayer::set_volume (float _volume)
304 {
305     volume = _volume;
306     if (voice)
307         voice->volume_changed();
308 }
309
310 void
311 FGVoicePlayer::update ()
312 {
313     if (voice)
314     {
315         voice->update();
316
317         if (next_voice)
318         {
319             if (! voice->element || voice->element->silence)
320             {
321                 voice = next_voice;
322                 looped = next_looped;
323
324                 next_voice = NULL;
325                 next_looped = false;
326
327                 voice->play();
328             }
329         }
330         else
331         {
332             if (! voice->element)
333             {
334                 if (looped)
335                     voice->play();
336                 else
337                     voice = NULL;
338             }
339         }
340     }
341 }