Skip to content

Architecture Overview

Application Layout

MIXI uses a CSS Grid with 3 columns and 3 rows:

gridTemplateColumns: '1fr auto 1fr'
gridTemplateRows:    'auto auto 1fr'
RowHeightContent
148px (h-12)Topbar — 3 HUD panels via CSS subgrid
218pxStatus bar — feedback ticker + symmetric VU
3RemainingMain — Deck A, Mixer, Deck B via subgrid

The topbar and main content both use gridTemplateColumns: subgrid to share column tracks with the parent, ensuring pixel-perfect alignment between HUD panels and their corresponding deck/mixer columns.

Audio Engine

Singleton Pattern

MixiEngine is a singleton with private constructor:

MixiEngine.getInstance() → creates AudioContext(44100 Hz) on first call

The AudioContext runs at a fixed 44,100 Hz sample rate.

Top-Level Signal Flow

Deck A Source → DeckChannel A → XfaderGain A ──┐
                                                ├→ MasterBus → Output
Deck B Source → DeckChannel B → XfaderGain B ──┘

DeckChannel A → CueGain A ──┐
                              ├→ HeadphoneBus → Headphone Output
DeckChannel B → CueGain B ──┘

Optional Wasm DSP Path

When useWasmDsp is enabled in Settings, audio routes through a Rust AudioWorklet (mixi-dsp-processor) that implements the full signal chain in WebAssembly, bypassing the WebAudio EQ/FX/MasterBus nodes.

  • Parameter bus: 512-byte SharedArrayBuffer
  • Metering bus: 28-byte SharedArrayBuffer for VU output

The worklet loads a dedicated lean wasm (the mixi-dsp crate → public/mixi_dsp.wasm), separate from the wasm-bindgen analysis module (mixi-core). It is compiled with no wasm-bindgen and a stable extern "C" ABI (dsp_engine_new, dsp_process, dsp_*_ptr, …), so it has zero imports and the AudioWorklet can instantiate it with an empty import object. The same DSP source is shared by both crates via #[path] (single source of truth); DspEngine itself is wasm-bindgen-free. scripts/build-wasm.mjs builds the lean wasm and fails the build if it ever gains an import. The bridge fetches the wasm bytes and transfers the ArrayBuffer to the worklet (not a WebAssembly.Module, which does not clone reliably into an AudioWorklet realm).

Deck Channel

Each deck has a DeckChannel with this signal chain:

Source → Trim (GainNode, default 1.0)
       → EQ Model (selectable, see below)
       → Color FX (BiquadFilterNode)
       → DeckFx (effects chain)
       → Fader (GainNode)
       → Analyser (fftSize=256, smoothing=0.8)
       → XfaderGain (GainNode) → Master Bus

DeckFx output also taps to:
       → CueGain (GainNode, default 0) → Headphone Bus

CUE is a pre-fader listen — it taps the signal after effects but before the volume fader.

EQ Models

Three selectable EQ models, hot-swappable at runtime:

LR4 Isolator (Default)

Linkwitz-Riley 24 dB/octave parallel isolator.

BandTopologyCrossover
Low2× cascaded LP (Q=0.707 each)250 Hz
Mid2× HP @ 250 Hz → 2× LP @ 4000 Hz250 Hz / 4000 Hz
High2× cascaded HP (Q=0.707 each)4000 Hz

Kill switch: when gain ≤ range minimum, band gain is set to 0 (hard kill). Other bands are 100% unaffected — parallel topology guarantees zero interaction between bands.

DJ Peak (Pioneer DJM-style)

Serial shelving/peaking EQ — no kill capability.

BandTypeFrequencyQ
LowLow shelf80 Hz
MidPeaking1000 Hz0.7
HighHigh shelf12000 Hz

Xone Kill (Allen & Heath-style)

48 dB/octave full-kill isolator with slight resonance at crossover points.

BandTopologyCrossoverOrder
Low4× cascaded LP (Q=1.0)200 Hz8th order
Mid4× HP @ 200 Hz → 4× LP @ 2500 Hz200 / 2500 Hz8th order
High4× cascaded HP (Q=1.0)2500 Hz8th order

Color FX

Bipolar knob from -1 to +1:

RangeEffectFrequency
-1 → 0Lowpass sweep20 Hz → 20 kHz (exponential)
0Bypass20 kHz (fully open)
0 → +1Highpass sweep20 Hz → 20 kHz (exponential)

Default Q = 0.707 (Butterworth). Q increases with depth for more aggressive filtering at extremes.

Master Bus

Full signal chain from input to output:

Input (GainNode)
  → Master EQ (3-band: 80 Hz / 1 kHz / 12 kHz, ±12 dB)
  → Master Filter (bipolar LP/HP sweep, 3-path crossfade)
  → Band-Split Distortion (300 Hz crossover)
  → Punch Compressor (parallel, 8:1 ratio)
  → DC Blocker (10 Hz highpass)
  → Headroom Pad (-0.3 dB)
  → Limiter (brickwall, -0.5 dB threshold)
  → Analyser → Channel Splitter → L/R Analysers

Master EQ

BandTypeFrequencyQRange
LowLow shelf80 Hz±12 dB
MidPeaking1000 Hz0.7±12 dB
HighHigh shelf12000 Hz±12 dB

Master Filter

Bipolar knob -1 to +1. Three parallel signal paths (bypass, LP, HP) with gain crossfading.

Frequency mapping: 20 × 1000^(1 - |knob|) — exponential sweep from 20 Hz to 20 kHz.

Band-Split Distortion

ParameterValue
Crossover300 Hz
Sub behaviorSummed to mono below 300 Hz (phase-safe for PA)
Waveshapertanh(k·x) / tanh(k), k = amount² × 80 + 1
Oversampling4× when active, none when off
Curve resolution2048 samples

Punch Compressor

Parallel compression — dry signal is always present, compressed signal is mixed in.

ParameterValue
Threshold-14 dB
Ratio3:1
Attack3 ms
Release120 ms
Knee10 dB
Wet mixamount × 0.5, compensation = 1 / (1 + wet)

DC Blocker

Highpass BiquadFilter at 10 Hz, Q = 0.707. Removes DC offset from distortion and compression.

Headroom Pad

Fixed -0.3 dB gain reduction before the limiter.

Limiter

ParameterValue
Threshold-0.5 dB
Ratio20:1
Attack1 ms
Release100 ms
Knee0 dB (hard)

Visual feedback via LimiterDot:

  • Idle (< 0.3 dB reduction): dark
  • Gentle (0.3–3 dB): amber glow
  • Emergency (> 3 dB): red flash + clip border

Headphone Bus

Stereo Mode (Default)

Both master and headphone output to all speakers.

Split Mode

Master output → right ear, CUE → left ear (via ChannelMergerNode).

CUE Mix

Equal-power cosine crossfade: cueMix = cos(mix × π/2), masterTap = sin(mix × π/2). At 0 = 100% CUE, at 0.5 = equal blend, at 1 = 100% MASTER.

Crossfader

CurveFormulaCharacter
smoothgainA = cos(pos × π/2), gainB = sin(pos × π/2)Equal-power, no center dip
sharpCubic curve with 2% dead zones: (1-x)³ / over 0.02–0.98 rangeFast cuts, both full at center

Position 0 = full Deck A, position 1 = full Deck B.

State Management

MIXI uses Zustand stores:

StoreKey State
mixiStoreDeck states (2), master, crossfader, headphones, AI mode, deck modes
settingsStoreEQ model, EQ range, Wasm DSP, demo tracks, skin, update check
browserStoreTrack browser visibility, file list, sort order
sessionStoreRecording state, session persistence

Deck State Shape

Each deck tracks: transport (isPlaying, playbackRate, isSynced, syncMode), audio (gain, volume, eq, colorFx), analysis (bpm, originalBpm, bpmConfidence, musicalKey, dropBeats), waveform data, performance (hotCues[8], activeLoop, quantize, keyLock, slipModeActive, cueActive), and track info (trackName, duration, loadingStage).

Pluggable Deck Modes

ModeKeyLabelColorComponent
TracktrackDeck colorDeckSection
GrooveboxgrooveboxGROOVEBOX#a855f7GrooveboxDeck (lazy)
TurboKickturbokickTURBOKICK#ef4444TurboKickDeck (lazy)
TurboBassjs303TURBOBASS#00ff88JS303Deck (lazy)

Thread Architecture & Data Flow

MIXI utilizes a multi-threaded architecture to decouple heavy visual rendering and real-time DSP operations from React's main UI thread, ensuring glitch-free audio performance and ultra-smooth interface visuals.

mermaid
graph TD
    %% Define Threads/Contexts
    subgraph MainThread ["React Main Thread (UI & State)"]
        ReactUI["React Components <br> (DeckSection, Controls)"]
        Store["Zustand Store <br> (mixiStore, settingsStore)"]
        Engine["MixiEngine (Web Audio API)"]
        Ticker["Main rAF Loop <br> (Time Poller)"]
        CanvasElement["HTMLCanvasElement <br> (Input Target)"]
    end

    subgraph WorkerThread ["Web Worker Thread (Waveform Renderer)"]
        Worker["Waveform Web Worker <br> (waveform.worker.ts)"]
        Offscreen["OffscreenCanvas <br> (Drawing Context)"]
        Interpolator["Time Interpolator <br> (performance.now)"]
    end

    subgraph AudioThread ["AudioWorklet Thread (Real-Time DSP)"]
        WorkletNode["AudioWorkletProcessor <br> (Rust/Wasm DSP Engine)"]
        RingBuffer["SharedArrayBuffer <br> (Lock-Free Ring Buffer)"]
        ParamBus["SharedArrayBuffer <br> (Parameter / VU Bus)"]
    end

    %% Communication Flows
    CanvasElement -- "1. transferControlToOffscreen()" --> Offscreen
    ReactUI -- "2. Drag/Scroll Events" --> Store
    Store -- "3. State Update (Structured Clone)" --> Worker
    Ticker -- "4. Ticks & Zoom (Structured Clone)" --> Worker
    
    Worker --> Interpolator
    Interpolator --> Offscreen
    
    Engine -- "5. Audio Node Controls" --> WorkletNode
    ReactUI -- "6. Lock-Free Params" --> ParamBus
    ParamBus -- "7. Real-Time VU Meters" --> ReactUI
    Engine -- "8. Stream PCM Data" --> RingBuffer
    RingBuffer -- "9. DSP Block Processing (128 samples)" --> WorkletNode

Execution Contexts & Thread Boundaries

  1. React Main Thread:

    • Responsibility: Handles user interactions (pointer drags, scroll zooms, context menus), React layout rendering, application state via Zustand stores, and general lifecycle coordination of the MixiEngine.
    • Waveform Interface: Relays mouse/drag events to coordinates conversion and manages a lightweight requestAnimationFrame ticking loop that forwards the deck playhead states to the worker.
  2. Waveform Web Worker Thread (waveform.worker.ts):

    • Responsibility: Conducts all canvas operations for waveform rendering (additive RGB bands, beatgrid lines, loop overlays, cue markers, drops, playheads, and downbeat flashes).
    • Time Interpolation: Runs its own requestAnimationFrame loop. It calculates elapsed time via performance.now() since the last received main thread playhead tick, ensuring continuous scroll updates at up to 60fps even if React is performing heavy render operations on the main thread.
    • Communication/Serialization:
      • Canvas rendering is offloaded by calling canvas.transferControlToOffscreen() and passing the OffscreenCanvas container during initialization.
      • Parameter states and tick coordinates are passed via postMessage(), serialized using the browser's built-in Structured Clone Algorithm (zero-copy for canvas and optimized object cloning).
  3. AudioWorklet Thread:

    • Responsibility: Executes real-time digital signal processing (DSP) loops for mixers, filters, and deck channels at high-priority thread levels in the browser's audio subsystem.
    • Communication/Serialization:
      • Uses SharedArrayBuffer (SAB) containers for lock-free parameter transmission and real-time VU metering, avoiding main-thread message-passing latency and garbage collection interruptions.
      • Utilizes lock-free ring buffers (built on SAB) to stream decrypted audio PCM blocks from the main thread database to the Wasm DSP engine.

Performance Patterns

Direct DOM Mutation

VU meters, phase meter, and limiter dot update at 30fps via requestAnimationFrame with frame-skipping, writing directly to DOM refs — zero React re-renders.

AudioWorklet Usage

WorkletFilePurpose
mixi-dsp-processormixi-dsp-worklet.jsFull Rust/Wasm signal chain
diode-ladder-processordiode-ladder-processor.jsTurboBass 4-pole diode ladder filter
recording-taprecording-tap.jsDisk recording bridge

React Bridge

useMixiSync and useMixiBridge hooks synchronize the Zustand store with the audio engine bidirectionally.

Watermarking

Three-tier system (all zero-impact on audio quality):

  1. UI Fingerprint — Invisible canvas overlay with per-session build hash at sub-1% opacity
  2. Code Fingerprint — Zero-Width Character steganography in compiled CSS/skin files
  3. Audio Container — Encrypted build metadata appended to exported recording containers (no audio samples modified)