28#include <simgear/compiler.h>
29#include <simgear/math/sg_random.hxx>
30#include <simgear/misc/sg_path.hxx>
31#include <simgear/sound/sample_group.hxx>
71 _time_before_search_sec(0.0)
77 string blinkMode = node->getStringValue(
"blink-mode");
78 if (blinkMode ==
"standard") {
79 _blinkMode = BlinkMode::Standard;
80 }
else if (blinkMode ==
"continuous") {
81 _blinkMode = BlinkMode::Continuous;
99 sound_working =
fgGetNode(
"/sim/sound/working",
true);
100 audio_btn = node->getChild(
"audio-btn", 0,
true);
101 audio_vol = node->getChild(
"volume", 0,
true);
103 if (audio_btn->getType() == simgear::props::NONE)
104 audio_btn->setBoolValue(
true );
106 auto smgr =
globals->get_subsystem<SGSoundMgr>();
108 _audioSampleGroup = smgr->find(
"avionics",
true);
109 _audioSampleGroup->tie_to_listener();
111 sound_working->addChangeListener(
this);
112 audio_btn->addChangeListener(
this);
113 audio_vol->addChangeListener(
this);
122 _time_before_search_sec = 0.0;
124 updateOutputProperties(
false);
132 _innerBlinkNode =
fgGetNode(branch +
"/inner",
true);
133 _middleBlinkNode =
fgGetNode(branch +
"/middle",
true);
134 _outerBlinkNode =
fgGetNode(branch +
"/outer",
true);
143 fgUntie((branch +
"/inner").c_str());
144 fgUntie((branch +
"/middle").c_str());
145 fgUntie((branch +
"/outer").c_str());
147 if (_audioSampleGroup) {
148 sound_working->removeChangeListener(
this);
149 audio_btn->removeChangeListener(
this);
150 audio_vol->removeChangeListener(
this);
163 updateOutputProperties(
false);
167 _time_before_search_sec -= dt;
168 if ( _time_before_search_sec < 0 ) {
172 if (_audioPropertiesChanged) {
180 const int elapasedUSec = (SGTimeStamp::now() - _audioStartTime).toUSecs();
183 if (_blinkMode != BlinkMode::Continuous) {
184 int t = elapasedUSec % _beaconTiming.durationUSec;
185 for (
int i = 0;
i < 4;
i++) {
186 t -= _beaconTiming.periodsUSec.at(
i);
198 updateOutputProperties(on);
204 if (node->getBoolValue() != v) {
205 node->setBoolValue(v);
209void FGMarkerBeacon::updateOutputProperties(
bool on)
215 SGPropertyNode* beacons[4] = {
nullptr, _innerBlinkNode.get(), _middleBlinkNode.get(), _outerBlinkNode.get()};
217 const bool bOn = on && (_lastBeacon == b);
222void FGMarkerBeacon::updateAudio()
224 _audioPropertiesChanged =
false;
225 if (!_audioSampleGroup)
228 float volume = audio_vol->getFloatValue();
229 if (!audio_btn->getBoolValue()) {
236 mkr->set_volume(volume);
244 double d = distSqr(b->
cart(), SGVec3d::fromGeod(pos));
254 double elev_ft = pos.getElevationFt();
260 if ( delev < 1538.0 ) {
261 maxrange2 = 2.4 * 2.4 * delev * delev;
262 }
else if ( delev < 4000.0 ) {
263 maxrange2 = 4000 * 4000 - delev * delev;
267 maxrange2 *= SG_FEET_TO_METER * SG_FEET_TO_METER;
272 if ( d < maxrange2 ) {
297 _time_before_search_sec = 0.5;
299 const SGGeod pos =
globals->get_aircraft_position();
300 if (!pos.isValid()) {
310 bool inrange =
false;
327 changeBeaconType(beacon_type);
330void FGMarkerBeacon::changeBeaconType(fgMkrBeacType newType)
332 if (newType == _lastBeacon)
335 _lastBeacon = newType;
339 updateOutputProperties(
false);
343 if (_blinkMode == BlinkMode::Standard) {
358 }
else if (_blinkMode == BlinkMode::BackwardsCompatible) {
360 _beaconTiming = FGBeacon::BeaconTiming{};
361 _beaconTiming.durationUSec = 500000;
362 _beaconTiming.periodsUSec[0] = 400000;
363 _beaconTiming.periodsUSec[1] = 100000;
367 if (_audioSampleGroup) {
370 if (!_audioSampleGroup->exists(
name)) {
373 _audioSampleGroup->add(sound,
name);
377 _audioSampleGroup->play_looped(
name);
383 _audioStartTime.stamp();
386void FGMarkerBeacon::stopAudio()
388 if (_audioSampleGroup) {
389 _audioSampleGroup->stop(
"outer-marker");
390 _audioSampleGroup->stop(
"middle-marker");
391 _audioSampleGroup->stop(
"inner-marker");
397 _audioPropertiesChanged =
true;
402SGSubsystemMgr::InstancedRegistrant<FGMarkerBeacon> registrantFGMarkerBeacon(
404 {{
"instrumentation", SGSubsystemMgr::Dependency::HARD}},
SGSharedPtr< FGPositioned > FGPositionedRef
-- Provides marker beacon audio generation.
void initServicePowerProperties(SGPropertyNode *node)
void readConfig(SGPropertyNode *config, std::string defaultName)
std::string nodePath() const
void setDefaultPowerSupplyPath(const std::string &p)
specify the default path to use to power the instrument, if it's non- standard.
bool isServiceableAndPowered() const
FGPositioned::Type minType() const override
FGPositioned::Type maxType() const override
SGSoundSample * get_inner()
BeaconTiming getTimingForOuter() const
SGSoundSample * get_middle()
BeaconTiming getTimingForInner() const
static FGBeacon * instance()
SGSoundSample * get_outer()
BeaconTiming getTimingForMiddle() const
FGMarkerBeacon(SGPropertyNode *node)
void valueChanged(SGPropertyNode *val) override
void update(double dt) override
Predicate class to support custom filtering of FGPositioned queries Default implementation of this pa...
virtual const SGVec3d & cart() const
The cartesian position associated with this object.
static FGPositionedRef findClosest(const SGGeod &aPos, double aCutoffNm, Filter *aFilter=NULL)
Find the closest item to a position, which pass the specified filter A cutoff range in NM must be spe...
void fgUntie(const char *name)
Untie a property from an external data source.
static SGSoundSample * createSampleForBeacon(FGMarkerBeacon::fgMkrBeacType ty)
static string sampleNameForBeacon(FGMarkerBeacon::fgMkrBeacType ty)
static void lazyChangeBoolProp(SGPropertyNode *node, bool v)
static bool check_beacon_range(const SGGeod &pos, FGPositioned *b)
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.