feat(ui B.1 #20): sound cues on start / stop / complete via Web Audio
Hands-off feedback for recording lifecycle: a short C5 pitch at record start, a falling G4 at record stop, and a staggered C5–E5–G5 major third when the finalise flow completes. Synthesised at runtime via the Web Audio API (OscillatorNode + linear-ramped GainNode envelope) rather than shipping WAV assets — keeps the binary size flat and lets us tweak timbre without touching bundled files. Off by default. Settings → Output exposes the toggle with a volume slider (0–100%, default 15%) and a "Test" button that plays the completion cue so the user can confirm loudness without recording. Hooked at three call sites in DictationPage: - playStartCue after page.recording = true in startRecording - playStopCue at the top of stopRecording - playCompleteCue just before `saved = true` at the end of finaliseTranscription's transcript-present branch All three no-op when settings.soundCues is false. The Web Audio context is lazily constructed on first cue (most browsers suspend it until a user gesture — Tauri's webview inherits that). If the AudioContext can't be built we silently drop the cue rather than throwing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1656,6 +1656,34 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<Toggle
|
||||
bind:checked={settings.soundCues}
|
||||
label="Sound cues on start / stop / complete"
|
||||
description="Short synthesised tones for eyes-off feedback. Synthesised locally via Web Audio — no assets bundled."
|
||||
/>
|
||||
{#if settings.soundCues}
|
||||
<div class="ml-[50px] mt-2 mb-1 animate-fade-in flex items-center gap-3">
|
||||
<label for="sound-cue-volume" class="text-[11px] text-text-tertiary uppercase tracking-wider">Volume</label>
|
||||
<input
|
||||
id="sound-cue-volume"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.05"
|
||||
bind:value={settings.soundCueVolume}
|
||||
class="w-[160px] accent-accent"
|
||||
data-no-transition
|
||||
/>
|
||||
<span class="text-[11px] text-text-secondary w-[34px]">{Math.round(settings.soundCueVolume * 100)}%</span>
|
||||
<button
|
||||
class="text-[11px] text-accent hover:text-accent-hover"
|
||||
onclick={async () => {
|
||||
const mod = await import("$lib/utils/sounds.js");
|
||||
mod.playCompleteCue(settings.soundCueVolume, true);
|
||||
}}
|
||||
>Test</button>
|
||||
</div>
|
||||
{/if}
|
||||
<Toggle bind:checked={settings.includeTimestamps} label="Include timestamps in exports" />
|
||||
<Toggle
|
||||
bind:checked={settings.saveAudio}
|
||||
|
||||
Reference in New Issue
Block a user