Architecture

This document describes the current (v4.0.1) system design: how audio flows through the plugin, the threading and synchronization model, the DSP behind each analyzer, and a map of the source tree. It is written to be accurate to the code — if you find a discrepancy, the code is authoritative and this document is a bug.

High-level structure

Buffle Audio Visualize is a JUCE AudioProcessor (the plugin) with an AudioProcessorEditor (the UI). The processor owns four independent analysis engines and passes audio through unchanged. The editor owns the display components, the mix-health rule engine, and the session recorder.

                        ┌───────────────────────────────────────────┐
   Host / DAW  ──audio──▶  WaveformVisualizerAudioProcessor          │
   (audio thread)       │    processBlock():                         │
                        │      • waveformBuffer.push()               │
                        │      • stereoImageAnalyzer.process()       │
                        │      • spectrumAnalyzer.process()          │
                        │      • loudnessAnalyzer.process()          │
                        │      • (audio copied to output unchanged)  │
                        └───────┬───────────────────────────────────┘
                                │  atomics + short critical sections
                                │  (engine → GUI snapshots)
                        ┌───────▼───────────────────────────────────┐
   Screen  ◀──repaint──▶  WaveformVisualizerAudioProcessorEditor    │
   (message thread)     │    • WaveformComponent   (60 fps)          │
                        │    • VectorScopeComponent(30 fps)          │
                        │    • SpectrumComponent   (30 fps)          │
                        │    • LoudnessMeterComponent (30 fps)       │
                        │    • HealthMonitor + SessionRecorder(10 Hz)│
                        │    • TimelineComponent   (15 fps)          │
                        └────────────────────────────────────────────┘

The audio path is transparent: processBlock clears any unused output channels, feeds the four engines, and does not modify the samples that reach the output. There are no sound-altering parameters and zero added latency.

Threading & synchronization model

Two threads matter: the audio (real-time) thread that calls processBlock, and the message (GUI) thread that runs timers and paints. Engines are written by the audio thread and read by the GUI thread. Synchronization is explicit and deliberately simple:

Data Writer Reader Mechanism
Scalar measurements (correlation, balance, LUFS, true peak, per-band values) audio GUI std::atomic<float>
Spectrum magnitude / peak-hold / average arrays audio GUI juce::CriticalSection (short hold)
Vectorscope point cloud audio GUI juce::CriticalSection
Loudness gating-block history audio GUI juce::CriticalSection
Health findings, session frames GUI only GUI only none needed

Real-time characteristics (disclosed honestly for review):

These are typical analyzer trade-offs; they are documented rather than hidden so a reviewer can weigh them. The HealthMonitor and SessionRecorder run only on the message thread and never touch the audio thread.

The analysis engines

WaveformBuffer (WaveformBuffer.h/.cpp)

Thread-safe circular buffer of recent L/R samples for the waveform display. Configurable time window (2 / 5 / 10 s). Reports sample rate and data-present flag.

StereoImageAnalyzer (StereoImageAnalyzer.h/.cpp)

SpectrumAnalyzer (SpectrumAnalyzer.h/.cpp)

LoudnessAnalyzer (LoudnessAnalyzer.h/.cpp)

UI structure

The editor lays out a header bar, a 2×2 analyzer grid, a Flight Recorder timeline strip, and a footer:

Custom look-and-feel (BuffleLookAndFeel) provides the dark theme, rounded buttons, and tooltip styling. A juce::TooltipWindow hosts hover help.

UI controls

Control Location Action
FREEZE header Pause all displays (analysis keeps running)
RESET header Reset integrated loudness, peak holds, spectrum average/peaks
AVG header Cycle spectrum averaging: fast / medium / slow
HOLD header Spectrum peak-hold duration: 1 / 3 / 5 / 10 s
WIN header Waveform time window: 2 / 5 / 10 s
PRESET header Factory presets (Streaming/Broadcast/Podcast/Club) or save/load a custom .bavpreset
click scope vectorscope Toggle M/S Lissajous ↔︎ polar dome
SNAP / LOAD spectrum Capture average as reference / load a reference file
REF / DELTA spectrum Toggle reference overlay / difference view
A–D / CLR spectrum Select reference slot / clear the library
LENS spectrum Cycle Translation Lens: off / phone / buds / car / club
MASK spectrum Toggle the Masking Radar overlay (beta)
Shift+click spectrum Place measurement cursor A, then B; delta-freq/delta-dB readout
click/drag timeline Scrub the session; replays the recorded spectrum shape at that moment
REPORT / CLR / LIVE timeline Export HTML report / clear session / return to live
click health line footer Open the Mix Health feed
click N INST badge footer Open the multi-instance session panel (shown once 2+ instances share this process)
click logo footer Open the About box

Decision-support layer (message thread)

Session intelligence (multi-instance, v4.0.0)

Source map

WaveformVisualizer/Source/
├── PluginProcessor.{h,cpp}        AudioProcessor: owns engines, passes audio through
├── PluginEditor.{h,cpp}           Editor: layout, controls, health/recorder ticks
├── PluginVersion.h                Single source of version truth
├── WaveformBuffer.{h,cpp}         Circular sample buffer
├── WaveformComponent.{h,cpp}      Waveform display
├── StereoImageAnalyzer.{h,cpp}    Correlation, balance, band-split stereo guard
├── VectorScopeComponent.{h,cpp}   Lissajous + polar dome + meters + band strip
├── SpectrumAnalyzer.{h,cpp}       FFT engine, peak hold, average
├── SpectrumComponent.{h,cpp}      Spectrum, references, lens, masking radar, tilt/sharpness
├── LoudnessAnalyzer.{h,cpp}       BS.1770-4 LUFS, true peak, LRA
├── LoudnessMeterComponent.{h,cpp} Loudness meter display
├── HealthMonitor.h                Mix-health rule engine (header-only)
├── SessionRecorder.h              Flight Recorder + HTML report (header-only)
├── TimelineComponent.{h,cpp}      Flight Recorder timeline strip
└── InstanceRegistry.h             Multi-instance session registry (header-only)

Build system

Mirrored from the project source for the public site — see the in-repo Markdown for the canonical, linkable version.