]> git.mxchange.org Git - flightgear.git/blob - src/Sound/fg_fx.cxx
c7820b94b05a4054fabe0d522a0ff35017e349cb
[flightgear.git] / src / Sound / fg_fx.cxx
1 // fgfx.cxx -- Sound effect management class implementation
2 //
3 // Started by David Megginson, October 2001
4 // (Reuses some code from main.cxx, probably by Curtis Olson)
5 //
6 // Copyright (C) 2001  Curtis L. Olson - curt@flightgear.org
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23
24 #include "fg_fx.hxx"
25 #include <Main/fg_props.hxx>
26
27 // FIXME: remove direct dependencies
28 #include <FDM/flight.hxx>
29
30 static const char * engine_names[FGFX::MAX_ENGINES] = {
31   "engine0",
32   "engine1"
33 };
34
35 static const char * crank_names[FGFX::MAX_ENGINES] = {
36   "crank0",
37   "crank1"
38 };
39
40
41 FGFX::FGFX ()
42   : _old_flap_position(0),
43     _old_gear_position(0),
44     _wind(0),
45     _stall(0),
46     _rumble(0),
47     _flaps(0),
48     _gear_up(0),
49     _gear_dn(0),
50     _squeal(0),
51     _click(0),
52     _stall_warning_prop(0),
53     _flaps_prop(0),
54     _gear_prop(0)
55 {
56   for (int i = 0; i < MAX_ENGINES; i++) {
57     _engine[i] = 0;
58     _crank[i] = 0;
59     _engine_running_prop[i] = 0;
60     _engine_cranking_prop[i] = 0;
61   }
62 }
63
64 FGFX::~FGFX ()
65 {
66                                 // FIXME: is this right, or does the
67                                 // sound manager assume pointer ownership?
68   for (int i = 0; i < MAX_ENGINES; i++) {
69     delete _engine[i];
70     delete _crank[i];
71   }
72   delete _wind;
73   delete _stall;
74   delete _rumble;
75
76   delete _flaps;
77   delete _gear_up;
78   delete _gear_dn;
79   delete _squeal;
80   delete _click;
81 }
82
83
84 void
85 FGFX::init ()
86 {
87   FGSoundMgr * mgr = globals->get_soundmgr();
88
89   //
90   // Create and add engine-related sounds.
91   //
92   for (int i = 0; i < MAX_ENGINES; i++) {
93                                 // Engine
94     _engine[i] =
95       new FGSimpleSound(fgGetString("/sim/sounds/engine/path",
96                                     "Sounds/wasp.wav"));
97     _engine[i]->set_volume(fgGetFloat("/sim/sounds/engine/volume", 1.0));
98     _engine[i]->set_pitch(fgGetFloat("/sim/sounds/engine/pitch", 1.0));
99     mgr->add(_engine[i], engine_names[i]);
100
101                                 // Starter
102     _crank[i] = new FGSimpleSound(fgGetString("/sim/sounds/cranking/path",
103                                               "Sounds/cranking.wav"));
104     _crank[i]->set_volume(fgGetFloat("/sim/sounds/cranking/volume", 0.175));
105     _crank[i]->set_pitch(fgGetFloat("/sim/sounds/cranking/pitch", 1.25));
106     mgr->add(_crank[i], crank_names[i]);
107   }
108
109
110   //
111   // Create and add the wind noise.
112   //
113   _wind = new FGSimpleSound(fgGetString("/sim/sounds/wind/path",
114                                         "Sounds/wind.wav"));
115   _wind->set_volume(fgGetFloat("/sim/sounds/wind/volume", 1.0));
116   _wind->set_pitch(fgGetFloat("/sim/sounds/wind/pitch", 1.0));
117   mgr->add(_wind, "wind");
118
119
120   //
121   // Create and add the stall noise.
122   //
123   _stall = new FGSimpleSound(fgGetString("/sim/sounds/stall/path",
124                                          "Sounds/stall.wav"));
125   _stall->set_volume(fgGetFloat("/sim/sounds/stall/volume", 1.0));
126   _stall->set_pitch(fgGetFloat("/sim/sounds/stall/pitch", 1.0));
127   mgr->add(_stall, "stall");
128
129   //
130   // Create and add the rumble noise.
131   //
132   _rumble = new FGSimpleSound(fgGetString("/sim/sounds/rumble/path",
133                                           "Sounds/rumble.wav"));
134   _rumble->set_volume(fgGetFloat("/sim/sounds/rumble/volume", 1.0));
135   _rumble->set_pitch(fgGetFloat("/sim/sounds/rumble/pitch", 1.0));
136   mgr->add(_rumble, "rumble");
137
138
139   //
140   // Create and add the flaps noise
141   //
142   _flaps = new FGSimpleSound(fgGetString("/sim/sounds/flaps/path",
143                                          "Sounds/flaps.wav"));
144   _flaps->set_volume(fgGetFloat("/sim/sounds/flaps/volume", 0.5));
145   _flaps->set_pitch(fgGetFloat("/sim/sounds/flaps/pitch", 1.0));
146   mgr->add(_flaps, "flaps");
147
148   //
149   // Create and add the gear noises.
150   //
151   _gear_up = new FGSimpleSound(fgGetString("/sim/sounds/gear-up/path",
152                                            "Sounds/gear-up.wav"));
153   _gear_dn = new FGSimpleSound(fgGetString("/sim/sounds/gear-down/path",
154                                            "Sounds/gear-dn.wav"));
155   _gear_up->set_volume(fgGetFloat("/sim/sounds/gear-up/volume", 1.0));
156   _gear_dn->set_volume(fgGetFloat("/sim/sounds/gear-down/volume", 1.0));
157   _gear_up->set_pitch(fgGetFloat("/sim/sounds/gear-up/pitch", 1.0));
158   _gear_dn->set_pitch(fgGetFloat("/sim/sounds/gear-down/pitch", 1.0));
159   mgr->add(_gear_up, "gear-up");
160   mgr->add(_gear_dn, "gear-down");
161
162   //
163   // Create and add the squeal noise.
164   //
165   _squeal = new FGSimpleSound(fgGetString("/sim/sounds/squeal/path",
166                                           "Sounds/squeal.wav"));
167   _squeal->set_volume(fgGetFloat("/sim/sounds/squeal/volume", 1.0));
168   _squeal->set_pitch(fgGetFloat("/sim/sounds/squeal/pitch", 1.0));
169   mgr->add(_squeal, "squeal");
170
171   //
172   // Create and add the click noise.
173   _click = new FGSimpleSound(fgGetString("/sim/sounds/click/path",
174                                          "Sounds/click.wav"));
175   _flaps->set_volume(fgGetFloat("/sim/sounds/click/volume", 1.0));
176   _flaps->set_pitch(fgGetFloat("/sim/sounds/click/pitch", 1.0));
177   mgr->add(_click, "click");
178
179
180   ////////////////////////////////////////////////////////////////////
181   // Grab some properties.
182   ////////////////////////////////////////////////////////////////////
183
184   for (int i = 0; i < MAX_ENGINES; i++) {
185     char buf[100];
186     sprintf(buf, "/engines/engine[%d]/running", i);
187     _engine_running_prop[i] = fgGetNode(buf, true);
188     sprintf(buf, "/engines/engine[%d]/cranking", i);
189     _engine_cranking_prop[i] = fgGetNode(buf, true);
190   }
191   _stall_warning_prop = fgGetNode("/sim/aero/alarms/stall-warning", true);
192   _vc_prop = fgGetNode("/velocities/airspeed-kt", true);
193   _flaps_prop = fgGetNode("/controls/flaps", true);
194   _gear_prop = fgGetNode("/controls/gear-down", true);
195 }
196
197 void
198 FGFX::bind ()
199 {
200 }
201
202 void
203 FGFX::unbind ()
204 {
205 }
206
207 void
208 FGFX::update ()
209 {
210   FGSoundMgr * mgr = globals->get_soundmgr();
211
212
213   ////////////////////////////////////////////////////////////////////
214   // Update the engine sound.
215   ////////////////////////////////////////////////////////////////////
216   
217   for (int i = 0; i < MAX_ENGINES; i++) {
218
219     if (cur_fdm_state->get_num_engines() > 0 &&
220         _engine_running_prop[i]->getBoolValue()) {
221           // pitch corresponds to rpm
222           // volume corresponds to manifold pressure
223
224       double rpm_factor;
225       if ( cur_fdm_state->get_num_engines() > 0 )
226         rpm_factor = cur_fdm_state->get_engine(i)->get_RPM() / 2500.0;
227       else
228         rpm_factor = 1.0;
229
230       double pitch = 0.3 + rpm_factor * 3.0;
231
232       // don't run at absurdly slow rates -- not realistic
233       // and sounds bad to boot.  :-)
234       if (pitch < 0.7)
235         pitch = 0.7;
236       if (pitch > 5.0)
237         pitch = 5.0;
238
239       double mp_factor;
240       if ( cur_fdm_state->get_num_engines() > 0 )
241         mp_factor =
242           cur_fdm_state->get_engine(i)->get_Manifold_Pressure() / 100;
243       else
244         mp_factor = 0.3;
245
246       double volume = 0.15 + mp_factor / 2.0;
247
248       if (volume < 0.15)
249         volume = 0.15;
250       if (volume > 0.5)
251         volume = 0.5;
252
253       _engine[i]->set_pitch( pitch );
254       _engine[i]->set_volume( volume );
255       set_playing(engine_names[i], true);
256     } else {
257       set_playing(engine_names[i], false);
258     }
259
260                                 // FIXME
261     set_playing(crank_names[i], _engine_cranking_prop[i]->getBoolValue());
262   }
263
264
265   ////////////////////////////////////////////////////////////////////
266   // Update the wind noise.
267   ////////////////////////////////////////////////////////////////////
268
269   float rel_wind = cur_fdm_state->get_V_rel_wind(); // FPS
270   float airspeed_kt = cur_fdm_state->get_V_equiv_kts();
271   if (rel_wind > 60.0) {        // a little off 30kt
272     // float volume = rel_wind/600.0;   // FIXME!!!
273     float volume = rel_wind/937.0;      // FIXME!!!
274     double pitch = 1.0+(airspeed_kt/113.0);
275     _wind->set_volume(volume);
276     _wind->set_pitch(pitch);
277     set_playing("wind", true);
278   } else {
279     set_playing("wind", false);
280   }
281
282
283   ////////////////////////////////////////////////////////////////////
284   // Update the stall horn.
285   ////////////////////////////////////////////////////////////////////
286
287   double stall = _stall_warning_prop->getDoubleValue();
288   double vc = _vc_prop->getDoubleValue();
289   if (stall > 0.0 && vc > 30.0) {
290     _stall->set_volume(stall);
291     set_playing("stall", true);
292   } else {
293     set_playing("stall", false);
294   }
295
296
297   ////////////////////////////////////////////////////////////////////
298   // Update the rumble.
299   ////////////////////////////////////////////////////////////////////
300
301   float totalGear = min(cur_fdm_state->get_num_gear(), int(MAX_GEAR));
302   float gearOnGround = 0;
303
304
305                                 // Calculate whether a squeal is
306                                 // required, and set the volume.
307                                 // Currently, the squeal volume is the
308                                 // current local down velocity in feet
309                                 // per second divided by 10.0, and
310                                 // will not be played if under 0.1.
311
312                                 // FIXME: take rotational velocities
313                                 // into account as well.
314   for (int i = 0; i < totalGear; i++) {
315     if (cur_fdm_state->get_gear_unit(i)->GetWoW()) {
316       gearOnGround++;
317       if (!_gear_on_ground[i]) {
318         // 3 parts horizontal velocity + 1 part vertical velocity
319         double squeal_volume = 0.75 * cur_fdm_state->get_V_equiv_kts() / 90.0 +
320             0.25 * cur_fdm_state->get_V_down() / 5.0;
321         if (squeal_volume > 0.1) {
322           _squeal->set_volume(squeal_volume);
323           _squeal->set_pitch(1.25);
324           mgr->play_once("squeal");
325         }
326         _gear_on_ground[i] = true;
327       }
328     } else {
329       _gear_on_ground[i] = false;
330     }
331   }
332
333                                 // Now, if any of the gear is in
334                                 // contact with the ground play the
335                                 // rumble sound.  The volume is the
336                                 // absolute velocity in knots divided
337                                 // by 120.0.  No rumble will be played
338                                 // if the velocity is under 6kt.
339   double speed = cur_fdm_state->get_V_equiv_kts();
340   if (gearOnGround > 0 && speed >= 6.0) {
341     double volume = 2.0 * (gearOnGround/totalGear) * (speed/60.0);
342     _rumble->set_volume(volume);
343     set_playing("rumble", true);
344   } else {
345     set_playing("rumble", false);
346   }
347
348
349   ////////////////////////////////////////////////////////////////////
350   // Check for flap movement.
351   ////////////////////////////////////////////////////////////////////
352
353   double flap_position = _flaps_prop->getDoubleValue();
354   if (fabs(flap_position - _old_flap_position) > 0.1) {
355     mgr->play_once("flaps");
356     _old_flap_position = flap_position;
357   }
358
359
360   ////////////////////////////////////////////////////////////////////
361   // Check for gear movement.
362   ////////////////////////////////////////////////////////////////////
363   
364   double gear_position = _gear_prop->getDoubleValue();
365   if (gear_position != _old_gear_position) {
366     if (gear_position < _old_gear_position) {
367       mgr->play_once("gear-up");
368     } else {
369       mgr->play_once("gear-down");
370     }
371     _old_gear_position = gear_position;
372   }
373
374   // TODO: click
375
376 }
377
378
379 void
380 FGFX::set_playing (const char * soundName, bool state)
381 {
382   FGSoundMgr * mgr = globals->get_soundmgr();
383   bool playing = mgr->is_playing(soundName);
384   if (state && !playing)
385     mgr->play_looped(soundName);
386   else if (!state && playing)
387     mgr->stop(soundName);
388 }
389
390 // end of fg_fx.cxx