1
0
Fork 0
flightgear/src/Sound/fg_fx.cxx
david aabdd355f0 Modified FGSubsystem::update() to take an int parameter for delta time
(i.e. multiloop).  Most subsystems currently ignore the parameter, but
eventually, it will allow all subsystems to update by time rather than
by framerate.
2001-12-22 17:33:27 +00:00

425 lines
12 KiB
C++

// fgfx.cxx -- Sound effect management class implementation
//
// Started by David Megginson, October 2001
// (Reuses some code from main.cxx, probably by Curtis Olson)
//
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#include <FDM/flight.hxx> // FIXME: remove direct dependencies
#include <Main/fg_props.hxx>
#include "fg_fx.hxx"
static const char * engine_names[FGFX::MAX_ENGINES] = {
"engine0",
"engine1"
};
static const char * crank_names[FGFX::MAX_ENGINES] = {
"crank0",
"crank1"
};
FGFX::FGFX ()
: _old_flap_position(0),
_old_gear_position(0),
_wind(0),
_stall(0),
_rumble(0),
_flaps(0),
_gear_up(0),
_gear_dn(0),
_squeal(0),
_click(0),
_stall_warning_prop(0),
_flaps_prop(0),
_gear_prop(0)
{
for (int i = 0; i < MAX_ENGINES; i++) {
_engine[i] = 0;
_crank[i] = 0;
_engine_running_prop[i] = 0;
_engine_cranking_prop[i] = 0;
}
}
FGFX::~FGFX ()
{
// FIXME: is this right, or does the
// sound manager assume pointer ownership?
for (int i = 0; i < MAX_ENGINES; i++) {
delete _engine[i];
delete _crank[i];
}
delete _wind;
delete _stall;
delete _rumble;
delete _flaps;
delete _gear_up;
delete _gear_dn;
delete _squeal;
delete _click;
}
void
FGFX::init ()
{
FGSoundMgr * mgr = globals->get_soundmgr();
int i;
//
// Create and add engine-related sounds.
//
for (i = 0; i < MAX_ENGINES; i++) {
// Engine
_engine[i] =
new FGSimpleSound(fgGetString("/sim/sounds/engine/path",
"Sounds/wasp.wav"));
_engine[i]->set_volume(fgGetFloat("/sim/sounds/engine/volume", 1.0));
_engine[i]->set_pitch(fgGetFloat("/sim/sounds/engine/pitch", 1.0));
mgr->add(_engine[i], engine_names[i]);
// Starter
_crank[i] = new FGSimpleSound(fgGetString("/sim/sounds/cranking/path",
"Sounds/cranking.wav"));
_crank[i]->set_volume(fgGetFloat("/sim/sounds/cranking/volume", 0.175));
_crank[i]->set_pitch(fgGetFloat("/sim/sounds/cranking/pitch", 1.25));
mgr->add(_crank[i], crank_names[i]);
}
//
// Create and add the wind noise.
//
_wind = new FGSimpleSound(fgGetString("/sim/sounds/wind/path",
"Sounds/wind.wav"));
_wind->set_volume(fgGetFloat("/sim/sounds/wind/volume", 1.0));
_wind->set_pitch(fgGetFloat("/sim/sounds/wind/pitch", 1.0));
mgr->add(_wind, "wind");
//
// Create and add the stall noise.
//
_stall = new FGSimpleSound(fgGetString("/sim/sounds/stall/path",
"Sounds/stall.wav"));
_stall->set_volume(fgGetFloat("/sim/sounds/stall/volume", 1.0));
_stall->set_pitch(fgGetFloat("/sim/sounds/stall/pitch", 1.0));
mgr->add(_stall, "stall");
//
// Create and add the rumble noise.
//
_rumble = new FGSimpleSound(fgGetString("/sim/sounds/rumble/path",
"Sounds/rumble.wav"));
_rumble->set_volume(fgGetFloat("/sim/sounds/rumble/volume", 1.0));
_rumble->set_pitch(fgGetFloat("/sim/sounds/rumble/pitch", 1.0));
mgr->add(_rumble, "rumble");
//
// Create and add the flaps noise
//
_flaps = new FGSimpleSound(fgGetString("/sim/sounds/flaps/path",
"Sounds/flaps.wav"));
_flaps->set_volume(fgGetFloat("/sim/sounds/flaps/volume", 0.5));
_flaps->set_pitch(fgGetFloat("/sim/sounds/flaps/pitch", 1.0));
mgr->add(_flaps, "flaps");
//
// Create and add the gear noises.
//
_gear_up = new FGSimpleSound(fgGetString("/sim/sounds/gear-up/path",
"Sounds/gear-up.wav"));
_gear_dn = new FGSimpleSound(fgGetString("/sim/sounds/gear-down/path",
"Sounds/gear-dn.wav"));
_gear_up->set_volume(fgGetFloat("/sim/sounds/gear-up/volume", 1.0));
_gear_dn->set_volume(fgGetFloat("/sim/sounds/gear-down/volume", 1.0));
_gear_up->set_pitch(fgGetFloat("/sim/sounds/gear-up/pitch", 1.0));
_gear_dn->set_pitch(fgGetFloat("/sim/sounds/gear-down/pitch", 1.0));
mgr->add(_gear_up, "gear-up");
mgr->add(_gear_dn, "gear-down");
//
// Create and add the squeal noise.
//
_squeal = new FGSimpleSound(fgGetString("/sim/sounds/squeal/path",
"Sounds/squeal.wav"));
_squeal->set_volume(fgGetFloat("/sim/sounds/squeal/volume", 1.0));
_squeal->set_pitch(fgGetFloat("/sim/sounds/squeal/pitch", 1.0));
mgr->add(_squeal, "squeal");
//
// Simplistic wheel spin model for audio effect purposes only. We
// don't want to play a full squeel, if the wheel has only departed
// from the ground for a split second.
//
for (i = 0; i < MAX_GEAR; i++) {
_wheel_spin[i] = 0.0;
}
//
// Create and add the click noise.
_click = new FGSimpleSound(fgGetString("/sim/sounds/click/path",
"Sounds/click.wav"));
_flaps->set_volume(fgGetFloat("/sim/sounds/click/volume", 1.0));
_flaps->set_pitch(fgGetFloat("/sim/sounds/click/pitch", 1.0));
mgr->add(_click, "click");
////////////////////////////////////////////////////////////////////
// Grab some properties.
////////////////////////////////////////////////////////////////////
for (i = 0; i < MAX_ENGINES; i++) {
char buf[100];
sprintf(buf, "/engines/engine[%d]/running", i);
_engine_running_prop[i] = fgGetNode(buf, true);
sprintf(buf, "/engines/engine[%d]/cranking", i);
_engine_cranking_prop[i] = fgGetNode(buf, true);
}
_stall_warning_prop = fgGetNode("/sim/aero/alarms/stall-warning", true);
_vc_prop = fgGetNode("/velocities/airspeed-kt", true);
_flaps_prop = fgGetNode("/controls/flaps", true);
_gear_prop = fgGetNode("/controls/gear-down", true);
}
void
FGFX::bind ()
{
}
void
FGFX::unbind ()
{
}
void
FGFX::update (int dt)
{
FGSoundMgr * mgr = globals->get_soundmgr();
int i;
////////////////////////////////////////////////////////////////////
// Update the engine sound.
////////////////////////////////////////////////////////////////////
for (i = 0; i < MAX_ENGINES; i++) {
if (cur_fdm_state->get_num_engines() > 0 &&
_engine_running_prop[i]->getBoolValue()) {
// pitch corresponds to rpm
// volume corresponds to manifold pressure
double rpm_factor;
if ( cur_fdm_state->get_num_engines() > 0 )
rpm_factor = cur_fdm_state->get_engine(i)->get_RPM() / 2500.0;
else
rpm_factor = 1.0;
double pitch = 0.3 + rpm_factor * 3.0;
// don't run at absurdly slow rates -- not realistic
// and sounds bad to boot. :-)
if (pitch < 0.7)
pitch = 0.7;
if (pitch > 5.0)
pitch = 5.0;
double mp_factor;
if ( cur_fdm_state->get_num_engines() > 0 )
mp_factor =
cur_fdm_state->get_engine(i)->get_Manifold_Pressure() / 100;
else
mp_factor = 0.3;
double volume = 0.15 + mp_factor / 2.0;
if (volume < 0.15)
volume = 0.15;
if (volume > 0.5)
volume = 0.5;
_engine[i]->set_pitch( pitch );
_engine[i]->set_volume( volume );
set_playing(engine_names[i], true);
} else {
set_playing(engine_names[i], false);
}
// FIXME
set_playing(crank_names[i], _engine_cranking_prop[i]->getBoolValue());
}
////////////////////////////////////////////////////////////////////
// Update the wind noise.
////////////////////////////////////////////////////////////////////
float rel_wind = cur_fdm_state->get_V_rel_wind(); // FPS
float airspeed_kt = cur_fdm_state->get_V_equiv_kts();
if (rel_wind > 60.0) { // a little off 30kt
// float volume = rel_wind/600.0; // FIXME!!!
float volume = rel_wind/937.0; // FIXME!!!
double pitch = 1.0+(airspeed_kt/113.0);
_wind->set_volume(volume);
_wind->set_pitch(pitch);
set_playing("wind", true);
} else {
set_playing("wind", false);
}
////////////////////////////////////////////////////////////////////
// Update the stall horn.
////////////////////////////////////////////////////////////////////
double stall = _stall_warning_prop->getDoubleValue();
double vc = _vc_prop->getDoubleValue();
if (stall > 0.0 && vc > 30.0) {
_stall->set_volume(stall);
set_playing("stall", true);
} else {
set_playing("stall", false);
}
////////////////////////////////////////////////////////////////////
// Update the rumble.
////////////////////////////////////////////////////////////////////
float totalGear = min(cur_fdm_state->get_num_gear(), int(MAX_GEAR));
float gearOnGround = 0;
// Calculate whether a squeal is
// required, and set the volume.
// Currently, the squeal volume is the
// current local down velocity in feet
// per second divided by 10.0, and
// will not be played if under 0.1.
// FIXME: take rotational velocities
// into account as well.
for (i = 0; i < totalGear; i++) {
// cout << "air speed = " << cur_fdm_state->get_V_equiv_kts();
// cout << " wheel " << i << " speed = " << _wheel_spin[i];
if (cur_fdm_state->get_gear_unit(i)->GetWoW()) {
gearOnGround++;
if (!_gear_on_ground[i]) {
// wheel just touched down
// 3 parts horizontal velocity + 1 part vertical velocity
double squeal_volume = 0.75 * cur_fdm_state->get_V_equiv_kts() / 90.0
+ 0.25 * cur_fdm_state->get_V_down() / 5.0;
// scale volume by difference between wheel spin speed and
// ground speed
double diff = fabs( cur_fdm_state->get_V_equiv_kts()
- _wheel_spin[i] );
// cout << " speed diff = " << diff;
double scale_factor = 0.0;
if ( diff > 10 ) {
scale_factor = ( diff - 10.0 ) / 30.0f;
if ( scale_factor > 1.0 ) { scale_factor = 1.0; }
}
// cout << " scale_factor = " << scale_factor;
squeal_volume *= scale_factor;
if (squeal_volume > 0.1) {
_squeal->set_volume(squeal_volume);
_squeal->set_pitch(1.25);
mgr->play_once("squeal");
}
_gear_on_ground[i] = true;
}
// cout << " wow";
_wheel_spin[i] = cur_fdm_state->get_V_equiv_kts();
} else {
// cout << " airborn";
_gear_on_ground[i] = false;
/* fix me: wheel spindown is currently frame rate dependent which
it shouldn't be */
_wheel_spin[i] -= 0.2;
if ( _wheel_spin[i] < 0.0 ) { _wheel_spin[i] = 0.0; }
}
// cout << endl;
}
// Now, if any of the gear is in
// contact with the ground play the
// rumble sound. The volume is the
// absolute velocity in knots divided
// by 120.0. No rumble will be played
// if the velocity is under 6kt.
double speed = cur_fdm_state->get_V_equiv_kts();
if (gearOnGround > 0 && speed >= 6.0) {
double volume = 2.0 * (gearOnGround/totalGear) * (speed/60.0);
_rumble->set_volume(volume);
set_playing("rumble", true);
} else {
set_playing("rumble", false);
}
////////////////////////////////////////////////////////////////////
// Check for flap movement.
////////////////////////////////////////////////////////////////////
double flap_position = _flaps_prop->getDoubleValue();
if (fabs(flap_position - _old_flap_position) > 0.1) {
mgr->play_once("flaps");
_old_flap_position = flap_position;
}
////////////////////////////////////////////////////////////////////
// Check for gear movement.
////////////////////////////////////////////////////////////////////
double gear_position = _gear_prop->getDoubleValue();
if (gear_position != _old_gear_position) {
if (gear_position < _old_gear_position) {
mgr->play_once("gear-up");
} else {
mgr->play_once("gear-down");
}
_old_gear_position = gear_position;
}
// TODO: click
}
void
FGFX::set_playing (const char * soundName, bool state)
{
FGSoundMgr * mgr = globals->get_soundmgr();
bool playing = mgr->is_playing(soundName);
if (state && !playing)
mgr->play_looped(soundName);
else if (!state && playing)
mgr->stop(soundName);
}
// end of fg_fx.cxx