Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-07-19 23:16:59 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-07-19 23:16:59 +1000
commit1f038540a59ff96aed3cda901449a298b6f1c11c (patch)
treee0768bc861938423c74d6e2abb9ef74357574238
parentd682b164aa87435183a5ad3196b25b5ff8a5ad18 (diff)
Port in the voice settings menu
-rw-r--r--assets/opensb/interface/opensb/voicechat/activity.pngbin0 -> 201 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/activityback.pngbin0 -> 326 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/bigbutton.pngbin0 -> 223 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/bigbuttonback.pngbin0 -> 496 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/body.pngbin0 -> 1049 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/device.pngbin0 -> 195 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/deviceback.pngbin0 -> 447 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/footer.pngbin0 -> 250 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/header.pngbin0 -> 569 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/indicator/back.png (renamed from assets/opensb/interface/voicechat/indicator/back.png)bin611 -> 611 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/indicator/front.png (renamed from assets/opensb/interface/voicechat/indicator/front.png)bin1526 -> 1526 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/indicator/front_muted.png (renamed from assets/opensb/interface/voicechat/indicator/front_muted.png)bin1620 -> 1620 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/pushtotalk.pngbin0 -> 207 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/pushtotalkback.pngbin0 -> 378 bytes
-rw-r--r--assets/opensb/interface/opensb/voicechat/voicechat.config174
-rw-r--r--assets/opensb/interface/opensb/voicechat/voicechat.lua227
-rw-r--r--assets/opensb/interface/optionsmenu/body_blank.pngbin0 -> 1017 bytes
-rw-r--r--assets/opensb/interface/optionsmenu/duocontrolsbutton.pngbin0 -> 159 bytes
-rw-r--r--assets/opensb/interface/optionsmenu/duocontrolsbuttonhover.pngbin0 -> 154 bytes
-rw-r--r--assets/opensb/interface/optionsmenu/optionsmenu.config.patch40
-rw-r--r--assets/opensb/interface/optionsmenu/tricontrolsbutton.png (renamed from assets/opensb/interface/optionsmenu/controlsbutton.png)bin213 -> 213 bytes
-rw-r--r--assets/opensb/interface/optionsmenu/tricontrolsbuttonhover.png (renamed from assets/opensb/interface/optionsmenu/controlsbuttonhover.png)bin213 -> 213 bytes
-rw-r--r--assets/opensb/scripts/opensb/universeclient/voicemanager.lua2
-rw-r--r--source/client/StarClientApplication.cpp9
-rw-r--r--source/frontend/CMakeLists.txt2
-rw-r--r--source/frontend/StarMainMixer.cpp3
-rw-r--r--source/frontend/StarOptionsMenu.cpp14
-rw-r--r--source/frontend/StarOptionsMenu.hpp3
-rw-r--r--source/frontend/StarVoice.cpp52
-rw-r--r--source/frontend/StarVoice.hpp2
-rw-r--r--source/frontend/StarVoiceLuaBindings.cpp12
-rw-r--r--source/frontend/StarVoiceLuaBindings.hpp2
-rw-r--r--source/frontend/StarVoiceSettingsMenu.cpp23
-rw-r--r--source/frontend/StarVoiceSettingsMenu.hpp24
-rw-r--r--source/windowing/StarPane.cpp4
35 files changed, 553 insertions, 40 deletions
diff --git a/assets/opensb/interface/opensb/voicechat/activity.png b/assets/opensb/interface/opensb/voicechat/activity.png
new file mode 100644
index 0000000..20286e7
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/activity.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/activityback.png b/assets/opensb/interface/opensb/voicechat/activityback.png
new file mode 100644
index 0000000..8308c3d
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/activityback.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/bigbutton.png b/assets/opensb/interface/opensb/voicechat/bigbutton.png
new file mode 100644
index 0000000..2908feb
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/bigbutton.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/bigbuttonback.png b/assets/opensb/interface/opensb/voicechat/bigbuttonback.png
new file mode 100644
index 0000000..fe10770
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/bigbuttonback.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/body.png b/assets/opensb/interface/opensb/voicechat/body.png
new file mode 100644
index 0000000..37f73a8
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/body.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/device.png b/assets/opensb/interface/opensb/voicechat/device.png
new file mode 100644
index 0000000..b686b60
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/device.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/deviceback.png b/assets/opensb/interface/opensb/voicechat/deviceback.png
new file mode 100644
index 0000000..b07990b
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/deviceback.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/footer.png b/assets/opensb/interface/opensb/voicechat/footer.png
new file mode 100644
index 0000000..39069c9
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/footer.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/header.png b/assets/opensb/interface/opensb/voicechat/header.png
new file mode 100644
index 0000000..a1be25d
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/header.png
Binary files differ
diff --git a/assets/opensb/interface/voicechat/indicator/back.png b/assets/opensb/interface/opensb/voicechat/indicator/back.png
index 869ed1c..869ed1c 100644
--- a/assets/opensb/interface/voicechat/indicator/back.png
+++ b/assets/opensb/interface/opensb/voicechat/indicator/back.png
Binary files differ
diff --git a/assets/opensb/interface/voicechat/indicator/front.png b/assets/opensb/interface/opensb/voicechat/indicator/front.png
index ff32e38..ff32e38 100644
--- a/assets/opensb/interface/voicechat/indicator/front.png
+++ b/assets/opensb/interface/opensb/voicechat/indicator/front.png
Binary files differ
diff --git a/assets/opensb/interface/voicechat/indicator/front_muted.png b/assets/opensb/interface/opensb/voicechat/indicator/front_muted.png
index be18587..be18587 100644
--- a/assets/opensb/interface/voicechat/indicator/front_muted.png
+++ b/assets/opensb/interface/opensb/voicechat/indicator/front_muted.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/pushtotalk.png b/assets/opensb/interface/opensb/voicechat/pushtotalk.png
new file mode 100644
index 0000000..6d38221
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/pushtotalk.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/pushtotalkback.png b/assets/opensb/interface/opensb/voicechat/pushtotalkback.png
new file mode 100644
index 0000000..3cc3a73
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/pushtotalkback.png
Binary files differ
diff --git a/assets/opensb/interface/opensb/voicechat/voicechat.config b/assets/opensb/interface/opensb/voicechat/voicechat.config
new file mode 100644
index 0000000..20e88d9
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/voicechat.config
@@ -0,0 +1,174 @@
+{
+ "scripts" : ["/interface/opensb/voicechat/voicechat.lua"],
+ "scriptDelta" : 1,
+ "scriptWidgetCallbacks" : [
+ "selectDevice",
+ "voiceToggle",
+ "switchVoiceMode"
+ ],
+
+ "canvasClickCallbacks" : {
+ "inputVolume" : "inputVolume",
+ "voiceVolume" : "voiceVolume",
+ "threshold" : "threshold"
+ },
+
+ "gui" : {
+ "panefeature" : {
+ "type" : "panefeature",
+ "positionLocked" : false
+ },
+ "background" : {
+ "type" : "background",
+ "fileHeader" : "/interface/opensb/voicechat/header.png",
+ "fileBody" : "/interface/opensb/voicechat/body.png",
+ "fileFooter" : "/interface/opensb/voicechat/footer.png"
+ },
+
+ "voiceVolumeLabel" : {
+ "type" : "label",
+ "value" : "THEIR VOLUME",
+ "position" : [26, 178],
+ "wrapWidth" : 48,
+ "lineSpacing" : 0.75,
+ "hAnchor" : "mid",
+ "vAnchor" : "mid"
+ },
+ "voiceVolume" : {
+ "type" : "canvas",
+ "rect" : [50, 171, 247, 186],
+ "captureMouseEvents" : true,
+ "captureKeyboardEvents" : false
+ },
+
+ "inputVolumeLabel" : {
+ "type" : "label",
+ "value" : "YOUR VOLUME",
+ "position" : [26, 158],
+ "wrapWidth" : 48,
+ "lineSpacing" : 0.75,
+ "hAnchor" : "mid",
+ "vAnchor" : "mid"
+ },
+ "inputVolume" : {
+ "type" : "canvas",
+ "rect" : [50, 151, 247, 166],
+ "captureMouseEvents" : true,
+ "captureKeyboardEvents" : false
+ },
+
+ "enableVoiceToggleBack" : {
+ "type" : "image",
+ "file" : "/interface/opensb/voicechat/bigbuttonback.png?multiply=0f0",
+ "position" : [2, 189],
+ "zlevel" : -1
+ },
+ "enableVoiceToggle" : {
+ "type" : "button",
+ "pressedOffset" : [0, 0],
+ "position" : [2, 189],
+ "base" : "/interface/opensb/voicechat/bigbutton.png?replace;fff=fff0;000=0007",
+ "hover" : "/interface/opensb/voicechat/bigbutton.png?replace;fff=fff7;000=3337",
+ "press" : "/interface/opensb/voicechat/bigbutton.png?replace;fff=000;000=7777",
+ "callback" : "voiceToggle",
+ "fontSize" : 16,
+ "zlevel" : 1
+ },
+
+
+ "voiceModeLabel" : {
+ "type" : "label",
+ "value" : "VOICE MODE",
+ "position" : [26, 133],
+ "wrapWidth" : 32,
+ "lineSpacing" : 0.75,
+ "hAnchor" : "mid",
+ "vAnchor" : "mid"
+ },
+ "pushToTalkBack" : {
+ "type" : "image",
+ "file" : "/interface/opensb/voicechat/pushtotalkback.png?multiply=0f0",
+ "position" : [50, 121],
+ "zlevel" : -1
+ },
+ "pushToTalk" : {
+ "type" : "button",
+ "pressedOffset" : [0, 0],
+ "position" : [50, 121],
+ "base" : "/interface/opensb/voicechat/pushtotalk.png?replace;fff=fff0;000=0007",
+ "hover" : "/interface/opensb/voicechat/pushtotalk.png?replace;fff=fff7;000=3337",
+ "press" : "/interface/opensb/voicechat/pushtotalk.png?replace;fff=000;000=7777",
+ "callback" : "switchVoiceMode",
+ "fontSize" : 16,
+ "zlevel" : 1
+ },
+
+ "voiceActivityBack" : {
+ "type" : "image",
+ "file" : "/interface/opensb/voicechat/activityback.png?multiply=0f0",
+ "position" : [167, 121],
+ "zlevel" : -1
+ },
+ "voiceActivity" : {
+ "type" : "button",
+ "pressedOffset" : [0, 0],
+ "position" : [167, 121],
+ "base" : "/interface/opensb/voicechat/activity.png?replace;fff=fff0;000=0007",
+ "hover" : "/interface/opensb/voicechat/activity.png?replace;fff=fff7;000=3337",
+ "press" : "/interface/opensb/voicechat/activity.png?replace;fff=000;000=7777",
+ "callback" : "switchVoiceMode",
+ "fontSize" : 16,
+ "zlevel" : 1
+ },
+
+ "thresholdLevel" : {
+ "type" : "label",
+ "value" : "THRESHOLD",
+ "position" : [26, 109],
+ "wrapWidth" : 48,
+ "lineSpacing" : 0.75,
+ "hAnchor" : "mid",
+ "vAnchor" : "mid"
+ },
+ "threshold" : {
+ "type" : "canvas",
+ "rect" : [50, 102, 247, 117],
+ "captureMouseEvents" : true,
+ "captureKeyboardEvents" : false
+ },
+
+ "devices" : {
+ "type" : "scrollArea",
+ "rect" : [3, 16, 248, 98],
+ "children" : {
+ "list" : {
+ "type" : "list",
+ "schema" : {
+ "selectedBG" : "/interface/opensb/voicechat/deviceback.png?multiply=0f0",
+ "unselectedBG" : "/interface/opensb/voicechat/deviceback.png?multiply=222",
+ "spacing" : [0, 1],
+ "memberSize" : [234, 16],
+ "listTemplate" : {
+ "background" : {
+ "type" : "image",
+ "file" : "/interface/opensb/voicechat/deviceback.png?multiply=222",
+ "position" : [0, 0],
+ "zlevel" : -1
+ },
+ "button" : {
+ "type" : "button",
+ "callback" : "selectDevice",
+ "caption" : "Unnamed",
+ "base" : "/interface/opensb/voicechat/device.png?replace;fff=fff0;000=0007",
+ "hover" : "/interface/opensb/voicechat/device.png?replace;fff=fff7;000=3337",
+ "press" : "/interface/opensb/voicechat/device.png?replace;fff=000;000=7777",
+ "pressedOffset" : [0, 0],
+ "position" : [0, 0]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/assets/opensb/interface/opensb/voicechat/voicechat.lua b/assets/opensb/interface/opensb/voicechat/voicechat.lua
new file mode 100644
index 0000000..4e9f7e7
--- /dev/null
+++ b/assets/opensb/interface/opensb/voicechat/voicechat.lua
@@ -0,0 +1,227 @@
+--constants
+local PATH = "/interface/opensb/voicechat/"
+local DEVICE_LIST_WIDGET = "devices.list"
+local DEFAULT_DEVICE_NAME = "Use System Default"
+local NULL_DEVICE_NAME = "No Audio Device"
+local COLD_COLOR = {25, 255, 255, 225}
+local HOT_COLOR = {255, 96, 96, 225}
+local MINIMUM_DB = -80
+local VOICE_MAX, INPUT_MAX = 1.75, 1.0
+local MID = 7.5
+
+local fmt = string.format
+
+local debugging = false
+local function log(...)
+ if not debugging then return end
+ sb.logInfo(...)
+end
+
+local function mapToRange(x, min, max)
+ return math.min(1, math.max(0, (x - min)) / max)
+end
+
+local function linear(a, b, c)
+ return a + (b - a) * c
+end
+
+local settings = {}
+
+local function set(k, v)
+ settings[k] = v
+ local newSettings = jobject()
+ newSettings[k] = v
+ voice.mergeSettings(newSettings)
+ return v
+end
+
+local devicesToWidgets = {}
+local widgetsToDevices = {}
+local nullWidget
+local function addDeviceToList(deviceName)
+ local name = widget.addListItem(DEVICE_LIST_WIDGET)
+ widget.setText(fmt("%s.%s.button", DEVICE_LIST_WIDGET, name), deviceName)
+ widgetsToDevices[name] = deviceName
+ devicesToWidgets[deviceName] = name
+ log("Added audio device '%s' to list", deviceName)
+ return name
+end
+
+function selectDevice()
+ local selected = widget.getListSelected(DEVICE_LIST_WIDGET)
+ if selected == nullWidget then
+ set("inputEnabled", false)
+ widget.setListSelected(DEVICE_LIST_WIDGET, nullWidget)
+ end
+ local deviceName = widgetsToDevices[selected]
+ if deviceName == DEFAULT_DEVICE_NAME then deviceName = nil end
+
+ if settings.deviceName == deviceName then
+ local inputEnabled = set("inputEnabled", not settings.inputEnabled)
+ widget.setListSelected(DEVICE_LIST_WIDGET, inputEnabled and selected or nullWidget)
+ else
+ set("deviceName", deviceName)
+ set("inputEnabled", true)
+ end
+end
+
+local function initCallbacks()
+ widget.registerMemberCallback(DEVICE_LIST_WIDGET, "selectDevice", selectDevice)
+end
+
+local function updateVoiceButton()
+ local enabled = settings.enabled
+ widget.setText("enableVoiceToggle", enabled and "^#0f0;disable voice chat" or "^#f00;enable voice chat")
+ widget.setImage("enableVoiceToggleBack", PATH .. "bigbuttonback.png?multiply=" .. (enabled and "0f0" or "f00"))
+end
+
+local function updateVoiceModeButtons()
+ local pushToTalk = settings.inputMode:lower() == "pushtotalk"
+ widget.setImage("pushToTalkBack", PATH .. "pushtotalkback.png?multiply=" .. (pushToTalk and "0f0" or "f00"))
+ widget.setImage("voiceActivityBack", PATH .. "activityback.png?multiply=" .. (pushToTalk and "f00" or "0f0"))
+ widget.setText("pushToTalk", pushToTalk and "^#0f0;PUSH TO TALK" or "^#f00;PUSH TO TALK")
+ widget.setText("voiceActivity", pushToTalk and "^#f00;ACTIVITY" or "^#0f0;ACTIVITY")
+end
+
+local voiceCanvas, inputCanvas = nil, nil
+local function updateVolumeCanvas(canvas, volume, multiplier)
+ canvas:clear()
+ local lineEnd = 1 + volume * 195
+ local lineColor = {95, 110, 255, 225}
+ local multiplied = volume * multiplier
+ if multiplied > 1 then
+ local level = (multiplied - 1) / (multiplier - 1)
+ for i = 1, 4 do
+ lineColor[i] = linear(lineColor[i], HOT_COLOR[i], level)
+ end
+ else
+ for i = 1, 4 do
+ lineColor[i] = linear(lineColor[i], COLD_COLOR[i], 1 - multiplied)
+ end
+ end
+
+ canvas:drawLine({1, MID}, {lineEnd, MID}, lineColor, 60)
+ canvas:drawLine({lineEnd - 0.5, MID}, {lineEnd + 0.5, MID}, {255, 255, 255, 200}, 60)
+ local str = volume == 0 and "^#f00,shadow;MUTED" or fmt("^shadow;%s%%", math.floor(volume * multiplier * 1000) * 0.1)
+ canvas:drawText(str, {position = {92.5, MID}, horizontalAnchor = "mid", verticalAnchor = "mid"}, 16, {255, 255, 255, 255})
+end
+
+local thresholdCanvas = nil
+local function updateThresholdCanvas(canvas, dB)
+ canvas:clear()
+ local scale = pane.scale()
+ local lineEnd = 1 + (1 - (dB / MINIMUM_DB)) * 195
+ local lineColor = {255, 255, 0, 127}
+ canvas:drawLine({1, 2}, {lineEnd, 2}, lineColor, scale)
+ canvas:drawLine({1, 13}, {lineEnd, 13}, lineColor, scale)
+ lineColor[4] = 64
+ canvas:drawLine({lineEnd, 2}, {196, 2}, lineColor, scale)
+ canvas:drawLine({lineEnd, 13}, {196, 13}, lineColor, scale)
+ canvas:drawLine({lineEnd - 0.5, MID}, {lineEnd + 0.5, MID}, {255, 255, 255, 200}, 60)
+
+ local loudness = 1 - (voice.speaker().smoothDecibels / MINIMUM_DB)
+ local loudnessEnd = math.min(1 + loudness * 195, 196)
+ if loudnessEnd > 0 then
+ lineColor[4] = 200
+ canvas:drawLine({1, MID}, {loudnessEnd, MID}, lineColor, 4 * scale)
+ end
+
+ local str = fmt("^shadow;%sdB", math.floor(dB * 10) * 0.1)
+ canvas:drawText(str, {position = {92.5, MID}, horizontalAnchor = "mid", verticalAnchor = "mid"}, 16, {255, 255, 255, 255})
+end
+
+function init()
+ settings = voice.getSettings()
+ voiceCanvas = widget.bindCanvas("voiceVolume")
+ inputCanvas = widget.bindCanvas("inputVolume")
+ thresholdCanvas = widget.bindCanvas("threshold")
+end
+
+function displayed()
+ devicesToWidgets = {}
+ widgetsToDevices = {}
+ widget.clearListItems(DEVICE_LIST_WIDGET)
+ initCallbacks()
+
+ addDeviceToList(DEFAULT_DEVICE_NAME)
+
+ for i, v in pairs(voice.devices()) do
+ addDeviceToList(v)
+ end
+
+ nullWidget = widget.addListItem(DEVICE_LIST_WIDGET)
+ local nullWidgetPath = fmt("%s.%s", DEVICE_LIST_WIDGET, nullWidget)
+ widget.setPosition(nullWidgetPath, {0, 10000})
+ widget.setVisible(nullWidgetPath, false)
+
+ local preferredDeviceWidget = devicesToWidgets[settings.deviceName or DEFAULT_DEVICE_NAME]
+ if preferredDeviceWidget and settings.inputEnabled then
+ widget.setListSelected(DEVICE_LIST_WIDGET, preferredDeviceWidget)
+ end
+
+ updateVoiceButton()
+ updateVoiceModeButtons()
+ updateVolumeCanvas(voiceCanvas, settings.outputVolume / VOICE_MAX, VOICE_MAX)
+ updateVolumeCanvas(inputCanvas, settings.inputVolume / INPUT_MAX, INPUT_MAX)
+ updateThresholdCanvas(thresholdCanvas, settings.threshold)
+end
+
+function update()
+ updateThresholdCanvas(thresholdCanvas, settings.threshold)
+end
+
+local function sliderToValue(x)
+ return mapToRange(x, 5, 187)
+end
+
+local function mouseInSlider(mouse)
+ return mouse[1] > 0 and mouse[1] < 197
+ and mouse[2] > 0 and mouse[2] < 16
+end
+
+local function handleVolume(canvas, mouse, multiplier, setter)
+ if not mouseInSlider(mouse) then return end
+
+ local volumePreMul = sliderToValue(mouse[1])
+ local volume = volumePreMul * multiplier;
+ if math.abs(volume - 1) < 0.01 then
+ volumePreMul = 1 / multiplier
+ volume = 1
+ end
+
+ updateVolumeCanvas(canvas, volumePreMul, multiplier)
+ setter(volume)
+end
+
+function voiceVolume(mouse, button)
+ if button ~= 0 then return end
+ handleVolume(voiceCanvas, mouse, VOICE_MAX, function(v) set("outputVolume", v) end)
+end
+
+function inputVolume(mouse, button)
+ if button ~= 0 then return end
+ handleVolume(inputCanvas, mouse, INPUT_MAX, function(v) set("inputVolume", v) end)
+end
+
+function threshold(mouse, button)
+ if button ~= 0 then return end
+ if not mouseInSlider(mouse) then return end
+ local dB = (1 - sliderToValue(mouse[1])) * MINIMUM_DB
+ set("threshold", dB)
+
+ updateThresholdCanvas(thresholdCanvas, dB)
+end
+
+function switchVoiceMode(mode)
+ log("switching voice mode to %s", tostring(mode))
+ local success, err = pcall(function()
+ set("inputMode", mode)
+ updateVoiceModeButtons()
+ end)
+ if not success then log("%s", err) end
+end
+
+function voiceToggle()
+ set("enabled", not settings.enabled)
+ updateVoiceButton()
+end \ No newline at end of file
diff --git a/assets/opensb/interface/optionsmenu/body_blank.png b/assets/opensb/interface/optionsmenu/body_blank.png
new file mode 100644
index 0000000..7d5b0f1
--- /dev/null
+++ b/assets/opensb/interface/optionsmenu/body_blank.png
Binary files differ
diff --git a/assets/opensb/interface/optionsmenu/duocontrolsbutton.png b/assets/opensb/interface/optionsmenu/duocontrolsbutton.png
new file mode 100644
index 0000000..1d40af3
--- /dev/null
+++ b/assets/opensb/interface/optionsmenu/duocontrolsbutton.png
Binary files differ
diff --git a/assets/opensb/interface/optionsmenu/duocontrolsbuttonhover.png b/assets/opensb/interface/optionsmenu/duocontrolsbuttonhover.png
new file mode 100644
index 0000000..bdeb055
--- /dev/null
+++ b/assets/opensb/interface/optionsmenu/duocontrolsbuttonhover.png
Binary files differ
diff --git a/assets/opensb/interface/optionsmenu/optionsmenu.config.patch b/assets/opensb/interface/optionsmenu/optionsmenu.config.patch
index fe5def8..68b27f9 100644
--- a/assets/opensb/interface/optionsmenu/optionsmenu.config.patch
+++ b/assets/opensb/interface/optionsmenu/optionsmenu.config.patch
@@ -1,25 +1,47 @@
{
"paneLayout" : {
+ "voiceLabel" : {
+ "type" : "label",
+ "position" : [119, 185],
+ "hAnchor" : "mid",
+ "value" : "VOICE"
+ },
+ "showVoiceSettings" : {
+ "type" : "button",
+ "position" : [30, 169],
+ "caption" : "Settings",
+ "base" : "/interface/optionsmenu/duocontrolsbutton.png",
+ "hover" : "/interface/optionsmenu/duocontrolsbuttonhover.png"
+ },
+ "showVoicePlayers" : {
+ "type" : "button",
+ "disabled" : true,
+ "position" : [133, 169],
+ "caption" : "^#a0a000,font=iosevka-semiboldoblique;TODO^#aa7;:^reset; Players",
+ "base" : "/interface/optionsmenu/duocontrolsbutton.png",
+ "hover" : "/interface/optionsmenu/duocontrolsbuttonhover.png"
+ },
"showKeybindings" : {
"type" : "button",
- "position" : [150, 95],
+ "position" : [153, 95],
"caption" : "Game Binds",
- "base" : "/interface/optionsmenu/controlsbutton.png",
- "hover" : "/interface/optionsmenu/controlsbuttonhover.png"
+ "base" : "/interface/optionsmenu/tricontrolsbutton.png",
+ "hover" : "/interface/optionsmenu/tricontrolsbuttonhover.png"
},
"showModBindings" : {
"type" : "button",
"position" : [87, 95],
"caption" : "Mod Binds",
- "base" : "/interface/optionsmenu/controlsbutton.png",
- "hover" : "/interface/optionsmenu/controlsbuttonhover.png"
+ "base" : "/interface/optionsmenu/tricontrolsbutton.png",
+ "hover" : "/interface/optionsmenu/tricontrolsbuttonhover.png"
},
"showGraphics" : {
"type" : "button",
- "position" : [24, 95],
+ "position" : [21, 95],
"caption" : "Graphics",
- "base" : "/interface/optionsmenu/controlsbutton.png",
- "hover" : "/interface/optionsmenu/controlsbuttonhover.png"
- }
+ "base" : "/interface/optionsmenu/tricontrolsbutton.png",
+ "hover" : "/interface/optionsmenu/tricontrolsbuttonhover.png"
+ },
+ "sfxValueLabel" : { "position" : [192, 142] } // this is 2px too low in vanilla lol
}
} \ No newline at end of file
diff --git a/assets/opensb/interface/optionsmenu/controlsbutton.png b/assets/opensb/interface/optionsmenu/tricontrolsbutton.png
index 1a2a6ed..1a2a6ed 100644
--- a/assets/opensb/interface/optionsmenu/controlsbutton.png
+++ b/assets/opensb/interface/optionsmenu/tricontrolsbutton.png
Binary files differ
diff --git a/assets/opensb/interface/optionsmenu/controlsbuttonhover.png b/assets/opensb/interface/optionsmenu/tricontrolsbuttonhover.png
index ba57e02..ba57e02 100644
--- a/assets/opensb/interface/optionsmenu/controlsbuttonhover.png
+++ b/assets/opensb/interface/optionsmenu/tricontrolsbuttonhover.png
Binary files differ
diff --git a/assets/opensb/scripts/opensb/universeclient/voicemanager.lua b/assets/opensb/scripts/opensb/universeclient/voicemanager.lua
index b7468ce..2f19f6a 100644
--- a/assets/opensb/scripts/opensb/universeclient/voicemanager.lua
+++ b/assets/opensb/scripts/opensb/universeclient/voicemanager.lua
@@ -7,7 +7,7 @@ local module = {}
modules.voice_manager = module
--constants
-local INDICATOR_PATH = "/interface/voicechat/indicator/"
+local INDICATOR_PATH = "/interface/opensb/voicechat/indicator/"
local BACK_INDICATOR_IMAGE = INDICATOR_PATH .. "back.png"
local FRONT_INDICATOR_IMAGE = INDICATOR_PATH .. "front.png"
local FRONT_MUTED_INDICATOR_IMAGE = INDICATOR_PATH .. "front_muted.png"
diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp
index d8d79fd..b264f15 100644
--- a/source/client/StarClientApplication.cpp
+++ b/source/client/StarClientApplication.cpp
@@ -376,6 +376,13 @@ void ClientApplication::update() {
else if (m_state > MainAppState::Title)
updateRunning();
+ // swallow leftover encoded data incase we aren't in-game yet to allow mic read to continue.
+ // TODO: directly disable encoding at menu so we don't have to do this
+ {
+ DataStreamBuffer ext;
+ m_voice->send(ext);
+ }
+
m_guiContext->cleanup();
m_edgeKeyEvents.clear();
m_input->reset();
@@ -499,7 +506,7 @@ void ClientApplication::changeState(MainAppState newState) {
m_statistics = make_shared<Statistics>(m_root->toStoragePath("player"), appController()->statisticsService());
m_universeClient = make_shared<UniverseClient>(m_playerStorage, m_statistics);
m_universeClient->setLuaCallbacks("input", LuaBindings::makeInputCallbacks());
- m_universeClient->setLuaCallbacks("voice", LuaBindings::makeVoiceCallbacks(m_voice.get()));
+ m_universeClient->setLuaCallbacks("voice", LuaBindings::makeVoiceCallbacks());
m_mainMixer->setUniverseClient(m_universeClient);
m_titleScreen = make_shared<TitleScreen>(m_playerStorage, m_mainMixer->mixer());
diff --git a/source/frontend/CMakeLists.txt b/source/frontend/CMakeLists.txt
index 4c6b9c8..b002155 100644
--- a/source/frontend/CMakeLists.txt
+++ b/source/frontend/CMakeLists.txt
@@ -58,6 +58,7 @@ SET (star_frontend_HEADERS
StarWireInterface.hpp
StarVoice.hpp
StarVoiceLuaBindings.hpp
+ StarVoiceSettingsMenu.hpp
)
SET (star_frontend_SOURCES
@@ -108,6 +109,7 @@ SET (star_frontend_SOURCES
StarWireInterface.cpp
StarVoice.cpp
StarVoiceLuaBindings.cpp
+ StarVoiceSettingsMenu.cpp
)
ADD_LIBRARY (star_frontend OBJECT ${star_frontend_SOURCES} ${star_frontend_HEADERS})
diff --git a/source/frontend/StarMainMixer.cpp b/source/frontend/StarMainMixer.cpp
index 6d68ea2..d4a2e73 100644
--- a/source/frontend/StarMainMixer.cpp
+++ b/source/frontend/StarMainMixer.cpp
@@ -121,6 +121,9 @@ void MainMixer::update(bool muteSfx, bool muteMusic) {
if (m_mixer->hasEffect("echo"))
m_mixer->removeEffect("echo", 0);
+ if (Voice* voice = Voice::singletonPtr())
+ voice->update();
+
m_mixer->update();
}
}
diff --git a/source/frontend/StarOptionsMenu.cpp b/source/frontend/StarOptionsMenu.cpp
index cef2e7d..caa1b21 100644
--- a/source/frontend/StarOptionsMenu.cpp
+++ b/source/frontend/StarOptionsMenu.cpp
@@ -7,6 +7,7 @@
#include "StarLabelWidget.hpp"
#include "StarAssets.hpp"
#include "StarKeybindingsMenu.hpp"
+#include "StarVoiceSettingsMenu.hpp"
#include "StarBindingsMenu.hpp"
#include "StarGraphicsMenu.hpp"
@@ -49,8 +50,14 @@ OptionsMenu::OptionsMenu(PaneManager* manager)
reader.registerCallback("showKeybindings", [=](Widget*) {
displayControls();
});
+ reader.registerCallback("showVoiceSettings", [=](Widget*) {
+ displayVoiceSettings();
+ });
+ reader.registerCallback("showVoicePlayers", [=](Widget*) {
+
+ });
reader.registerCallback("showModBindings", [=](Widget*) {
- displayModBindings();
+ displayModBindings();
});
reader.registerCallback("showGraphics", [=](Widget*) {
displayGraphics();
@@ -74,6 +81,7 @@ OptionsMenu::OptionsMenu(PaneManager* manager)
m_sfxSlider->setRange(m_sfxRange, assets->json("/interface/optionsmenu/optionsmenu.config:sfxDelta").toInt());
m_musicSlider->setRange(m_musicRange, assets->json("/interface/optionsmenu/optionsmenu.config:musicDelta").toInt());
+ m_voiceSettingsMenu = make_shared<VoiceSettingsMenu>(assets->json(config.getString("voiceSettingsPanePath", "/interface/opensb/voicechat/voicechat.config")));
m_modBindingsMenu = make_shared<BindingsMenu>(assets->json(config.getString("bindingsPanePath", "/interface/opensb/bindings/bindings.config")));
m_keybindingsMenu = make_shared<KeybindingsMenu>();
m_graphicsMenu = make_shared<GraphicsMenu>();
@@ -169,6 +177,10 @@ void OptionsMenu::displayControls() {
m_paneManager->displayPane(PaneLayer::ModalWindow, m_keybindingsMenu);
}
+void OptionsMenu::displayVoiceSettings() {
+ m_paneManager->displayPane(PaneLayer::ModalWindow, m_voiceSettingsMenu);
+}
+
void OptionsMenu::displayModBindings() {
m_paneManager->displayPane(PaneLayer::ModalWindow, m_modBindingsMenu);
}
diff --git a/source/frontend/StarOptionsMenu.hpp b/source/frontend/StarOptionsMenu.hpp
index bd8c4ba..b984f02 100644
--- a/source/frontend/StarOptionsMenu.hpp
+++ b/source/frontend/StarOptionsMenu.hpp
@@ -10,6 +10,7 @@ namespace Star {
STAR_CLASS(SliderBarWidget);
STAR_CLASS(ButtonWidget);
STAR_CLASS(LabelWidget);
+STAR_CLASS(VoiceSettingsMenu);
STAR_CLASS(KeybindingsMenu);
STAR_CLASS(GraphicsMenu);
STAR_CLASS(BindingsMenu);
@@ -38,6 +39,7 @@ private:
void syncGuiToConf();
void displayControls();
+ void displayVoiceSettings();
void displayModBindings();
void displayGraphics();
@@ -59,6 +61,7 @@ private:
JsonObject m_origConfig;
JsonObject m_localChanges;
+ VoiceSettingsMenuPtr m_voiceSettingsMenu;
BindingsMenuPtr m_modBindingsMenu;
KeybindingsMenuPtr m_keybindingsMenu;
GraphicsMenuPtr m_graphicsMenu;
diff --git a/source/frontend/StarVoice.cpp b/source/frontend/StarVoice.cpp
index b7f8a6c..843203f 100644
--- a/source/frontend/StarVoice.cpp
+++ b/source/frontend/StarVoice.cpp
@@ -312,15 +312,19 @@ void Voice::readAudioData(uint8_t* stream, int len) {
size_t sampleCount = len / 2;
if (active) {
- float volume = m_inputVolume;
float decibels = getAudioLoudness((int16_t*)stream, sampleCount);
+ if (!m_loopback)
+ m_clientSpeaker->decibelLevel = getAudioLoudness((int16_t*)stream, sampleCount, m_inputVolume);
+
if (m_inputMode == VoiceInputMode::VoiceActivity) {
if (decibels > m_threshold)
m_lastThresholdTime = now;
active = now - m_lastThresholdTime < 50;
}
}
+ else if (!m_loopback)
+ m_clientSpeaker->decibelLevel = -96.0f;
if (!m_loopback) {
if (active && !m_clientSpeaker->playing)
@@ -405,6 +409,7 @@ void Voice::mix(int16_t* buffer, size_t frameCount, unsigned channels) {
}
else {
speaker->playing = false;
+ speaker->decibelLevel = -96.0f;
it = m_activeSpeakers.erase(it);
}
}
@@ -423,23 +428,25 @@ void Voice::mix(int16_t* buffer, size_t frameCount, unsigned channels) {
}
void Voice::update(PositionalAttenuationFunction positionalAttenuationFunction) {
- if (positionalAttenuationFunction) {
- for (auto& entry : m_speakers) {
- if (SpeakerPtr& speaker = entry.second) {
- speaker->channelVolumes = {
- 1.0f - positionalAttenuationFunction(0, speaker->position, 1.0f),
+ for (auto& entry : m_speakers) {
+ if (SpeakerPtr& speaker = entry.second) {
+ if (positionalAttenuationFunction) {
+ speaker->channelVolumes = {
+ 1.0f - positionalAttenuationFunction(0, speaker->position, 1.0f),
1.0f - positionalAttenuationFunction(1, speaker->position, 1.0f)
- };
+ };
+ }
+ else
+ speaker->channelVolumes = Vec2F::filled(1.0f);
- auto& dbHistory = speaker->dbHistory;
- memcpy(&dbHistory[1], &dbHistory[0], (dbHistory.size() - 1) * sizeof(float));
- dbHistory[0] = speaker->decibelLevel;
- float smoothDb = 0.0f;
- for (float dB : dbHistory)
- smoothDb += dB;
-
- speaker->smoothDb = smoothDb / dbHistory.size();
- }
+ auto& dbHistory = speaker->dbHistory;
+ memcpy(&dbHistory[1], &dbHistory[0], (dbHistory.size() - 1) * sizeof(float));
+ dbHistory[0] = speaker->decibelLevel;
+ float smoothDb = 0.0f;
+ for (float dB : dbHistory)
+ smoothDb += dB;
+
+ speaker->smoothDb = smoothDb / dbHistory.size();
}
}
@@ -467,6 +474,7 @@ StringList Voice::availableDevices() {
for (size_t i = 0; i != devices; ++i)
deviceList.emplace_back(SDL_GetAudioDeviceName(i, 1));
}
+ deviceList.sort();
return deviceList;
}
@@ -488,7 +496,7 @@ int Voice::send(DataStreamBuffer& out, size_t budget) {
for (auto& chunk : encodedChunks) {
out.write<uint32_t>(chunk.size());
out.writeBytes(chunk);
- if ((budget -= min<size_t>(budget, chunk.size())) == 0)
+ if (budget && (budget -= min<size_t>(budget, chunk.size())) == 0)
break;
}
@@ -499,7 +507,7 @@ int Voice::send(DataStreamBuffer& out, size_t budget) {
}
bool Voice::receive(SpeakerPtr speaker, std::string_view view) {
- if (!speaker || view.empty())
+ if (!m_enabled || !speaker || view.empty())
return false;
try {
@@ -635,9 +643,8 @@ void Voice::closeDevice() {
return;
m_applicationController->closeAudioInputDevice();
- if (!m_loopback)
- m_clientSpeaker->playing = false;
-
+ m_clientSpeaker->playing = false;
+ m_clientSpeaker->decibelLevel = -96.0f;
m_deviceOpen = false;
}
@@ -684,9 +691,6 @@ void Voice::thread() {
samples[i] *= m_inputVolume;
}
- if (!m_loopback)
- m_clientSpeaker->decibelLevel = getAudioLoudness(samples.data(), samples.size());
-
if (int encodedSize = opus_encode(m_encoder.get(), samples.data(), VOICE_FRAME_SIZE, (unsigned char*)encoded.ptr(), encoded.size())) {
if (encodedSize == 1)
continue;
diff --git a/source/frontend/StarVoice.hpp b/source/frontend/StarVoice.hpp
index 4500aa6..95046af 100644
--- a/source/frontend/StarVoice.hpp
+++ b/source/frontend/StarVoice.hpp
@@ -141,7 +141,7 @@ public:
void setDeviceName(Maybe<String> device);
StringList availableDevices();
- int send(DataStreamBuffer& out, size_t budget);
+ int send(DataStreamBuffer& out, size_t budget = 0);
bool receive(SpeakerPtr speaker, std::string_view view);
// Must be called every frame with input state, expires after 1s.
diff --git a/source/frontend/StarVoiceLuaBindings.cpp b/source/frontend/StarVoiceLuaBindings.cpp
index 1b62aef..934b294 100644
--- a/source/frontend/StarVoiceLuaBindings.cpp
+++ b/source/frontend/StarVoiceLuaBindings.cpp
@@ -6,9 +6,11 @@
namespace Star {
typedef Voice::SpeakerId SpeakerId;
-LuaCallbacks LuaBindings::makeVoiceCallbacks(Voice* voice) {
+LuaCallbacks LuaBindings::makeVoiceCallbacks() {
LuaCallbacks callbacks;
+ auto voice = Voice::singletonPtr();
+
callbacks.registerCallbackWithSignature<StringList>("devices", bind(&Voice::availableDevices, voice));
callbacks.registerCallback( "getSettings", [voice]() -> Json { return voice->saveJson(); });
callbacks.registerCallback("mergeSettings", [voice](Json const& settings) { voice->loadJson(settings); });
@@ -21,7 +23,13 @@ LuaCallbacks LuaBindings::makeVoiceCallbacks(Voice* voice) {
callbacks.registerCallback("speakerPosition", [voice](SpeakerId speakerId) { return voice->speaker(speakerId)->position; });
- callbacks.registerCallback("speaker", [voice](SpeakerId speakerId) { return voice->speaker(speakerId)->toJson(); });
+ callbacks.registerCallback("speaker", [voice](Maybe<SpeakerId> speakerId) {
+ if (speakerId)
+ return voice->speaker(*speakerId)->toJson();
+ else
+ return voice->localSpeaker()->toJson();
+ });
+
callbacks.registerCallback("speakers", [voice](Maybe<bool> onlyPlaying) -> List<Json> {
List<Json> list;
diff --git a/source/frontend/StarVoiceLuaBindings.hpp b/source/frontend/StarVoiceLuaBindings.hpp
index 8c83e54..5d670f3 100644
--- a/source/frontend/StarVoiceLuaBindings.hpp
+++ b/source/frontend/StarVoiceLuaBindings.hpp
@@ -8,7 +8,7 @@ namespace Star {
STAR_CLASS(Voice);
namespace LuaBindings {
- LuaCallbacks makeVoiceCallbacks(Voice* voice);
+ LuaCallbacks makeVoiceCallbacks();
}
}
diff --git a/source/frontend/StarVoiceSettingsMenu.cpp b/source/frontend/StarVoiceSettingsMenu.cpp
new file mode 100644
index 0000000..c815dee
--- /dev/null
+++ b/source/frontend/StarVoiceSettingsMenu.cpp
@@ -0,0 +1,23 @@
+#include "StarVoiceSettingsMenu.hpp"
+#include "StarVoiceLuaBindings.hpp"
+
+namespace Star {
+
+VoiceSettingsMenu::VoiceSettingsMenu(Json const& config) : BaseScriptPane(config) {
+ m_script.setLuaRoot(make_shared<LuaRoot>());
+ m_script.addCallbacks("voice", LuaBindings::makeVoiceCallbacks());
+}
+
+void VoiceSettingsMenu::show() {
+ BaseScriptPane::show();
+}
+
+void VoiceSettingsMenu::displayed() {
+ BaseScriptPane::displayed();
+}
+
+void VoiceSettingsMenu::dismissed() {
+ BaseScriptPane::dismissed();
+}
+
+} \ No newline at end of file
diff --git a/source/frontend/StarVoiceSettingsMenu.hpp b/source/frontend/StarVoiceSettingsMenu.hpp
new file mode 100644
index 0000000..1f9e58d
--- /dev/null
+++ b/source/frontend/StarVoiceSettingsMenu.hpp
@@ -0,0 +1,24 @@
+#ifndef STAR_VOICE_SETTINGS_MENU_HPP
+#define STAR_VOICE_SETTINGS_MENU_HPP
+
+#include "StarBaseScriptPane.hpp"
+
+namespace Star {
+
+STAR_CLASS(VoiceSettingsMenu);
+
+class VoiceSettingsMenu : public BaseScriptPane {
+public:
+ VoiceSettingsMenu(Json const& config);
+
+ virtual void show() override;
+ void displayed() override;
+ void dismissed() override;
+
+private:
+
+};
+
+}
+
+#endif
diff --git a/source/windowing/StarPane.cpp b/source/windowing/StarPane.cpp
index a2d32ad..04739cb 100644
--- a/source/windowing/StarPane.cpp
+++ b/source/windowing/StarPane.cpp
@@ -404,6 +404,10 @@ LuaCallbacks Pane::makePaneCallbacks() {
return this->removeChild(widgetName);
});
+ callbacks.registerCallback("scale", []() -> int {
+ return GuiContext::singleton().interfaceScale();
+ });
+
return callbacks;
}