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