feat(clients): event sound effects + optional text-to-speech

Add audible cues and optional spoken announcements for session events
(join/leave, channel + PM sent/recv, login, logout/connection-lost,
mic on/off, voice-activity, PTT) across all three clients, driven off
the shared C ABI vc_event stream so the mapping stays consistent.

TTS is off by default; when enabled it announces events and reads
message/PM bodies aloud. Master toggles + a sound-volume slider; the
per-utterance voice-activity and PTT cues default off. WAVs ship from
assets/sounds/.

Windows (built + verified): new VoiceCat.App/Notifications/ layer
(FeedbackSettings -> %AppData%\VoiceCat\feedback.json, SoundPlayerPool
via System.Media.SoundPlayer, SpeechAnnouncer via Prismatoid 0.3.0,
EventFeedback dispatcher); MainForm hooks; NotificationSettingsForm
under Settings > Notifications; csproj adds the Prismatoid PackageRef
and copies the WAVs into sounds\.

macOS + iOS (written, not yet built -- needs a Mac): shared
VoiceCatCore/Feedback/ (SoundEvent, EventFeedback = AVAudioPlayer pool
+ native AVSpeechSynthesizer, FeedbackSettings over UserDefaults); WAVs
bundled via Package.swift resources (.process). Hooks in SessionState/
AppState (iOS) and MainWindowController (macOS); settings UI in
SettingsView (iOS) and SettingsWindowController (macOS).

No core/server code touched; ctest --preset dev unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 15:20:11 +02:00
parent 725bd8e925
commit 50416c33a2
45 changed files with 812 additions and 19 deletions

View File

@@ -4,6 +4,21 @@
<ProjectReference Include="..\VoiceCat.Interop\VoiceCat.Interop.csproj" />
</ItemGroup>
<!-- Prismatoid — .NET bindings for the Prism speech library, used for spoken event
announcements (text-to-speech). net10.0, no transitive dependencies. -->
<ItemGroup>
<PackageReference Include="Prismatoid" Version="0.3.0" />
</ItemGroup>
<!-- Event-cue WAVs (shared with the macOS/iOS clients) copied into sounds\ next to the exe;
SoundPlayerPool loads them from AppContext.BaseDirectory\sounds. -->
<ItemGroup>
<Content Include="..\..\..\assets\sounds\*.wav">
<Link>sounds\%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>