From 078573629d168310d17805e76b48ed3251bbde97 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 11 Jun 2021 23:41:37 +0200 Subject: [PATCH] SRS - added coordinate - added google --- Moose Development/Moose/Functional/Range.lua | 6 +- Moose Development/Moose/Ops/ATIS.lua | 3 + Moose Development/Moose/Sound/SRS.lua | 89 +++++++++++++++---- Moose Development/Moose/Sound/SoundOutput.lua | 48 +++++++++- Moose Development/Moose/Wrapper/Airbase.lua | 83 +++++++++++------ 5 files changed, 180 insertions(+), 49 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index fc850743c..7ba9dcfc7 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -36,7 +36,7 @@ -- -- === -- --- ## Sound files: Check out the pinned messages in the Moose discord *#func-range* channel. +-- ## Sound files: [MOOSE Sound Files](https://github.com/FlightControl-Master/MOOSE_SOUND/releases) -- -- === -- @@ -91,9 +91,9 @@ -- @field #boolean defaultsmokebomb If true, initialize player settings to smoke bomb. -- @field #boolean autosave If true, automatically save results every X seconds. -- @field #number instructorfreq Frequency on which the range control transmitts. --- @field Core.RadioQueue#RADIOQUEUE instructor Instructor radio queue. +-- @field Sound.RadioQueue#RADIOQUEUE instructor Instructor radio queue. -- @field #number rangecontrolfreq Frequency on which the range control transmitts. --- @field Core.RadioQueue#RADIOQUEUE rangecontrol Range control radio queue. +-- @field Sound.RadioQueue#RADIOQUEUE rangecontrol Range control radio queue. -- @field #string rangecontrolrelayname Name of relay unit. -- @field #string instructorrelayname Name of relay unit. -- @field #string soundpath Path inside miz file where the sound files are located. Default is "Range Soundfiles/". diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index 92683b48e..65b0475e5 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -2156,6 +2156,9 @@ function ATIS:onafterBroadcast(From, Event, To) -- VOR if self.vor then subtitle=string.format("VOR frequency %.2f MHz", self.vor) + if self.useSRS then + subtitle=string.format("V O R frequency %.2f MHz", self.vor) + end if not self.useSRS then self:Transmission(ATIS.Sound.VORFrequency, 1.0, subtitle) local f=string.format("%.2f", self.vor) diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index 04b785b6c..d4253971c 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -17,7 +17,7 @@ -- -- === -- --- ## Sound files: None yet. +-- ## Sound files: [MOOSE Sound Files](https://github.com/FlightControl-Master/MOOSE_SOUND/releases) -- -- === -- @@ -44,6 +44,7 @@ -- @field #string voice Specifc voce. -- @field Core.Point#COORDINATE coordinate Coordinate from where the transmission is send. -- @field #string path Path to the SRS exe. This includes the final slash "/". +-- @field #string google Full path google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json". -- @extends Core.Base#BASE --- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde @@ -91,6 +92,10 @@ -- -- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`. -- Note that this must be installed on your windows system. +-- +-- ## Set Coordinate +-- +-- Use @{#MSRS.SetCoordinate} to define the origin from where the transmission is broadcasted. -- -- @field #MSRS MSRS = { @@ -107,9 +112,6 @@ MSRS = { volume = 1, speed = 1, coordinate = nil, - latitude = nil, - longitude = nil, - altitude = nil, } --- MSRS class version. @@ -121,8 +123,8 @@ MSRS.version="0.0.3" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: Add functions to add/remove freqs and modulations. --- TODO: Add coordinate. --- TODO: Add google. +-- DONE: Add coordinate. +-- DONE: Add google. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -290,15 +292,41 @@ function MSRS:SetVoice(Voice) return self end ---- Opens a new command window and prints the SRS STTS help. +--- Set the coordinate from which the transmissions will be broadcasted. +-- @param #MSRS self +-- @param Core.Point#COORDINATE Coordinate Origin of the transmission. +-- @return #MSRS self +function MSRS:SetCoordinate(Coordinate) + + self.coordinate=Coordinate + + return self +end + +--- Use google text-to-speech. +-- @param #MSRS self +-- @param PathToCredentials Full path to the google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json". +-- @return #MSRS self +function MSRS:SetGoogle(PathToCredentials) + + self.google=PathToCredentials + + return self +end + +--- Print SRS STTS help to DCS log file. -- @param #MSRS self -- @return #MSRS self function MSRS:Help() + + -- Path and exe. local path=self:GetPath() or STTS.DIRECTORY local exe=STTS.EXECUTABLE or "DCS-SR-ExternalAudio.exe" + -- Text file for output. local filename = os.getenv('TMP') .. "\\MSRS-help-"..STTS.uuid()..".txt" + -- Print help. local command=string.format("%s/%s --help > %s", path, exe, filename) os.execute(command) @@ -306,7 +334,11 @@ function MSRS:Help() local data=f:read("*all") f:close() + -- Print to log file. + env.info("SRS STTS help output:") + env.info("======================================================================") env.info(data) + env.info("======================================================================") return self end @@ -371,6 +403,7 @@ function MSRS:PlaySoundText(SoundText, Delay) -- Append text. command=command..string.format(" --text=\"%s\"", tostring(SoundText.text)) + -- Execute command. self:_ExecCommand(command) --[[ @@ -405,6 +438,7 @@ function MSRS:PlayText(Text, Delay) -- Append text. command=command..string.format(" --text=\"%s\"", tostring(Text)) + -- Execute command. self:_ExecCommand(command) --[[ @@ -474,9 +508,8 @@ function MSRS:PlayTextFile(TextFile, Delay) -- Count length of command. local l=string.len(command) - -- Execute SRS command. + -- Execute command. self:_ExecCommand(command) --- local x=os.execute(command) end @@ -491,19 +524,20 @@ end --- Execute SRS command to play sound using the `DCS-SR-ExternalAudio.exe`. -- @param #MSRS self -- @param #string command Command to executer --- @return #string Command. +-- @return #number Return value of os.execute() command. function MSRS:_ExecCommand(command) -- Create a tmp file. - local filename = os.getenv('TMP') .. "\\MSRS-"..STTS.uuid()..".bat" + local filename=os.getenv('TMP').."\\MSRS-"..STTS.uuid()..".bat" - local script = io.open(filename, "w+") + local script=io.open(filename, "w+") script:write(command.." && exit") script:close() -- Play command. command=string.format('start /b "" "%s"', filename) + local res=nil if true then -- Create a tmp file. @@ -525,7 +559,7 @@ function MSRS:_ExecCommand(command) self:T("MSRS execute VBS command="..runvbs) -- Play file in 0.01 seconds - os.execute(runvbs) + res=os.execute(runvbs) -- Remove file in 1 second. timer.scheduleFunction(os.remove, filename, timer.getTime()+1) @@ -537,8 +571,8 @@ function MSRS:_ExecCommand(command) -- Debug output. self:T("MSRS execute command="..command) - -- Play file in 0.05 seconds - timer.scheduleFunction(os.execute, command, timer.getTime()+0.01) + -- Execute command + res=os.execute(command) -- Remove file in 1 second. timer.scheduleFunction(os.remove, filename, timer.getTime()+1) @@ -549,6 +583,19 @@ function MSRS:_ExecCommand(command) return res end +--- Get lat, long and alt from coordinate. +-- @param #MSRS self +-- @param Core.Point#Coordinate Coordinate Coordinate. Can also be a DCS#Vec3. +-- @return #number Latitude. +-- @return #number Longitude. +-- @return #number Altitude. +function MSRS:_GetLatLongAlt(Coordinate) + + local lat, lon, alt=coord.LOtoLL(Coordinate) + + return lat, lon, math.floor(alt) +end + --- Get SRS command to play sound using the `DCS-SR-ExternalAudio.exe`. -- @param #MSRS self @@ -588,6 +635,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp --local command=string.format('start /b "" /d "%s" "%s" -f %s -m %s -c %s -p %s -n "%s" > bla.txt', path, exe, freqs, modus, coal, port, "ROBOT") + -- Command. local command=string.format('%s/%s -f %s -m %s -c %s -p %s -n "%s"', path, exe, freqs, modus, coal, port, "ROBOT") -- Set voice or gender/culture. @@ -605,6 +653,17 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp end end + -- Set coordinate. + if self.coordinate then + local lat,lon,alt=self:_GetLatLongAlt(self.coordinate) + command=command..string.format(" -L %.4f -O %.4f -A %d", lat, lon, alt) + end + + -- Set google. + if self.google then + command=command..string.format(' -G "%s"', self.google) + end + -- Debug output. self:T("MSRS command="..command) diff --git a/Moose Development/Moose/Sound/SoundOutput.lua b/Moose Development/Moose/Sound/SoundOutput.lua index f581e9fe3..01fd00483 100644 --- a/Moose Development/Moose/Sound/SoundOutput.lua +++ b/Moose Development/Moose/Sound/SoundOutput.lua @@ -5,7 +5,7 @@ -- ## Features: -- -- * Create a SOUNDFILE object (mp3 or ogg) to be played via DCS or SRS transmissions --- * Create a SOUNDTEXT object for text-to-speech output vis SRS Simple-Text-To-Speech +-- * Create a SOUNDTEXT object for text-to-speech output vis SRS Simple-Text-To-Speech (STTS) -- -- === -- @@ -29,7 +29,7 @@ do -- Sound Base -- @extends Core.Base#BASE - --- Basic sound output inherited by other classes. + --- Basic sound output inherited by other classes suche as SOUNDFILE and SOUNDTEXT. -- -- This class is **not** meant to be used by "ordinary" users. -- @@ -51,6 +51,50 @@ do -- Sound Base return self end + --- Function returns estimated speech time in seconds. + -- Assumptions for time calc: 100 Words per min, avarage of 5 letters for english word so + -- + -- * 5 chars * 100wpm = 500 characters per min = 8.3 chars per second + -- + -- So lengh of msg / 8.3 = number of seconds needed to read it. rounded down to 8 chars per sec map function: + -- + -- * (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min + -- + -- @param #string Text The text string to analyze. + -- @param #number Speed Speed factor. Default 1. + -- @param #boolean isGoogle If true, google text-to-speech is used. + function SOUNDBASE:GetSpeechTime(length,speed,isGoogle) + + local maxRateRatio = 3 + + speed = speed or 1.0 + isGoogle = isGoogle or false + + local speedFactor = 1.0 + if isGoogle then + speedFactor = speed + else + if speed ~= 0 then + speedFactor = math.abs(speed) * (maxRateRatio - 1) / 10 + 1 + end + if speed < 0 then + speedFactor = 1/speedFactor + end + end + + -- Words per minute. + local wpm = math.ceil(100 * speedFactor) + + -- Characters per second. + local cps = math.floor((wpm * 5)/60) + + if type(length) == "string" then + length = string.len(length) + end + + return math.ceil(length/cps) + end + end diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 55f5cc632..615cf6870 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -336,41 +336,53 @@ AIRBASE.TheChannel = { -- * AIRBASE.Syria.Incirlik -- * AIRBASE.Syria.Damascus -- * AIRBASE.Syria.Bassel_Al_Assad +-- * AIRBASE.Syria.Rosh_Pina -- * AIRBASE.Syria.Aleppo --- * AIRBASE.Syria.Qabr_as_Sitt +-- * AIRBASE.Syria.Al_Qusayr -- * AIRBASE.Syria.Wujah_Al_Hajar -- * AIRBASE.Syria.Al_Dumayr +-- * AIRBASE.Syria.Gazipasa +-- * AIRBASE.Syria.Ru_Convoy_4 -- * AIRBASE.Syria.Hatay +-- * AIRBASE.Syria.Nicosia +-- * AIRBASE.Syria.Pinarbashi +-- * AIRBASE.Syria.Paphos +-- * AIRBASE.Syria.Kingsfield +-- * AIRBASE.Syria.Tha'lah -- * AIRBASE.Syria.Haifa -- * AIRBASE.Syria.Khalkhalah -- * AIRBASE.Syria.Megiddo +-- * AIRBASE.Syria.Lakatamia -- * AIRBASE.Syria.Rayak +-- * AIRBASE.Syria.Larnaca -- * AIRBASE.Syria.Mezzeh --- * AIRBASE.Syria.King_Hussein_Air_College --- * AIRBASE.Syria.Jirah +-- * AIRBASE.Syria.Gecitkale +-- * AIRBASE.Syria.Akrotiri +-- * AIRBASE.Syria.Naqoura +-- * AIRBASE.Syria.Gaziantep +-- * AIRBASE.Syria.CVN_71 +-- * AIRBASE.Syria.Sayqal +-- * AIRBASE.Syria.Tiyas +-- * AIRBASE.Syria.Shayrat -- * AIRBASE.Syria.Taftanaz +-- * AIRBASE.Syria.H4 +-- * AIRBASE.Syria.King_Hussein_Air_College -- * AIRBASE.Syria.Rene_Mouawad +-- * AIRBASE.Syria.Jirah -- * AIRBASE.Syria.Ramat_David +-- * AIRBASE.Syria.Qabr_as_Sitt -- * AIRBASE.Syria.Minakh -- * AIRBASE.Syria.Adana_Sakirpasa --- * AIRBASE.Syria.Marj_as_Sultan_South --- * AIRBASE.Syria.Hama --- * AIRBASE.Syria.Al_Qusayr -- * AIRBASE.Syria.Palmyra +-- * AIRBASE.Syria.Hama +-- * AIRBASE.Syria.Ercan +-- * AIRBASE.Syria.Marj_as_Sultan_South -- * AIRBASE.Syria.Tabqa -- * AIRBASE.Syria.Beirut_Rafic_Hariri -- * AIRBASE.Syria.An_Nasiriyah -- * AIRBASE.Syria.Abu_al_Duhur --- * AIRBASE.Syria.H4 --- * AIRBASE.Syria.Gaziantep --- * AIRBASE.Syria.Rosh_Pina --- * AIRBASE.Syria.Sayqal --- * AIRBASE.Syria.Shayrat --- * AIRBASE.Syria.Tiyas --- * AIRBASE.Syria.Tha_lah --- * AIRBASE.Syria.Naqoura -- --- @field Syria +--@field Syria AIRBASE.Syria={ ["Kuweires"]="Kuweires", ["Marj_Ruhayyil"]="Marj Ruhayyil", @@ -380,42 +392,55 @@ AIRBASE.Syria={ ["Incirlik"]="Incirlik", ["Damascus"]="Damascus", ["Bassel_Al_Assad"]="Bassel Al-Assad", + ["Rosh_Pina"]="Rosh Pina", ["Aleppo"]="Aleppo", - ["Qabr_as_Sitt"]="Qabr as Sitt", + ["Al_Qusayr"]="Al Qusayr", ["Wujah_Al_Hajar"]="Wujah Al Hajar", ["Al_Dumayr"]="Al-Dumayr", + ["Gazipasa"]="Gazipasa", + ["Ru_Convoy_4"]="Ru Convoy-4", ["Hatay"]="Hatay", + ["Nicosia"]="Nicosia", + ["Pinarbashi"]="Pinarbashi", + ["Paphos"]="Paphos", + ["Kingsfield"]="Kingsfield", + ["Tha'lah"]="Tha'lah", ["Haifa"]="Haifa", ["Khalkhalah"]="Khalkhalah", ["Megiddo"]="Megiddo", + ["Lakatamia"]="Lakatamia", ["Rayak"]="Rayak", + ["Larnaca"]="Larnaca", ["Mezzeh"]="Mezzeh", - ["King_Hussein_Air_College"]="King Hussein Air College", - ["Jirah"]="Jirah", + ["Gecitkale"]="Gecitkale", + ["Akrotiri"]="Akrotiri", + ["Naqoura"]="Naqoura", + ["Gaziantep"]="Gaziantep", + ["CVN_71"]="CVN-71", + ["Sayqal"]="Sayqal", + ["Tiyas"]="Tiyas", + ["Shayrat"]="Shayrat", ["Taftanaz"]="Taftanaz", + ["H4"]="H4", + ["King_Hussein_Air_College"]="King Hussein Air College", ["Rene_Mouawad"]="Rene Mouawad", + ["Jirah"]="Jirah", ["Ramat_David"]="Ramat David", + ["Qabr_as_Sitt"]="Qabr as Sitt", ["Minakh"]="Minakh", ["Adana_Sakirpasa"]="Adana Sakirpasa", - ["Marj_as_Sultan_South"]="Marj as Sultan South", - ["Hama"]="Hama", - ["Al_Qusayr"]="Al Qusayr", ["Palmyra"]="Palmyra", + ["Hama"]="Hama", + ["Ercan"]="Ercan", + ["Marj_as_Sultan_South"]="Marj as Sultan South", ["Tabqa"]="Tabqa", ["Beirut_Rafic_Hariri"]="Beirut-Rafic Hariri", ["An_Nasiriyah"]="An Nasiriyah", ["Abu_al_Duhur"]="Abu al-Duhur", - ["H4"]="H4", - ["Gaziantep"]="Gaziantep", - ["Rosh_Pina"]="Rosh Pina", - ["Sayqal"]="Sayqal", - ["Shayrat"]="Shayrat", - ["Tiyas"]="Tiyas", - ["Tha_lah"]="Tha'lah", - ["Naqoura"]="Naqoura", } + --- Airbases of the Mariana Islands map. -- -- * AIRBASE.MarianaIslands.Rota_International_Airport