diff --git a/README.md b/README.md index 68c9cf9..e7e7125 100644 --- a/README.md +++ b/README.md @@ -541,7 +541,7 @@ The repository includes `rc-race-sound-pack/`. `sound_manifest.json` is the sour 1. Open `Settings -> Race sounds and announcements`. 2. Select `sv` or `en`, then set master, effects, voice, and passing volume. -3. Enable or disable effect and voice independently for each event and use its Test button. +3. Enable or disable effect and voice independently for each event and use its Test button. Changes save automatically, and the section also has its own Save button. WAV effects are prerecorded; voice announcements use the operating system Web Speech voices. 4. Select a 0/10/30/60-second pre-start, start lights, and random delay limits. For timed race sessions the clock starts at the same callback that initiates the start tone. Open/Free Practice starts immediately. 5. Use the Race Control buttons in `Timing` for Track call, Track clear, Red flag, False start, and Marshal warning. diff --git a/README.sv.md b/README.sv.md index c67779c..11c14fc 100644 --- a/README.sv.md +++ b/README.sv.md @@ -530,7 +530,7 @@ Repot innehåller `rc-race-sound-pack/`. `sound_manifest.json` är källan för 1. Öppna `Inställningar -> Raceljud och utrop`. 2. Välj `sv` eller `en` och ställ master-, effekt-, röst- och passing-volym. -3. Slå på/av effekt och röst separat för varje event och använd radens Testa-knapp. +3. Slå på/av effekt och röst separat för varje event och använd radens Testa-knapp. Ändringar sparas automatiskt och sektionen har även en egen Spara-knapp. WAV-effekter är förinspelade; röstutrop använder operativsystemets Web Speech-röster. 4. Välj 0/10/30/60 sekunders förstart, startljus och gränser för slumpad startfördröjning. För tidsstyrda race startar klockan i samma callback som starttonen initieras. Open/Free Practice startar direkt. 5. Använd Race Control-knapparna i `Tidtagning` för Stopp på banan, Banan fri, Röd flagg, Felaktig start och Banvaktsvarning. diff --git a/src/app.js b/src/app.js index 439b373..3c81830 100644 --- a/src/app.js +++ b/src/app.js @@ -1024,7 +1024,7 @@ const TRANSLATIONS = { "audio.max_delay": "Största fördröjning (sek)", "audio.per_competitor": "Olika passing-ton per förare/bil", "audio.test": "Testa", - "audio.note": "Effekter får överlappa och blockerar aldrig tidtagningen. Kritiska utrop avbryter lägre prioriterat tal. Saknade ljudfiler använder fallback eller hoppas över.", + "audio.note": "Fasta effekter spelas från ljudpaketets WAV-filer. Röstutrop använder webbläsarens installerade systemröster. Val sparas automatiskt; kritiska utrop avbryter lägre prioriterat tal.", "audio.effect": "Effekt", "audio.voice": "Röst", "audio.track_call": "STOPP PÅ BANAN", @@ -2131,7 +2131,7 @@ const TRANSLATIONS = { "audio.max_delay": "Maximum delay (seconds)", "audio.per_competitor": "Different passing tone per driver/car", "audio.test": "Test", - "audio.note": "Effects may overlap and never block timing. Critical announcements interrupt lower-priority speech. Missing files use a fallback or are skipped.", + "audio.note": "Fixed effects use WAV files from the sound pack. Voice announcements use the browser installed system voices. Changes save automatically; critical announcements interrupt lower-priority speech.", "audio.effect": "Effect", "audio.voice": "Voice", "audio.track_call": "TRACK CALL", @@ -2744,7 +2744,7 @@ const raceAudioEngine = createRaceAudioEngine({ speak: (text, options = {}) => new Promise((resolve) => { let settled = false; const done = (value) => { if (!settled) { settled = true; resolve(value); } }; - const started = speakText(text, { ...options, onEnd: () => done(true), onError: () => done(false) }); + const started = speakText(text, { ...options, voiceUri: "", onEnd: () => done(true), onError: () => done(false) }); if (!started) done(false); else setTimeout(() => done(true), 15000); }), diff --git a/src/runtime_services.js b/src/runtime_services.js index c8f088c..b3534b3 100644 --- a/src/runtime_services.js +++ b/src/runtime_services.js @@ -340,7 +340,8 @@ export function speakTextHelper(text, { state, currentLanguage }, options = {}) utterance.volume = Math.max(0, Math.min(1, Number(options.volume ?? 1))); if (typeof options.onEnd === "function") utterance.onend = options.onEnd; if (typeof options.onError === "function") utterance.onerror = options.onError; - const voice = selectSpeechVoice(synth.getVoices(), String(state.settings.speechVoiceUri || ""), utterance.lang); + const configuredVoiceUri = options.voiceUri !== undefined ? options.voiceUri : state.settings.speechVoiceUri; + const voice = selectSpeechVoice(synth.getVoices(), String(configuredVoiceUri || ""), utterance.lang); if (voice) utterance.voice = voice; synth.speak(utterance); return true; diff --git a/src/settings.js b/src/settings.js index 03dba9e..3e4a721 100644 --- a/src/settings.js +++ b/src/settings.js @@ -186,7 +186,7 @@ export function renderSettings(deps) { - +
${t("audio.note")}
| Event | ${t("audio.effect")} | ${t("audio.voice")} |
|---|