FlightGear next
voiceplayer.cxx
Go to the documentation of this file.
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//
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 <cmath>
37
38#include <string>
39#include <sstream>
40
41#include <simgear/debug/logstream.hxx>
42#include <simgear/sound/soundmgr.hxx>
43#include <simgear/sound/sample_group.hxx>
44#include <simgear/structure/exception.hxx>
45
46using std::string;
47using std::map;
48using std::vector;
49
51// constants //////////////////////////////////////////////////////////////////
53
54
56// helpers ////////////////////////////////////////////////////////////////////
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
65// FGVoicePlayer::Voice::SampleElement ///////////////////////////
67
68FGVoicePlayer::Voice::SampleElement::SampleElement (SGSharedPtr<SGSoundSample> sample, float volume)
69: _sample(sample), _volume(volume)
70{
71 silence = false;
72}
73
75{
76 if (_sample && (volume > 0.05)) { set_volume(volume); _sample->play_once(); }
77}
78
80{
81 if (_sample) _sample->stop();
82}
83
85{
86 return _sample ? _sample->is_playing() : false;
87}
88
90{
91 if (_sample) _sample->set_volume(volume * _volume);
92}
93
95// FGVoicePlayer //////////////////////////////////////////////////////////////
97
98void
99FGVoicePlayer::Speaker::bind (SGPropertyNode *node)
100{
101 // uses xmlsound property names
102 tie(node, "volume", &volume);
103 tie(node, "pitch", &pitch);
104}
105
106void
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
122{
123 for (iter = elements.begin(); iter != elements.end(); iter++)
124 delete *iter; // we owned the element
125 elements.clear();
126}
127
128void
130{
131 iter = elements.begin();
132 element = *iter;
133
134 element->play(get_volume());
135}
136
137void
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
152void
154{
155 volume = _volume;
157}
158
159void
161{
162 if (element)
163 element->set_volume(get_volume());
164}
165
166void
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
184FGVoicePlayer::FGVoicePlayer (PropertiesHandler* properties_handler, string _dev_name)
185: volume(1.0), voice(NULL), next_voice(NULL), paused(false),
186dev_name(_dev_name), dir_prefix(""),
187speaker(this,properties_handler)
188{
189 _sgr = NULL;
190}
191
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
201void
202FGVoicePlayer::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
208void
210{
211 auto smgr = globals->get_subsystem<SGSoundMgr>();
212 _sgr = smgr->find("avionics", true);
213 _sgr->tie_to_listener();
214 speaker.update_configuration();
215}
216
217void
219{
220 if (paused)
221 return;
222
223 paused = true;
224 if (voice)
225 {
226 voice->stop(true);
227 }
228}
229
230void
232{
233 if (!paused)
234 return;
235 paused = false;
236 if (voice)
237 {
238 voice->play();
239 }
240}
241
242SGSoundSample *
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 sample = new SGSoundSample(filename.c_str(), SGPath());
253
254 _sgr->add(sample, refname);
255 samples[refname] = sample;
256 }
257
258 return sample;
259}
260
261void
262FGVoicePlayer::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;
285 }
286}
287
288void
289FGVoicePlayer::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
302void
304{
305 volume = _volume;
306 if (voice)
307 voice->volume_changed();
308}
309
310void
312{
313 if (voice)
314 {
315 voice->update();
316
317 if (next_voice)
318 {
319 if (! voice->element || voice->element->silence)
320 {
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}
342
343void
344FGVoicePlayer::append (Voice *voice, const char *sample_name)
345{
346 voice->append(new Voice::SampleElement(get_sample(sample_name)));
347}
348
void bind(SGPropertyNode *node)
SampleElement(SGSharedPtr< SGSoundSample > sample, float volume=1.0)
virtual void play(float volume)
virtual void set_volume(float volume)
void set_volume(float _volume)
void stop(bool now)
virtual ~FGVoicePlayer()
SGSharedPtr< SGSampleGroup > _sgr
void set_volume(float _volume)
void bind(SGPropertyNode *node, const char *default_dir_prefix)
SGSoundSample * get_sample(const char *name)
void append(Voice *voice, Voice::Element *element)
std::string dev_name
void play(Voice *_voice, unsigned int flags=0)
std::map< std::string, SGSharedPtr< SGSoundSample > > samples
std::vector< Voice * > _voices
FGVoicePlayer(PropertiesHandler *properties_handler, std::string _dev_name)
std::string dir_prefix
void stop(unsigned int flags=0)
const char * name
FGGlobals * globals
Definition globals.cxx:142
#define test_bits(_bits, _test)
Definition mk_viii.cxx:104