Förbättrat ljudsystemet
This commit is contained in:
@@ -16,6 +16,9 @@ export function renderSettings(deps) {
|
||||
connectDecoder,
|
||||
playPassingBeep,
|
||||
playFinishSiren,
|
||||
playStartCue,
|
||||
speakText,
|
||||
getSpeechVoices,
|
||||
openOverlayWindow,
|
||||
buildOverlayUrl,
|
||||
normalizeObsOverlaySettings,
|
||||
@@ -42,6 +45,10 @@ export function renderSettings(deps) {
|
||||
const ammcOutput = Array.isArray(ammcStatus.lastOutput) ? ammcStatus.lastOutput : [];
|
||||
const suggestedWsUrl = getManagedWsUrl();
|
||||
const running = Boolean(ammcStatus.running);
|
||||
const speechVoices = getSpeechVoices();
|
||||
const speechVoiceOptions = speechVoices
|
||||
.map((voice) => `<option value="${escapeHtml(voice.voiceURI)}" ${state.settings.speechVoiceUri === voice.voiceURI ? "selected" : ""}>${escapeHtml(`${voice.name} (${voice.lang})`)}</option>`)
|
||||
.join("");
|
||||
|
||||
dom.view.innerHTML = `
|
||||
<section class="panel">
|
||||
@@ -80,7 +87,32 @@ export function renderSettings(deps) {
|
||||
<input type="checkbox" name="finishVoiceEnabled" form="settingsForm" ${state.settings.finishVoiceEnabled ? "checked" : ""} />
|
||||
<span>${t("settings.finish_voice")}</span>
|
||||
</label>
|
||||
<button id="settingsTestAudio" class="btn" type="button">${t("settings.test_audio")}</button>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" name="startSoundEnabled" form="settingsForm" ${state.settings.startSoundEnabled ? "checked" : ""} />
|
||||
<span>${t("settings.start_sound")}</span>
|
||||
</label>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" name="finishSoundEnabled" form="settingsForm" ${state.settings.finishSoundEnabled ? "checked" : ""} />
|
||||
<span>${t("settings.finish_sound")}</span>
|
||||
</label>
|
||||
<label class="settings-audio-wide">
|
||||
<span>${t("settings.speech_voice")}</span>
|
||||
<select name="speechVoiceUri" form="settingsForm">
|
||||
<option value="">${t("settings.system_default_voice")}</option>
|
||||
${speechVoiceOptions}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>${t("settings.speech_rate")}</span>
|
||||
<input type="range" min="0.65" max="1.35" step="0.05" name="speechRate" form="settingsForm" value="${state.settings.speechRate || 0.95}" />
|
||||
</label>
|
||||
<label>
|
||||
<span>${t("settings.speech_pitch")}</span>
|
||||
<input type="range" min="0.7" max="1.3" step="0.05" name="speechPitch" form="settingsForm" value="${state.settings.speechPitch || 1}" />
|
||||
</label>
|
||||
<button id="settingsTestStart" class="btn" type="button">${t("settings.test_start")}</button>
|
||||
<button id="settingsTestFinish" class="btn" type="button">${t("settings.test_finish")}</button>
|
||||
<button id="settingsTestDriverVoice" class="btn" type="button">${t("settings.test_driver_voice")}</button>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" name="speakerPassingCueEnabled" form="settingsForm" ${state.settings.speakerPassingCueEnabled ? "checked" : ""} />
|
||||
<span>${t("settings.speaker_passing_cue")}</span>
|
||||
@@ -108,6 +140,7 @@ export function renderSettings(deps) {
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>${t("settings.audio_note")}</p>
|
||||
<p class="hint">${t("settings.voice_note")}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -277,15 +310,27 @@ export function renderSettings(deps) {
|
||||
</section>
|
||||
`;
|
||||
|
||||
const applyAudioFormValues = () => {
|
||||
const formNode = document.getElementById("settingsForm");
|
||||
if (!(formNode instanceof HTMLFormElement)) return;
|
||||
const form = new FormData(formNode);
|
||||
state.settings.audioEnabled = form.get("audioEnabled") === "on";
|
||||
state.settings.passingSoundMode = String(form.get("passingSoundMode") || "beep");
|
||||
state.settings.finishVoiceEnabled = form.get("finishVoiceEnabled") === "on";
|
||||
state.settings.startSoundEnabled = form.get("startSoundEnabled") === "on";
|
||||
state.settings.finishSoundEnabled = form.get("finishSoundEnabled") === "on";
|
||||
state.settings.speechVoiceUri = String(form.get("speechVoiceUri") || "");
|
||||
state.settings.speechRate = Math.max(0.65, Math.min(1.35, Number(form.get("speechRate") || 0.95) || 0.95));
|
||||
state.settings.speechPitch = Math.max(0.7, Math.min(1.3, Number(form.get("speechPitch") || 1) || 1));
|
||||
};
|
||||
|
||||
document.getElementById("settingsForm")?.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
const form = new FormData(e.currentTarget);
|
||||
state.settings.wsUrl = String(form.get("wsUrl") || "").trim();
|
||||
state.settings.backendUrl = String(form.get("backendUrl") || "").trim();
|
||||
state.settings.autoReconnect = form.get("autoReconnect") === "on";
|
||||
state.settings.audioEnabled = form.get("audioEnabled") === "on";
|
||||
state.settings.passingSoundMode = String(form.get("passingSoundMode") || "beep");
|
||||
state.settings.finishVoiceEnabled = form.get("finishVoiceEnabled") === "on";
|
||||
applyAudioFormValues();
|
||||
state.settings.speakerPassingCueEnabled = form.get("speakerPassingCueEnabled") === "on";
|
||||
state.settings.speakerLeaderCueEnabled = form.get("speakerLeaderCueEnabled") === "on";
|
||||
state.settings.speakerFinishCueEnabled = form.get("speakerFinishCueEnabled") === "on";
|
||||
@@ -303,13 +348,24 @@ export function renderSettings(deps) {
|
||||
});
|
||||
|
||||
document.getElementById("settingsConnect")?.addEventListener("click", connectDecoder);
|
||||
document.getElementById("settingsTestAudio")?.addEventListener("click", () => {
|
||||
playPassingBeep();
|
||||
setTimeout(() => {
|
||||
if (state.settings.finishVoiceEnabled) {
|
||||
playFinishSiren();
|
||||
}
|
||||
}, 180);
|
||||
document.getElementById("settingsTestStart")?.addEventListener("click", () => {
|
||||
applyAudioFormValues();
|
||||
if (state.settings.startSoundEnabled) playStartCue();
|
||||
if (state.settings.finishVoiceEnabled) {
|
||||
setTimeout(() => speakText(t("timing.race_started_voice"), { interrupt: true }), state.settings.startSoundEnabled ? 650 : 0);
|
||||
}
|
||||
});
|
||||
document.getElementById("settingsTestFinish")?.addEventListener("click", () => {
|
||||
applyAudioFormValues();
|
||||
if (state.settings.finishSoundEnabled) playFinishSiren();
|
||||
if (state.settings.finishVoiceEnabled) {
|
||||
setTimeout(() => speakText(t("timing.race_finished_voice"), { interrupt: true }), state.settings.finishSoundEnabled ? 1150 : 0);
|
||||
}
|
||||
});
|
||||
document.getElementById("settingsTestDriverVoice")?.addEventListener("click", () => {
|
||||
applyAudioFormValues();
|
||||
const driver = state.drivers[0];
|
||||
speakText(driver?.speechName || driver?.name || t("settings.driver_voice_sample"), { interrupt: true });
|
||||
});
|
||||
document.getElementById("settingsLaunchObs")?.addEventListener("click", () => openOverlayWindow("obs", { public: true }));
|
||||
document.getElementById("settingsCopyObsUrl")?.addEventListener("click", async () => {
|
||||
|
||||
Reference in New Issue
Block a user