Overview
LoopbackTranscriber is a single WPF project (LoopbackTranscriber.csproj, net10.0-windows) plus a test project (LoopbackTranscriber.Tests). It follows MVVM with CommunityToolkit.Mvvm and a Microsoft.Extensions.DependencyInjection container.
Layers
flowchart TB
subgraph UI["Views · WPF"]
direction LR
MW["MainWindow<br/>Views/*.xaml"]
LW["LiveTranslation<br/>Window"]
TM[TrayMenuWindow]
end
subgraph VM["ViewModels"]
direction LR
Shell[MainViewModel]
Children["Targets · Recording<br/>History · Viewer"]
Live["LiveTranslation<br/>ViewModel"]
Tray["TrayMenuViewModel<br/>AppExitWorkflow"]
end
subgraph SV["Services · no WPF except dispatcher and dialogs"]
WF["Recording<br/>Workflow"]
CC["Capture<br/>Coordinator"]
RP["Recording<br/>Processor"]
SUM["Summarization<br/>Service"]
LTS["LiveTranscription<br/>Session"]
ST["SettingsService<br/>Strings · AppLog"]
end
subgraph IO["Interop and processes"]
WAS["WASAPI · NAudio"]
WK["Worker processes<br/>--worker"]
end
MW ~~~ LW ~~~ TM
Shell ~~~ Children ~~~ Live ~~~ Tray
UI --> VM
VM --> SV
CC --> WAS
RP --> WK
SUM --> WK
LTS --> WK
class WAS,WK io
| Folder | Contents |
|---|---|
Views/, MainWindow*.cs, Converters/, Styles/ |
XAML and code-behind. Presentation only: window, tray, calendar, floating window. |
ViewModels/ |
State and commands of each screen. They do not know the views. |
Services/ |
Logic: capture, processing, transcription, summary, live session, persistence, localization and logging. |
Models/ |
Plain data: settings, watched applications, history items, speaker labels. |
Interop/ |
WASAPI COM interfaces, process loopback activation, audio sessions and the process tree. |
Build/ |
LocalizationCheck.targets: build-time translation check. |
| Root | Program, App, AppServices (container), CrashHandler, SingleInstance. |
Design principles
Nothing leaves the computer. The only network access is downloading the two models, from fixed Hugging Face revisions and with their SHA256 checked. See Models and integrity.
No audio is lost. A recording that cannot be transcribed is kept to be retried, also when the application closes, hangs or the computer shuts down. See Reliability.
Inference runs in separate processes. Whisper and LLamaSharp allocate native and GPU memory that is not always released when the model is unloaded. Each transcription and each summary runs in a child process that exits when done. That keeps the main application light while it waits in the tray. See Worker processes.
Services do not depend on WPF. RecordingWorkflow, RecordingProcessor, CaptureCoordinator and the parts of the live session (segmenter, work queue, line splitting) are tested without a window. Dependencies on the system (capture, Whisper, audio conversion, dialogs, dispatcher, process watcher) sit behind interfaces that the tests replace with test doubles.
Child ViewModels do not know each other. The shell (MainViewModel) coordinates them, and they talk to each other through messages. See ViewModels and messaging.
Main dependencies
| Package | Version | Used for |
|---|---|---|
| CommunityToolkit.Mvvm | 8.4.2 | ObservableObject, [ObservableProperty], [RelayCommand], WeakReferenceMessenger. |
| Microsoft.Extensions.DependencyInjection | 10.0.0 | Service container. |
| WPF-UI | 4.3.0 | Dark theme, accent color and Fluent controls. |
| NAudio | 2.2.1 | Device and microphone capture; reading, writing and converting WAV. |
| Whisper.net (+ Runtime, Runtime.Vulkan) | 1.9.1 | Speech recognition, on the CPU or on a Vulkan GPU. |
| LLamaSharp (+ Backend.Cpu, Backend.Vulkan) | 0.27.0 | Summaries and translation with Qwen3-4B. |
Runtime settings
The .csproj turns off concurrent GC and Tiered PGO, and sets System.GC.ConserveMemory=5. All of this aims to reduce the resident memory of an application that spends most of its time in the tray. In addition:
MemoryTrimmer.Release()compacts the heap and trims the working set: after each transcription and each summary, when a recording finishes processing, when the window is minimized or hidden, and once 4 s after it is first shown.BackgroundMemoryTrimmertrims the working set every 5 minutes while the window is minimized or hidden in the tray.