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