Skip to content

Architecture

github-actions[bot] edited this page Sep 15, 2026 · 2 revisions

Architecture

Component Responsibility
VxSound.Core Validated presets, semantic parametric filters, per-ear settings, filter planning, response/headroom evaluation, streaming stereo DSP, finite listening tones and route rules
VxSound.App WPF controls, parametric/graphic EQ editing, WASAPI device integration, live audio mixing, file playback and local persistence
VxSound.Tests Dependency-free executable tests for filter response, signal behavior, persistence, limits and route validation

The WPF control thread prepares complete FilterPlan/filter banks. The render thread receives a ready bank through an atomic exchange and crossfades between banks over 10 ms. The steady-state DSP render loop performs no managed allocations and no file I/O. This statement concerns the tested core DSP loop, not every allocation inside Windows or third-party audio transport.

EQ and filter planning

VxSound supports two profile modes:

  • Graphic — the original 10-band EQ at 31.25 Hz through 16 kHz, including optional independent right-channel values.
  • Parametric — semantic filter objects with stable IDs, enabled state, frequency, gain, Q, filter type and channel targeting. Supported types are Peak, Low Shelf, High Shelf, High Pass, Low Pass and Notch.

Filter coefficients use normalized Audio EQ Cookbook/RBJ-style biquad equations. Gain/Q/frequency limits and finite-value validation apply before coefficient construction. Filters at or above 45% of the active sample rate are skipped instead of being silently clamped into a different audible filter.

FrequencyResponseEvaluator is the authoritative mathematical response path for the UI curve and automatic headroom analysis. Headroom samples the combined left/right filter response on a dense logarithmic grid, includes the profile preamp, then adds a configurable safety margin. FilterPlan.ResponseCurve exposes the same result to visualizations. The profile editor can also display each planned filter response separately without using separate approximation math.

The render chain is:

profile EQ → bass/treble/fullness → output-bound personal L/R EQ → profile preamp + automatic headroom + channel/master level → linked limiter

A stereo-linked, instantaneous-attack/80 ms-release sample-peak limiter contains output samples. It has no lookahead and is not a true-peak limiter. The processor also exposes bounded sample-peak, smoothed RMS, limiter-reduction and pre-limiter clipping counters for diagnostics; these meters do not claim LUFS, SPL or acoustic exposure.

Fullness is an independent optional shelf amount. Its bass lift scales with the attenuation of the VxSound level control and tapers toward zero at 0 dB. It is not JBL Personi-Fi code, a measured equal-loudness calibration, or automatic headphone frequency-response correction.

Mixer and Windows audio

Each live channel has a bounded capture buffer and its own profile/filter state. Mono becomes stereo; different input rates use the NAudio WDL resampler. The sum is processed by a separate master stage with personal EQ, master level and a final limiter. The user-selected output remains explicit. Long-running drift compensation and automatic reconnection require Windows hardware testing and are not implemented yet.

NAudio 3.1's span-based providers, WasapiPlayerBuilder and WasapiRecorderBuilder are used. The player requests a 50 ms buffer and the loopback recorder a 30 ms capture buffer. These requests are not an end-to-end latency measurement. Windows/device behavior and buffer occupancy affect actual latency. Physical loopback endpoints are not offered as normal mixer inputs because replaying their already-audible output would cause double playback or feedback.

Official source references: NAudio, Audio EQ Cookbook, WASAPI loopback, format support.

Studio design and profile compatibility

The native WPF studio retains VxSound's existing dark palette and purple accent. The selected rounded line-art audio icon direction is implemented as in-app WPF vector geometry; icons inherit the same control foreground/accent instead of introducing the blue/cyan colors from reference art. Microphone processing remains explicitly unavailable.

Profile schema history:

  • schema 1 — original shared 10-band EQ;
  • schema 2 — optional independent RightBands;
  • schema 3 — profile provenance/redistribution metadata;
  • schema 4 — EqualizerMode, profile preamp and semantic ParametricFilter collection.

Schemas 1–3 remain accepted. Imports are validated first, then copied to schema 4 with a new profile identity. Imported parametric filter IDs are regenerated so uploaded data cannot collide with existing local identities. Graphic profiles remain graphic unless deliberately converted; no legacy profile is silently reinterpreted as another EQ curve.

Studio channel switches keep independent profiles, EQ enable/compare state and live levels. Parametric profiles open the parametric editor; graphic profiles retain the 10-band editor. Personal listening maps are local settings and remain excluded from exported sound presets.

The file player uses AudioFileReader, WASAPI and the same DSP chain. Pause/resume retains the decoder; seek uses its synchronized stream position. Output or test transitions stop file playback explicitly. No file plays merely because it was dropped into the window.

Listening sessions

ListeningSurvey is a transport-independent state machine. It keeps selected frequencies, ear order, supported-format exclusions, categorical responses and a bounded review queue. Playback tokens invalidate late completions after replay, pause or navigation. Draft restoration always requires a new completed sample before a Heard/Unclear answer. Report schema 2 records protocol and Windows volume; schema 1 maps retain the original 12-frequency protocol and are not treated as setup-matched comparisons.

ListeningAudioSession uses one dedicated WASAPI stream across successive tones, bypassing VxSound EQ. It prepares sine samples with raised-cosine ramps on the control thread and retains at most two mono waveforms. ListeningBuffer copies into the selected stereo channel using atomic command publication, with no locks or managed allocation in Read. It supplies silence between explicitly requested tones. Completion requires both source consumption and the WASAPI device clock reaching the final frame. Pause, interruption and close cancel playback and dispose the stream; resume rechecks the original output configuration. Hardware volume, external effects and acoustic output cannot be inferred from this stream.

ListeningStore writes drafts and maps atomically outside general settings, validates file size/schema/identity and retains unreadable originals. History displays up to 20 recent valid reports for a headset while keeping older files. Only matching headset/output, sample rate, Windows volume, tone pattern, duration and digital level qualify for comparison. Frequency selections may differ; the table compares shared frequency/ear pairs. JSON export includes the device binding; CSV uses controlled numeric/enum fields and omits user labels.

Clone this wiki locally