# include <config.h>
#endif
+#include "ATC.hxx"
+
+#include <iostream>
+
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/structure/exception.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
+#include <ATC/CommStation.hxx>
+#include <Airports/simple.hxx>
-#include "ATC.hxx"
-
-FGATC::FGATC() {
- freqClear = true;
- receiving = false;
- respond = false;
- runResponseCounter = false;
- _runReleaseCounter = false;
- responseID = "";
- responseReqd = false;
- _type = INVALID;
- _display = false;
- _displaying = false;
-
+FGATC::FGATC() :
+ _playing(false),
+ _voiceOK(false),
+ _sgr(NULL),
+ freqClear(true),
+ receiving(false),
+ respond(false),
+ responseID(""),
+ runResponseCounter(false),
+ _runReleaseCounter(false),
+ responseReqd(false),
+ _type(INVALID),
+ _display(false),
// Transmission timing stuff
- pending_transmission = "";
- _timeout = 0;
- _pending = false;
- _callback_code = 0;
- _transmit = false;
- _transmitting = false;
- _counter = 0.0;
- _max_count = 5.0;
-
- _voiceOK = false;
+ pending_transmission(""),
+ _timeout(0),
+ _pending(false),
+ _transmit(false),
+ _transmitting(false),
+ _counter(0.0),
+ _max_count(5.0)
+{
+ SGSoundMgr *smgr = globals->get_soundmgr();
+ _sgr = smgr->find("atc", true);
+ _sgr->tie_to_listener();
+
+ _volume = fgGetNode("/sim/sound/atc/volume", true);
+ _enabled = fgGetNode("/sim/sound/atc/enabled", true);
+ _atc_external = fgGetNode("/sim/sound/atc/external-view", true);
+ _internal = fgGetNode("/sim/current-view/internal", true);
}
FGATC::~FGATC() {
}
-// Derived classes wishing to use the response counter should call this from their own Update(...).
+// Derived classes wishing to use the response counter should
+// call this from their own Update(...).
void FGATC::Update(double dt) {
if(runResponseCounter) {
//cout << responseCounter << '\t' << responseTime << '\n';
}
}
+#ifdef ENABLE_AUDIO_SUPPORT
+ bool active = _atc_external->getBoolValue() ||
+ _internal->getBoolValue();
+
+ if ( active && _enabled->getBoolValue() ) {
+ _sgr->set_volume( _volume->getFloatValue() );
+ _sgr->resume(); // no-op if already in resumed state
+ } else {
+ _sgr->suspend();
+ }
+#endif
+
if(_transmit) {
_counter = 0.0;
_max_count = 5.0; // FIXME - hardwired length of message - need to calculate it!
//Render(pending_transmission, ident, false);
Render(pending_transmission);
}
- // Run the callback regardless of whether on same freq as user or not.
- //cout << "_callback_code = " << _callback_code << '\n';
- if(_callback_code) {
- ProcessCallback(_callback_code);
- }
_transmit = false;
_transmitting = true;
} else if(_transmitting) {
}
}
-void FGATC::Transmit(int callback_code) {
- SG_LOG(SG_ATC, SG_INFO, "Transmit called by " << ident << " " << _type << ", msg = " << pending_transmission);
- _pending = true;
- _callback_code = callback_code;
- _timeout = 0.0;
-}
-
-void FGATC::ConditionalTransmit(double timeout, int callback_code) {
- SG_LOG(SG_ATC, SG_INFO, "Timed transmit called by " << ident << " " << _type << ", msg = " << pending_transmission);
- _pending = true;
- _callback_code = callback_code;
- _timeout = timeout;
-}
-
-void FGATC::ImmediateTransmit(int callback_code) {
- SG_LOG(SG_ATC, SG_INFO, "Immediate transmit called by " << ident << " " << _type << ", msg = " << pending_transmission);
- if(_display) {
- //Render(pending_transmission, ident, false);
- Render(pending_transmission);
- // At the moment Render doesn't work except for ATIS
- }
- if(callback_code) {
- ProcessCallback(callback_code);
- }
-}
-
-// Derived classes should override this.
-void FGATC::ProcessCallback(int code) {
-}
-
-void FGATC::AddPlane(const string& pid) {
-}
-
-int FGATC::RemovePlane() {
- return 0;
-}
-
-void FGATC::SetData(ATCData* d) {
- lon = d->lon;
- lat = d->lat;
- elev = d->elev;
- x = d->x;
- y = d->y;
- z = d->z;
- range = d->range;
- ident = d->ident;
- name = d->name;
- freq = d->freq;
+void FGATC::SetStation(flightgear::CommStation* sta) {
+ switch (sta->type()) {
+ case FGPositioned::FREQ_ATIS: _type = ATIS; break;
+ case FGPositioned::FREQ_AWOS: _type = AWOS; break;
+ default:
+ throw sg_exception("unsupported comm station type");
+ }
+
+ _geod = sta->geod();
+ _cart = sta->cart();
+ range = sta->rangeNm();
+ ident = sta->airport()->ident();
+ name = sta->airport()->name();
+ freq = sta->freqKHz();
}
// Render a transmission
// Outputs the transmission either on screen or as audio depending on user preference
// The refname is a string to identify this sample to the sound manager
// The repeating flag indicates whether the message should be repeated continuously or played once.
-void FGATC::Render(string& msg, const string& refname, bool repeating) {
+void FGATC::Render(string& msg, const float volume,
+ const string& refname, const bool repeating) {
+ if (volume < 0.05) return;
+
if (repeating)
fgSetString("/sim/messages/atis", msg.c_str());
else
fgSetString("/sim/messages/atc", msg.c_str());
- #ifdef ENABLE_AUDIO_SUPPORT
+#ifdef ENABLE_AUDIO_SUPPORT
_voice = (_voiceOK && fgGetBool("/sim/sound/voice"));
if(_voice) {
- int len;
- unsigned char* buf = _vPtr->WriteMessage((char*)msg.c_str(), len, _voice);
- if(_voice) {
+ size_t len;
+ void* buf = _vPtr->WriteMessage((char*)msg.c_str(), &len);
+ if(buf) {
+ NoRender(refname);
try {
- SGSoundSample *simple
- = new SGSoundSample(buf, len, 8000);
- // TODO - at the moment the volume is always set off comm1
- // and can't be changed after the transmission has started.
- simple->set_volume(5.0 * fgGetDouble("/instrumentation/comm[0]/volume"));
- globals->get_soundmgr()->add(simple, refname);
- if(repeating) {
- globals->get_soundmgr()->play_looped(refname);
- } else {
- globals->get_soundmgr()->play_once(refname);
- }
+// >>> Beware: must pass a (new) object to the (add) method,
+// >>> because the (remove) method is going to do a (delete)
+// >>> whether that's what you want or not.
+ SGSoundSample *simple = new SGSoundSample(&buf, len, 8000);
+ simple->set_volume(volume);
+ _sgr->add(simple, refname);
+ _sgr->play(refname, repeating);
} catch ( sg_io_exception &e ) {
- SG_LOG(SG_GENERAL, SG_ALERT, e.getFormattedMessage());
+ SG_LOG(SG_ATC, SG_ALERT, e.getFormattedMessage());
}
}
- delete[] buf;
}
- #endif // ENABLE_AUDIO_SUPPORT
+#endif // ENABLE_AUDIO_SUPPORT
if(!_voice) {
// first rip the underscores and the pause hints out of the string - these are for the convienience of the voice parser
for(unsigned int i = 0; i < msg.length(); ++i) {
if(_playing) {
if(_voice) {
#ifdef ENABLE_AUDIO_SUPPORT
- globals->get_soundmgr()->stop(refname);
- globals->get_soundmgr()->remove(refname);
+ _sgr->stop(refname);
+ _sgr->remove(refname);
#endif
}
_playing = false;
ostream& operator << (ostream& os, atc_type atc) {
switch(atc) {
- case(INVALID): return(os << "INVALID");
- case(ATIS): return(os << "ATIS");
- case(GROUND): return(os << "GROUND");
- case(TOWER): return(os << "TOWER");
+ case(AWOS): return(os << "AWOS");
+ case(ATIS): return(os << "ATIS");
+ case(GROUND): return(os << "GROUND");
+ case(TOWER): return(os << "TOWER");
case(APPROACH): return(os << "APPROACH");
case(DEPARTURE): return(os << "DEPARTURE");
- case(ENROUTE): return(os << "ENROUTE");
+ case(ENROUTE): return(os << "ENROUTE");
+ case(INVALID): return(os << "INVALID");
}
return(os << "ERROR - Unknown switch in atc_type operator << ");
}
+
+std::istream& operator >> ( std::istream& fin, ATCData& a )
+{
+ double f;
+ char ch;
+ char tp;
+
+ fin >> tp;
+
+ switch(tp) {
+ case 'I':
+ a.type = ATIS;
+ break;
+ case 'T':
+ a.type = TOWER;
+ break;
+ case 'G':
+ a.type = GROUND;
+ break;
+ case 'A':
+ a.type = APPROACH;
+ break;
+ case '[':
+ a.type = INVALID;
+ return fin >> skipeol;
+ default:
+ SG_LOG(SG_ATC, SG_ALERT, "Warning - unknown type \'" << tp << "\' found whilst reading ATC frequency data!\n");
+ a.type = INVALID;
+ return fin >> skipeol;
+ }
+
+ double lat, lon, elev;
+
+ fin >> lat >> lon >> elev >> f >> a.range >> a.ident;
+ a.geod = SGGeod::fromDegM(lon, lat, elev);
+ a.name = "";
+ fin >> ch;
+ if(ch != '"') a.name += ch;
+ while(1) {
+ //in >> noskipws
+ fin.unsetf(std::ios::skipws);
+ fin >> ch;
+ if((ch == '"') || (ch == 0x0A)) {
+ break;
+ } // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the "
+ a.name += ch;
+ }
+ fin.setf(std::ios::skipws);
+ //cout << "Comm name = " << a.name << '\n';
+
+ a.freq = (int)(f*100.0 + 0.5);
+
+ // cout << a.ident << endl;
+
+ // generate cartesian coordinates
+ a.cart = SGVec3d::fromGeod(a.geod);
+ return fin >> skipeol;
+}
+