-// Sounds better with a pause in there:
- transmission += PAUSE;
-
- int did_some(0);
- int did_ceiling(0);
-
- for (int layer = 0; layer <= 4; layer++) {
- snprintf(buf, bs, "/environment/clouds/layer[%i]/coverage", layer);
- string coverage = fgGetString(buf);
- if (coverage == clear) continue;
- snprintf(buf, bs, "/environment/clouds/layer[%i]/thickness-ft", layer);
- if (fgGetDouble(buf) == 0) continue;
- snprintf(buf, bs, "/environment/clouds/layer[%i]/elevation-ft", layer);
- double ceiling = int(fgGetDouble(buf) - _geod.getElevationFt());
- if (ceiling > 12000) continue;
-
-// BEWARE: At the present time, the environment system has no
-// way (so far as I know) to represent a "thin broken" or
-// "thin overcast" layer. If/when such things are implemented
-// in the environment system, code will have to be written here
-// to handle them.
-
-// First, do the prefix if any:
- if (coverage == scattered || coverage == few) {
- if (!did_some) {
- transmission += " " + Sky_condition + ": ";
- did_some++;
- }
- } else /* must be a ceiling */ if (!did_ceiling) {
- transmission += " " + Ceiling + ": ";
- did_ceiling++;
- did_some++;
- } else {
- transmission += " "; // no prefix required
- }
- int cig00 = int(SGMiscd::round(ceiling/100)); // hundreds of feet
- if (cig00) {
- int cig000 = cig00/10;
- cig00 -= cig000*10; // just the hundreds digit
- if (cig000) {
- snprintf(buf, bs, "%i", cig000);
- transmission += ConvertNumToSpokenDigits(buf);
- transmission += " " + thousand + " ";
+ // TODO check whether "no significant change" applies - somehow...
+ transmission += No_sig + BRK; // sounds better with festival than "nosig"
+
+ // some warnings may appear at the very end
+ genWarnings(1);
+
+ if ((!_report.concise)|| _report.US_CA)
+ transmission += Advise_on_initial_contact_you_have_information;
+ else
+ transmission += information;
+ transmission += " " + phonetic_seq_string + ".";
+
+ if (!_report.US_CA)
+ {
+ // non-US ATIS ends with "out!"
+ transmission += " " + out;
+ }
+
+ // Pause in between two messages must be 3-5 seconds
+ transmission += " / / / / / / / / ";
+
+ /////////////////////////////////////////////////////////
+ // post-processing
+ /////////////////////////////////////////////////////////
+ transmission_readable = transmission;
+
+ // Take the previous readable string and munge it to
+ // be relatively-more acceptable to the primitive tts system.
+ // Note that : ; and . are among the token-delimiters recognized
+ // by the tts system.
+ for (size_t where;;) {
+ where = transmission.find_first_of(":.");
+ if (where == string::npos) break;
+ transmission.replace(where, 1, PAUSE);
+ }
+
+ return true;
+}
+
+/** Collect (most of) the data and create report.
+ */
+void FGATIS::createReport(const FGAirport* apt)
+{
+ // check country
+ _report.US_CA = Apt_US_CA(ident);
+
+ // switch to enable brief ATIS message (really depends on the airport)
+ _report.concise = fgGetBool("/sim/atis/concise-reports", false);
+
+ _report.ils = false;
+
+ // time information
+ string time_str = fgGetString("sim/time/gmt-string");
+ // Warning - this is fragile if the time string format changes
+ _report.hours = time_str.substr(0,2).c_str();
+ _report.mins = time_str.substr(3,2).c_str();
+
+ // pressure/temperature
+ {
+ double press, temp;
+ double Tsl = fgGetDouble("/environment/temperature-sea-level-degc");
+ tie(press, temp) = PT_vs_hpt(_geod.getElevationM(), _report.psl*atmodel::inHg, Tsl + atmodel::freezing);
+ #if 0
+ SG_LOG(SG_ATC, SG_ALERT, "Field P: " << press << " T: " << temp);
+ SG_LOG(SG_ATC, SG_ALERT, "based on elev " << elev
+ << " Psl: " << Psl
+ << " Tsl: " << Tsl);
+ #endif
+ _report.qnh = FGAtmo().QNH(_geod.getElevationM(), press);
+ _report.temp = int(SGMiscd::round(FGAtmo().fake_T_vs_a_us(_geod.getElevationFt(), Tsl)));
+ }
+
+ // dew point
+ double dpsl = fgGetDouble("/environment/dewpoint-sea-level-degc");
+ _report.dewpoint = int(SGMiscd::round(FGAtmo().fake_dp_vs_a_us(dpsl, _geod.getElevationFt())));
+
+ // precipitation
+ _report.rain_norm = fgGetDouble("environment/rain-norm");
+ _report.snow_norm = fgGetDouble("environment/snow-norm");
+
+ // NOTAMs
+ _report.notam = 0;
+ if (fgGetBool("/sim/atis/random-notams", true))
+ {
+ _report.notam = fgGetInt("/sim/atis/notam-id", 0); // fixed NOTAM for testing/debugging only
+ if (!_report.notam)
+ {
+ // select pseudo-random NOTAM (changes every hour, differs for each airport)
+ char cksum = 0;
+ string name = apt->getName();
+ for(string::iterator p = name.begin(); p != name.end(); p++)
+ {
+ cksum += *p;
+ }
+ cksum ^= atoi(_report.hours.c_str());
+ _report.notam = cksum % 12; // 12 intentionally higher than number of available NOTAMs, so they don't appear too often
+ // debugging
+ //fgSetInt("/sim/atis/selected-notam", _report.notam);
+ }
+ }
+}
+
+void FGATIS::genPrecipitationInfo(void)
+{
+ using namespace lex;
+
+ double rain_norm = _report.rain_norm;
+ double snow_norm = _report.snow_norm;
+
+ // report rain or snow - which ever is worse
+ if (rain_norm > 0.7)
+ transmission += heavy + " " + rain + BRK;
+ else
+ if (snow_norm > 0.7)
+ transmission += heavy + " " + snow + BRK;
+ else
+ if (rain_norm > 0.4)
+ transmission += moderate + " " + rain + BRK;
+ else
+ if (snow_norm > 0.4)
+ transmission += moderate + " " + snow + BRK;
+ else
+ if (rain_norm > 0.2)
+ transmission += light + " " + rain + BRK;
+ else
+ if (snow_norm > 0.05)
+ transmission += light + " " + snow + BRK;
+ else
+ if (rain_norm > 0.05)
+ transmission += light + " " + drizzle + BRK;
+}
+
+void FGATIS::genTimeInfo(void)
+{
+ using namespace lex;
+
+ if (!_report.concise)
+ transmission += Time + " ";
+
+ // speak each digit separately:
+ transmission += ConvertNumToSpokenDigits(_report.hours + _report.mins);
+ transmission += " " + zulu + BRK;
+}
+
+bool FGATIS::genVisibilityInfo(string& vis_info)
+{
+ using namespace lex;
+
+ double visibility = fgGetDouble("/environment/config/boundary/entry[0]/visibility-m");
+ bool IsMax = false;
+ bool USE_KM = !_report.US_CA;
+
+ vis_info += Visibility + ": ";
+ if (USE_KM)
+ {
+ visibility /= 1000.0; // convert to statute miles
+ // integer kilometers
+ if (visibility >= 9.5)
+ {
+ visibility = 10;
+ IsMax = true;
+ }
+ snprintf(buf, sizeof(buf), "%i", int(.5 + visibility));
+ // "kelometers" instead of "kilometers" since the festival language generator doesn't get it right otherwise
+ vis_info += ConvertNumToSpokenDigits(buf) + " " + kelometers;
+ }
+ else
+ {
+ visibility /= atmodel::sm; // convert to statute miles
+ if (visibility < 0.25) {
+ vis_info += less_than_one_quarter;
+ } else if (visibility < 0.5) {
+ vis_info += one_quarter;
+ } else if (visibility < 0.75) {
+ vis_info += one_half;
+ } else if (visibility < 1.0) {
+ vis_info += three_quarters;
+ } else if (visibility >= 1.5 && visibility < 2.0) {
+ vis_info += one_and_one_half;
+ } else {
+ // integer miles
+ if (visibility > 9.5)
+ {
+ visibility = 10;
+ IsMax = true;
+ }
+ snprintf(buf, sizeof(buf), "%i", int(.5 + visibility));
+ vis_info += ConvertNumToSpokenDigits(buf);
+ }
+ }
+ if (IsMax)
+ {
+ vis_info += " " + or_more;
+ }
+ vis_info += BRK;
+ return !IsMax;
+}
+
+void FGATIS::addTemperature(int Temp)
+{
+ if (Temp < 0)
+ transmission += lex::minus + " ";
+ else
+ if (Temp > 0)
+ {
+ transmission += lex::plus + " ";
+ }
+ snprintf(buf, sizeof(buf), "%i", abs(Temp));
+ transmission += ConvertNumToSpokenDigits(buf);
+ if (_report.US_CA)
+ transmission += " " + lex::Celsius;
+}
+
+void FGATIS::genTemperatureInfo()
+{
+ // temperature
+ transmission += lex::Temperature + ": ";
+ addTemperature(_report.temp);
+
+ // dewpoint
+ transmission += BRK + lex::Dewpoint + ": ";
+ addTemperature(_report.dewpoint);
+
+ transmission += BRK;
+}
+
+bool FGATIS::genCloudInfo(string& cloud_info)
+{
+ using namespace lex;
+
+ bool did_some = false;
+ bool did_ceiling = false;
+
+ for (int layer = 0; layer <= 4; layer++) {
+ snprintf(buf, sizeof(buf), "/environment/clouds/layer[%i]/coverage", layer);
+ string coverage = fgGetString(buf);
+ if (coverage == clear)
+ continue;
+ snprintf(buf, sizeof(buf), "/environment/clouds/layer[%i]/thickness-ft", layer);
+ if (fgGetDouble(buf) == 0)
+ continue;
+ snprintf(buf, sizeof(buf), "/environment/clouds/layer[%i]/elevation-ft", layer);
+ double ceiling = int(fgGetDouble(buf) - _geod.getElevationFt());
+ if (ceiling > 12000)
+ continue;
+
+ // BEWARE: At the present time, the environment system has no
+ // way (so far as I know) to represent a "thin broken" or
+ // "thin overcast" layer. If/when such things are implemented
+ // in the environment system, code will have to be written here
+ // to handle them.
+
+ // First, do the prefix if any:
+ if (coverage == scattered || coverage == few) {
+ if (!did_some) {
+ if (_report.concise)
+ cloud_info += Clouds + ": ";
+ else
+ cloud_info += Sky_condition + ": ";
+ did_some = true;
+ }
+ } else /* must be a ceiling */ if (!did_ceiling) {
+ cloud_info += " " + Ceiling + ": ";
+ did_ceiling = true;
+ did_some = true;
+ } else {
+ cloud_info += " "; // no prefix required