<Filter\r
Name="Lib_Sound"\r
>\r
+ <File\r
+ RelativePath="..\..\..\src\Sound\audioident.cxx"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\..\src\Sound\audioident.hxx"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\..\..\src\Sound\beacon.cxx"\r
>\r
}
SGSoundSample *sound;
- sound = FGMorse::instance()->make_ident( ident, LO_FREQUENCY );
+ sound = FGMorse::instance()->make_ident( ident, FGMorse::LO_FREQUENCY );
sound->set_volume(_last_volume = 0);
_sgr->add( sound, _adf_ident );
#endif
#include <simgear/compiler.h>
+#include <simgear/sg_inlines.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/sg_random.h>
#include <Main/fg_props.hxx>
#include <Navaids/navlist.hxx>
+#include <Sound/audioident.hxx>
#include "dme.hxx"
-
/**
* Adjust the range.
*
: _last_distance_nm(0),
_last_frequency_mhz(-1),
_time_before_search_sec(0),
- _transmitter_valid(false),
- _transmitter_elevation_ft(0),
- _transmitter_range_nm(0),
- _transmitter_bias(0.0),
+ _navrecord(NULL),
_name(node->getStringValue("name", "dme")),
- _num(node->getIntValue("number", 0))
+ _num(node->getIntValue("number", 0)),
+ _audioIdent(NULL)
{
}
DME::~DME ()
{
+ delete _audioIdent;
}
void
SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true );
- _longitude_node = fgGetNode("/position/longitude-deg", true);
- _latitude_node = fgGetNode("/position/latitude-deg", true);
- _altitude_node = fgGetNode("/position/altitude-ft", true);
_serviceable_node = node->getChild("serviceable", 0, true);
_electrical_node = fgGetNode("/systems/electrical/outputs/dme", true);
SGPropertyNode *fnode = node->getChild("frequencies", 0, true);
_distance_node = node->getChild("indicated-distance-nm", 0, true);
_speed_node = node->getChild("indicated-ground-speed-kt", 0, true);
_time_node = node->getChild("indicated-time-min", 0, true);
+
+ double d = node->getDoubleValue( "volume", 1.0 );
+ _volume_node = node->getChild("volume", 0, true);
+ _volume_node->setDoubleValue( d );
+
+ bool b = node->getBoolValue( "ident", false );
+ _ident_btn_node = node->getChild("ident", 0, true);
+ _ident_btn_node->setBoolValue( b );
+
+ std::ostringstream temp;
+ temp << _name << "-ident-" << _num;
+ if( NULL == _audioIdent )
+ _audioIdent = new DMEAudioIdent( temp.str() );
+ _audioIdent->init();
}
void
DME::update (double delta_time_sec)
{
+ if( delta_time_sec < SGLimitsd::min() )
+ return; //paused
+
// Figure out the source
const char * source = _source_node->getStringValue();
if (source[0] == '\0') {
_frequency_node->setDoubleValue(frequency_mhz);
// Get the aircraft position
- double longitude_rad =
- _longitude_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
- double latitude_rad =
- _latitude_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
- double altitude_m =
- _altitude_node->getDoubleValue() * SG_FEET_TO_METER;
-
- // On timeout, scan again
+ // On timeout, scan again
_time_before_search_sec -= delta_time_sec;
- if (_time_before_search_sec < 0)
- search(frequency_mhz, longitude_rad,
- latitude_rad, altitude_m);
+ if (_time_before_search_sec < 0) {
+ _time_before_search_sec = 1.0;
- // If it's off, don't bother.
+ _navrecord = globals->get_dmelist()->findByFreq( frequency_mhz,
+ globals->get_aircraft_position());
+ }
+
+ // If it's off, don't bother.
if (!_serviceable_node->getBoolValue() ||
!_electrical_node->getBoolValue() ||
- !_transmitter_valid) {
+ NULL == _navrecord ) {
_last_distance_nm = 0;
_in_range_node->setBoolValue(false);
_distance_node->setDoubleValue(0);
_speed_node->setDoubleValue(0);
_time_node->setDoubleValue(0);
+ _audioIdent->setIdent("", 0.0 );
return;
}
- // Calculate the distance to the transmitter
- SGGeod geod = SGGeod::fromRadM(longitude_rad, latitude_rad, altitude_m);
- SGVec3d location = SGVec3d::fromGeod(geod);
+ // Calculate the distance to the transmitter
+ SGVec3d location = SGVec3d::fromGeod(globals->get_aircraft_position());
- double distance_nm = dist(_transmitter, location) * SG_METER_TO_NM;
+ double distance_nm = dist(_navrecord->cart(), location) * SG_METER_TO_NM;
- double range_nm = adjust_range(_transmitter_elevation_ft,
- altitude_m * SG_METER_TO_FEET,
- _transmitter_range_nm);
+ double range_nm = adjust_range(_navrecord->get_elev_ft(),
+ globals->get_aircraft_position().getElevationFt(),
+ _navrecord->get_range());
if (distance_nm <= range_nm) {
+ double volume = _volume_node->getDoubleValue();
+ if( false == _ident_btn_node->getBoolValue() )
+ volume = 0.0;
+
+ _audioIdent->setIdent(_navrecord->ident(), volume );
+
double speed_kt = (fabs(distance_nm - _last_distance_nm) *
((1 / delta_time_sec) * 3600.0));
_last_distance_nm = distance_nm;
_in_range_node->setBoolValue(true);
- double tmp_dist = distance_nm - _transmitter_bias;
+ double tmp_dist = distance_nm - _navrecord->get_multiuse();
if ( tmp_dist < 0.0 ) {
tmp_dist = 0.0;
}
_distance_node->setDoubleValue(0);
_speed_node->setDoubleValue(0);
_time_node->setDoubleValue(0);
+ _audioIdent->setIdent("", 0.0 );
}
-}
-
-void
-DME::search (double frequency_mhz, double longitude_rad,
- double latitude_rad, double altitude_m)
-{
- // reset search time
- _time_before_search_sec = 1.0;
-
- // try the ILS list first
- FGNavRecord *dme = globals->get_dmelist()->findByFreq( frequency_mhz,
- SGGeod::fromRadM(longitude_rad, latitude_rad, altitude_m));
-
- _transmitter_valid = (dme != NULL);
-
- if ( _transmitter_valid ) {
- _transmitter = dme->cart();
- _transmitter_elevation_ft = dme->get_elev_ft();
- _transmitter_range_nm = dme->get_range();
- _transmitter_bias = dme->get_multiuse();
- }
+ _audioIdent->update( delta_time_sec );
}
// end of dme.cxx
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
-
/**
* Model a DME radio.
*
private:
- void search (double frequency, double longitude_rad,
- double latitude_rad, double altitude_m);
-
- SGPropertyNode_ptr _longitude_node;
- SGPropertyNode_ptr _latitude_node;
- SGPropertyNode_ptr _altitude_node;
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _electrical_node;
SGPropertyNode_ptr _source_node;
SGPropertyNode_ptr _distance_node;
SGPropertyNode_ptr _speed_node;
SGPropertyNode_ptr _time_node;
+ SGPropertyNode_ptr _ident_btn_node;
+ SGPropertyNode_ptr _volume_node;
double _last_distance_nm;
double _last_frequency_mhz;
double _time_before_search_sec;
- bool _transmitter_valid;
- SGVec3d _transmitter;
- double _transmitter_elevation_ft;
- double _transmitter_range_nm;
- double _transmitter_bias;
+ FGNavRecord * _navrecord;
string _name;
int _num;
+ class AudioIdent * _audioIdent;
};
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
-// $Id$
#ifdef HAVE_CONFIG_H
// Constructor
FGKR_87::FGKR_87( SGPropertyNode *node ) :
- lon_node(fgGetNode("/position/longitude-deg", true)),
- lat_node(fgGetNode("/position/latitude-deg", true)),
- alt_node(fgGetNode("/position/altitude-ft", true)),
bus_power(fgGetNode("/systems/electrical/outputs/adf", true)),
serviceable(fgGetNode("/instrumentation/adf/serviceable", true)),
need_update(true),
// Update the various nav values based on position and valid tuned in navs
void FGKR_87::update( double dt_sec ) {
- SGGeod acft = SGGeod::fromDegFt(lon_node->getDoubleValue(),
- lat_node->getDoubleValue(),
- alt_node->getDoubleValue());
+ SGGeod acft = globals->get_aircraft_position();
need_update = false;
// Update current nav/adf radio stations based on current postition
void FGKR_87::search() {
- SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
- lat_node->getDoubleValue(), alt_node->getDoubleValue());
+ SGGeod pos = globals->get_aircraft_position();
// FIXME: the panel should handle this
static string last_ident = "";
_sgr->remove( "adf-ident" );
}
SGSoundSample *sound;
- sound = FGMorse::instance()->make_ident( trans_ident, LO_FREQUENCY );
+ sound = FGMorse::instance()->make_ident( trans_ident, FGMorse::LO_FREQUENCY );
sound->set_volume( 0.3 );
_sgr->add( sound, "adf-ident" );
class FGKR_87 : public SGSubsystem
{
- SGPropertyNode_ptr lon_node;
- SGPropertyNode_ptr lat_node;
- SGPropertyNode_ptr alt_node;
SGPropertyNode_ptr bus_power;
SGPropertyNode_ptr serviceable;
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
-// $Id$
-
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <simgear/misc/strutils.hxx>
#include <Navaids/navrecord.hxx>
-
+#include <Sound/audioident.hxx>
#include <Airports/runways.hxx>
#include <Navaids/navlist.hxx>
#include <Main/util.hxx>
-#include <Sound/morse.hxx>
-
using std::string;
term_tbl(NULL),
low_tbl(NULL),
high_tbl(NULL),
- lon_node(fgGetNode("/position/longitude-deg", true)),
- lat_node(fgGetNode("/position/latitude-deg", true)),
- alt_node(fgGetNode("/position/altitude-ft", true)),
_operable(false),
play_count(0),
last_time(0),
_gsCart(SGVec3d::zeros()),
_gsAxis(SGVec3d::zeros()),
_gsVertical(SGVec3d::zeros()),
- _dmeInRange(false),
_toFlag(false),
_fromFlag(false),
_cdiDeflection(0.0),
_cdiCrossTrackErrorM(0.0),
_gsNeedleDeflection(0.0),
_gsNeedleDeflectionNorm(0.0),
- _sgr(NULL)
+ _audioIdent(NULL)
{
SGPath path( globals->get_fg_root() );
SGPath term = path;
delete term_tbl;
delete low_tbl;
delete high_tbl;
+
+ delete _audioIdent;
}
void
FGNavRadio::init ()
{
- SGSoundMgr *smgr = globals->get_soundmgr();
- _sgr = smgr->find("avionics", true);
- _sgr->tie_to_listener();
-
SGPropertyNode* node = _radio_node.get();
bus_power_node =
fgGetNode(("/systems/electrical/outputs/" + _name).c_str(), true);
cdi_serviceable_node = createServiceableProp(node, "cdi");
gs_serviceable_node = createServiceableProp(node, "gs");
tofrom_serviceable_node = createServiceableProp(node, "to-from");
- dme_serviceable_node = createServiceableProp(node, "dme");
falseCoursesEnabledNode =
fgGetNode("/sim/realism/false-radio-courses-enabled");
_magvarNode = fgGetNode("/environment/magnetic-variation-deg", true);
std::ostringstream temp;
- temp << _name << "nav-ident" << _num;
- nav_fx_name = temp.str();
- temp << _name << "dme-ident" << _num;
- dme_fx_name = temp.str();
+ temp << _name << "-ident-" << _num;
+ if( NULL == _audioIdent )
+ _audioIdent = new VORAudioIdent( temp.str() );
+ _audioIdent->init();
+
+ // dme-in-range is deprecated,
+ // temporarily create dme-in-range alias for instrumentation/dme[0]/in-range
+ // remove after flightgear 2.6.0
+ node->getNode( "dme-in-range", true )->alias( fgGetNode("/instrumentation/dme[0]/in-range", true ) );
}
void
FGNavRadio::bind ()
{
- tie("dme-in-range", SGRawValuePointer<bool>(&_dmeInRange));
- tie("operable", SGRawValueMethods<FGNavRadio, bool>(*this, &FGNavRadio::isOperable, NULL));
+ _radio_node->tie( "operable", SGRawValueMethods<FGNavRadio,bool>( *this, &FGNavRadio::isOperable ) );
}
void
FGNavRadio::unbind ()
{
- for (unsigned int t=0; t<_tiedNodes.size(); ++t) {
- _tiedNodes[t]->untie();
- }
- _tiedNodes.clear();
+ _radio_node->untie("operable");
}
clearOutputs();
}
- updateAudio();
+ updateAudio( dt );
}
void FGNavRadio::clearOutputs()
is_valid_node->setBoolValue(false);
nav_id_node->setStringValue("");
- _dmeInRange = false;
_operable = false;
_navaid = NULL;
}
void FGNavRadio::updateReceiver(double dt)
{
- SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
- lat_node->getDoubleValue(),
- alt_node->getDoubleValue());
- SGVec3d aircraft = SGVec3d::fromGeod(pos);
+ SGVec3d aircraft = SGVec3d::fromGeod(globals->get_aircraft_position());
double loc_dist = 0;
// Do a nav station search only once a second to reduce
loc_dist = dist(aircraft, _navaid->cart());
loc_dist_node->setDoubleValue( loc_dist );
}
- updateDME(aircraft);
if (nav_slaved_to_gps_node->getBoolValue()) {
// when slaved to GPS: only allow stuff above: tune NAV station
- // upate DME. All other data driven by GPS only.
+ // All other data driven by GPS only.
updateGPSSlaved();
return;
}
// compute forward and reverse wgs84 headings to localizer
//////////////////////////////////////////////////////////
double hdg;
- SGGeodesy::inverse(pos, _navaid->geod(), hdg, az2, s);
+ SGGeodesy::inverse(globals->get_aircraft_position(), _navaid->geod(), hdg, az2, s);
heading_node->setDoubleValue(hdg);
double radial = az2 - twist;
double recip = radial + 180.0;
double offset = radial - target_radial;
SG_NORMALIZE_RANGE(offset, -180.0, 180.0);
effective_range
- = adjustILSRange( nav_elev, pos.getElevationM(), offset,
+ = adjustILSRange( nav_elev, globals->get_aircraft_position().getElevationM(), offset,
loc_dist * SG_METER_TO_NM );
} else {
effective_range
- = adjustNavRange( nav_elev, pos.getElevationM(), _navaid->get_range() );
+ = adjustNavRange( nav_elev, globals->get_aircraft_position().getElevationM(), _navaid->get_range() );
}
double effective_range_m = effective_range * SG_NM_TO_METER;
->setDoubleValue( gs_rate_of_climb_node->getDoubleValue() * 60 );
}
-void FGNavRadio::updateDME(const SGVec3d& aircraft)
-{
- if (!_dme || !dme_serviceable_node->getBoolValue()) {
- _dmeInRange = false;
- return;
- }
-
- double dme_distance = dist(aircraft, _dme->cart());
- _dmeInRange = (dme_distance < _dme->get_range() * SG_NM_TO_METER);
-}
-
void FGNavRadio::valueChanged (SGPropertyNode* prop)
{
if (prop == gps_course_node) {
last_xtrack_error = _cdiCrossTrackErrorM;
}
-void FGNavRadio::updateAudio()
+void FGNavRadio::updateAudio( double dt )
{
if (!_navaid || !inrange_node->getBoolValue() || !nav_serviceable_node->getBoolValue()) {
+ _audioIdent->setIdent("", 0.0 );
return;
}
|| !(bus_power_node->getDoubleValue() > 1.0)
|| !ident_btn_node->getBoolValue()
|| !audio_btn_node->getBoolValue() ) {
- _sgr->stop( nav_fx_name );
- _sgr->stop( dme_fx_name );
+ _audioIdent->setIdent("", 0.0 );
return;
}
- SGSoundSample *sound = _sgr->find( nav_fx_name );
- double vol = vol_btn_node->getFloatValue();
- SG_CLAMP_RANGE(vol, 0.0, 1.0);
-
- if ( sound != NULL ) {
- sound->set_volume( vol );
- } else {
- SG_LOG( SG_COCKPIT, SG_ALERT, "Can't find nav-vor-ident sound" );
- }
-
- sound = _sgr->find( dme_fx_name );
- if ( sound != NULL ) {
- sound->set_volume( vol );
- } else {
- SG_LOG( SG_COCKPIT, SG_ALERT, "Can't find nav-dme-ident sound" );
- }
-
- const int NUM_IDENT_SLOTS = 5;
- const time_t SLOT_LENGTH = 5; // seconds
-
- // There are N slots numbered 0 through (NUM_IDENT_SLOTS-1) inclusive.
- // Each slot is 5 seconds long.
- // Slots 0 is for DME
- // the rest are for azimuth.
- time_t now = globals->get_time_params()->get_cur_time();
- if ((now >= last_time) && (now < last_time + SLOT_LENGTH)) {
- return; // wait longer
- }
-
- last_time = now;
- play_count++;
- play_count %= NUM_IDENT_SLOTS;
-
- // Previous ident is out of time; if still playing, cut it off:
- _sgr->stop( nav_fx_name );
- _sgr->stop( dme_fx_name );
- if (play_count == 0) { // the DME slot
- if (_dmeInRange && dme_serviceable_node->getBoolValue()) {
- // play DME ident
- if (vol > 0.05) _sgr->play_once( dme_fx_name );
- }
- } else { // NAV slot
- if (inrange_node->getBoolValue() && nav_serviceable_node->getBoolValue()) {
- if (vol > 0.05) _sgr->play_once(nav_fx_name);
- }
- }
+ _audioIdent->setIdent( _navaid->get_trans_ident(), vol_btn_node->getFloatValue() );
+
+ _audioIdent->update( dt );
}
FGNavRecord* FGNavRadio::findPrimaryNavaid(const SGGeod& aPos, double aFreqMHz)
void FGNavRadio::search()
{
_time_before_search_sec = 1.0;
- SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
- lat_node->getDoubleValue(), alt_node->getDoubleValue());
double freq = freq_node->getDoubleValue();
- FGNavRecord* nav = findPrimaryNavaid(pos, freq);
+ FGNavRecord* nav = findPrimaryNavaid(globals->get_aircraft_position(), freq);
if (nav == _navaid) {
return; // found the same as last search, we're done
}
_navaid = nav;
string identBuffer(4, ' ');
if (nav) {
- // use ILS signals as DME, otherwise search by frequency
- if (nav->type()==FGPositioned::ILS)
- _dme = nav;
- else
- _dme = globals->get_dmelist()->findByFreq(freq, pos);
-
nav_id_node->setStringValue(nav->get_ident());
identBuffer = simgear::strutils::rpad( nav->ident(), 4, ' ' );
- effective_range = adjustNavRange(nav->get_elev_ft(), pos.getElevationM(), nav->get_range());
+ effective_range = adjustNavRange(nav->get_elev_ft(), globals->get_aircraft_position().getElevationM(), nav->get_range());
loc_node->setBoolValue(nav->type() != FGPositioned::VOR);
twist = nav->get_multiuse();
_gs = NULL;
has_gs_node->setBoolValue(false);
} else { // ILS or LOC
- _gs = globals->get_gslist()->findByFreq(freq, pos);
+ _gs = globals->get_gslist()->findByFreq(freq, globals->get_aircraft_position());
has_gs_node->setBoolValue(_gs != NULL);
_localizerWidth = nav->localizerWidth();
twist = 0.0;
} // of have glideslope
} // of found LOC or ILS
- audioNavidChanged();
} else { // found nothing
_gs = NULL;
- _dme = NULL;
nav_id_node->setStringValue("");
loc_node->setBoolValue(false);
has_gs_node->setBoolValue(false);
-
- _sgr->remove( nav_fx_name );
- _sgr->remove( dme_fx_name );
+ _audioIdent->setIdent("", 0.0 );
}
is_valid_node->setBoolValue(nav != NULL);
id_c3_node->setIntValue( (int)identBuffer[2] );
id_c4_node->setIntValue( (int)identBuffer[3] );
}
-
-void FGNavRadio::audioNavidChanged()
-{
- if (_sgr->exists(nav_fx_name)) {
- _sgr->remove(nav_fx_name);
- }
-
- try {
- string trans_ident(_navaid->get_trans_ident());
- SGSoundSample* sound = FGMorse::instance()->make_ident(trans_ident, LO_FREQUENCY);
- sound->set_volume( 0.3 );
- if (!_sgr->add( sound, nav_fx_name )) {
- SG_LOG(SG_COCKPIT, SG_WARN, "Failed to add v1-vor-ident sound");
- }
-
- if ( _sgr->exists( dme_fx_name ) ) {
- _sgr->remove( dme_fx_name );
- }
-
- sound = FGMorse::instance()->make_ident( trans_ident, HI_FREQUENCY );
- sound->set_volume( 0.3 );
- _sgr->add( sound, dme_fx_name );
-
- int offset = (int)(sg_random() * 30.0);
- play_count = offset / 4;
- last_time = globals->get_time_params()->get_cur_time() - offset;
- } catch (sg_io_exception& e) {
- SG_LOG(SG_GENERAL, SG_ALERT, e.getFormattedMessage());
- }
-}
SGInterpTable *high_tbl;
SGPropertyNode_ptr _radio_node;
- SGPropertyNode_ptr lon_node;
- SGPropertyNode_ptr lat_node;
- SGPropertyNode_ptr alt_node;
SGPropertyNode_ptr bus_power_node;
// property inputs
SGPropertyNode_ptr cdi_serviceable_node;
SGPropertyNode_ptr gs_serviceable_node;
SGPropertyNode_ptr tofrom_serviceable_node;
- SGPropertyNode_ptr dme_serviceable_node;
// property outputs
SGPropertyNode_ptr fmt_freq_node; // formated frequency
FGNavRecordPtr _navaid;
FGNavRecordPtr _gs;
- string nav_fx_name;
- string dme_fx_name;
-
double target_radial;
double effective_range;
double target_gs;
SGVec3d _gsCart, _gsAxis, _gsVertical, _gsBaseline;
- FGNavRecordPtr _dme;
- bool _dmeInRange;
-
// CDI properties
bool _toFlag, _fromFlag;
double _cdiDeflection;
double _gsNeedleDeflection;
double _gsNeedleDeflectionNorm;
double _gsDirect;
-
- SGSharedPtr<SGSampleGroup> _sgr;
- std::vector<SGPropertyNode_ptr> _tiedNodes;
+
+ class AudioIdent * _audioIdent;
bool updateWithPower(double aDt);
double adjustILSRange( double stationElev, double aircraftElev,
double offsetDegrees, double distance );
- void updateAudio();
- void audioNavidChanged();
+ void updateAudio( double dt );
void updateReceiver(double dt);
- void updateDME(const SGVec3d& aircraft);
void updateGlideSlope(double dt, const SGVec3d& aircraft, double signal_quality_norm);
void updateGPSSlaved();
void updateCDI(double dt);
bool isOperable() const
{ return _operable; }
- /**
- * Tied-properties helper, record nodes which are tied for easy un-tie-ing
- */
- template <typename T>
- void tie(const char* aRelPath, const SGRawValue<T>& aRawValue)
- {
- SGPropertyNode_ptr nd = _radio_node->getNode(aRelPath, true);
- _tiedNodes.push_back(nd);
- nd->tie(aRawValue);
- }
-
// implement SGPropertyChangeListener
virtual void valueChanged (SGPropertyNode * prop);
public:
include(FlightGearComponent)
set(SOURCES
+ audioident.cxx
soundgenerator.cxx
beacon.cxx
fg_fx.cxx
)
set(HEADERS
+ audioident.hxx
soundgenerator.hxx
beacon.hxx
fg_fx.hxx
noinst_LIBRARIES = libSound.a
libSound_a_SOURCES = \
+ audioident.cxx audioident.hxx \
soundgenerator.cxx soundgenerator.hxx \
beacon.cxx beacon.hxx \
fg_fx.cxx fg_fx.hxx \
--- /dev/null
+// audioident.cxx -- audible station identifiers
+//
+// Written by Torsten Dreyer, September 2011
+//
+// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+
+#include "audioident.hxx"
+#include <simgear/sg_inlines.h>
+
+#include <Main/globals.hxx>
+#include <Sound/Morse.hxx>
+
+AudioIdent::AudioIdent( const std::string & fx_name, const double interval_secs, const int frequency_hz ) :
+ _fx_name(fx_name),
+ _frequency(frequency_hz),
+ _timer(0.0),
+ _interval(interval_secs),
+ _running(false)
+{
+}
+
+void AudioIdent::init()
+{
+ _timer = 0.0;
+ _ident = "";
+ _running = false;
+ _sgr = globals->get_soundmgr()->find("avionics", true);
+ _sgr->tie_to_listener();
+}
+
+void AudioIdent::stop()
+{
+ if( _sgr->exists( _fx_name ) )
+ _sgr->stop( _fx_name );
+ _running = false;
+}
+
+void AudioIdent::start()
+{
+ _timer = _interval;
+ _sgr->play_once(_fx_name);
+ _running = true;
+}
+
+void AudioIdent::setVolumeNorm( double volumeNorm )
+{
+ SG_CLAMP_RANGE(volumeNorm, 0.0, 1.0);
+
+ SGSoundSample *sound = _sgr->find( _fx_name );
+
+ if ( sound != NULL ) {
+ sound->set_volume( volumeNorm );
+ }
+}
+
+void AudioIdent::setIdent( const std::string & ident, double volumeNorm )
+{
+ if( _ident == ident ) {
+ if( false == _ident.empty() )
+ setVolumeNorm( volumeNorm );
+ return;
+ }
+
+ try {
+ stop();
+
+ if ( _sgr->exists( _fx_name ) )
+ _sgr->remove( _fx_name );
+
+ if( false == ident.empty() ) {
+
+ SGSoundSample* sound = FGMorse::instance()->make_ident(ident, _frequency );
+ sound->set_volume( volumeNorm );
+ if (!_sgr->add( sound, _fx_name )) {
+ SG_LOG(SG_SOUND, SG_WARN, "Failed to add sound '" << _fx_name << "' for ident '" << ident << "'" );
+ return;
+ }
+
+ start();
+ }
+ _ident = ident;
+
+ } catch (sg_io_exception& e) {
+ SG_LOG(SG_SOUND, SG_ALERT, e.getFormattedMessage());
+ }
+
+}
+
+void AudioIdent::update( double dt )
+{
+ // single-shot
+ if( false == _running || _interval < SGLimitsd::min() )
+ return;
+
+ _timer -= dt;
+
+ if( _timer < SGLimitsd::min() ) {
+ _timer = _interval;
+ stop();
+ start();
+ }
+}
+
+// FIXME: shall transmit at least 6 wpm (ICAO Annex 10 - 3.5.3.6.3)
+DMEAudioIdent::DMEAudioIdent( const std::string & fx_name )
+: AudioIdent( fx_name, 40, FGMorse::HI_FREQUENCY )
+{
+}
+
+
+//FIXME: for co-located VOR/DME or ILS/DME, assign four time-slots
+// 3xVOR/ILS ident, 1xDME ident
+
+// FIXME: shall transmit at approx. 7 wpm (ICAO Annex 10 - 3.3.6.5.1)
+VORAudioIdent::VORAudioIdent( const std::string & fx_name )
+: AudioIdent( fx_name, 10, FGMorse::LO_FREQUENCY )
+{
+}
+
+//FIXME: LOCAudioIdent at approx 7wpm (ICAO Annex 10 - 3.1.3.9.4)
+// not less than six times per minute at approx equal intervals
+// frequency 1020+/-50Hz (3.1.3.9.2)
+
+// FIXME: NDBAudioIdent at approx 7 wpm (ICAO ANNEX 10 - 3.4.5.1)
+// at least once every 10s (3.4.5.2.1)
+// frequency 1020+/-50Hz or 400+/-25Hz (3.4.5.4)
\ No newline at end of file
--- /dev/null
+// audioident.hxx -- audible station identifiers
+//
+// Written by Torsten Dreyer, September 2011
+//
+// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+
+
+#ifndef _FGAUDIOIDENT_HXX
+#define _FGAUDIOIDENT_HXX
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string>
+#include <simgear/sound/soundmgr_openal.hxx>
+
+class AudioIdent {
+public:
+ AudioIdent( const std::string & fx_name, const double interval_secs, const int frequency );
+ void init();
+ void setVolumeNorm( double volumeNorm );
+ void setIdent( const std::string & ident, double volumeNorm );
+
+ void update( double dt );
+
+private:
+ void stop();
+ void start();
+
+ SGSharedPtr<SGSampleGroup> _sgr;
+ std::string _fx_name;
+ const int _frequency;
+ std::string _ident;
+ double _timer;
+ double _interval;
+ bool _running;
+};
+
+class DMEAudioIdent : public AudioIdent {
+public:
+ DMEAudioIdent( const std::string & fx_name );
+};
+
+class VORAudioIdent : public AudioIdent {
+public:
+ VORAudioIdent( const std::string & fx_name );
+};
+
+#endif // _FGAUDIOIDENT_HXX
#include <cstring>
+static const char DI = '1';
+static const char DIT = '1';
+static const char DA = '2';
+static const char DAH = '2';
+static const char END = '0';
+
static const char alphabet[26][4] = {
{ DI, DAH, END, END }, /* A */
{ DA, DI, DI, DIT }, /* B */
// Hz for the VOR ident.
-static const char DI = '1';
-static const char DIT = '1';
-static const char DA = '2';
-static const char DAH = '2';
-static const char END = '0';
-
-static const int BYTES_PER_SECOND = 22050;
-// static const int BEAT_LENGTH = 240; // milleseconds (5 wpm)
-static const int BEAT_LENGTH = 92; // milleseconds (13 wpm)
-static const int TRANSITION_BYTES = (int)(0.005 * BYTES_PER_SECOND);
-static const int COUNT_SIZE = BYTES_PER_SECOND * BEAT_LENGTH / 1000;
-static const int DIT_SIZE = 2 * COUNT_SIZE; // 2 counts
-static const int DAH_SIZE = 4 * COUNT_SIZE; // 4 counts
-static const int SPACE_SIZE = 3 * COUNT_SIZE; // 3 counts
-static const int LO_FREQUENCY = 1020; // AIM 1-1-7 (f) specified in Hz
-static const int HI_FREQUENCY = 1350; // AIM 1-1-7 (f) specified in Hz
-
// manages everything we need to know for an individual sound sample
class FGMorse : public FGSoundGenerator {
bool init();
public:
+ static const int BYTES_PER_SECOND = 22050;
+ // static const int BEAT_LENGTH = 240; // milleseconds (5 wpm)
+ static const int BEAT_LENGTH = 92; // milleseconds (13 wpm)
+ static const int TRANSITION_BYTES = (int)(0.005 * BYTES_PER_SECOND);
+ static const int COUNT_SIZE = BYTES_PER_SECOND * BEAT_LENGTH / 1000;
+ static const int DIT_SIZE = 2 * COUNT_SIZE; // 2 counts
+ static const int DAH_SIZE = 4 * COUNT_SIZE; // 4 counts
+ static const int SPACE_SIZE = 3 * COUNT_SIZE; // 3 counts
+ static const int LO_FREQUENCY = 1020; // AIM 1-1-7 (f) specified in Hz
+ static const int HI_FREQUENCY = 1350; // AIM 1-1-7 (f) specified in Hz
+
FGMorse();
~FGMorse();