Phase 8: Add stereo track mixer, automation and undo/redo

This commit is contained in:
Johannes Findeisen 2026-10-27 01:06:57 +01:00
commit 7db5fb7738
45 changed files with 1611 additions and 130 deletions

98
docs/MIXER.md Normal file
View file

@ -0,0 +1,98 @@
# Mixer, automation and undo
Phase 8 provides one selectable channel strip per project track. Open Mixer
(Ctrl+2), select a track, and set Gain, Pan, Mute and Solo. Changes stop transport;
Play prepares independent audio/MIDI snapshots with the accepted settings.
No edit changes a plan that the callback is using. Editing is blocked while
recording. Graph edits retain their existing live publication behavior.
Gain is a linear multiplier from 0 to 4. Pan ranges from -1 (left) to +1 (right):
center has unity on both sides and moving away attenuates the opposite side
linearly. This preserves existing centered mono levels; it is not an equal-power
pan law. Mute wins over Solo. If any track is soloed, only soloed, unmuted tracks
play. WAV clips and scheduled MIDI use their containing track's settings before
summing into the audio/instrument graph sources. Live MIDI input and independent
graph oscillators/external input are unassigned sources and bypass track mixing.
Stereo WAV files are still downmixed at import; stereo output comes from panning
those mono sources. Separate per-track graph inserts/sends are deferred.
## Automation lanes
Choose Gain or Pan under Automation. The lane shows four bars (15360 ticks);
First tick moves its viewport across the project. Grid labels are absolute ticks.
Click to add a point or replace the point at that snapped time (1/16 note, 240
ticks). Vertical position maps to gain 0..4 or pan -1..1, top to bottom descending.
Right-click near a point's time to remove it. Removing every point restores the
static control. There are at most 1024 points globally, with one per
track/parameter/tick. Track deletion cascades to its automation.
A nonempty lane replaces that parameter's static value. Between points the C
engine interpolates linearly at each sample, holding the first/last value outside
their range. Preparation converts ticks to integer sample endpoints, sorts and
indexes lanes. When several ticks quantize to one sample at very low sample
rates, the last point wins at that sample. Rendering searches prepared bounded
arrays; it never sorts, allocates, accesses project data, or calls the GUI.
Seeking and block partitioning give the same timeline values. Mute/solo are
static; automation capture, modes, curves and tempo automation are deferred.
## Stereo output and meters
The GUI opens the JACK backend with two audio output ports: `output` (left) and
`output_right`. Input and raw WAV recording remain mono. Connect both outputs
explicitly using an external JACK routing tool. Nothing connects hardware
automatically. Legacy configurations with channel_count=1 and the original
port/route APIs remain supported; output_name(channel) queries either stereo
port. Old mono audio/MIDI render functions apply gain/mute/solo and gain
automation while ignoring pan; the stereo variants apply both lanes.
The graph executes the same topology separately on left and right buses;
oscillators advance once per frame and are centered on both sides. Existing
port metadata and validation describe the mono graph topology. Stereo processing
uses explicit paired buffers, not new port IDs. Output buffers must be distinct;
stereo callers must not alias them with source buffers. Graph-node meter reads
report the maximum of both sides on the processing owner only.
Mixer Output L/R bars show last-block post-graph absolute peaks, polled at 100 ms.
Peaks above unity turn red. Independent lock-free integer snapshots avoid sharing
DSP pointers or float state between callback and GUI; stopped meters show zero.
They are output meters, without per-track RMS, peak hold or loudness analysis.
There is no limiter: finite summed output can exceed unity. GUI polling may miss
brief peaks between refreshes; these bars are not overload history.
## Undo and keyboard workflow
Ctrl+Z undoes; Ctrl+Shift+Z or Ctrl+Y redoes. The C history keeps 32 project edits
plus a baseline, cloning metadata and graph, never audio samples. Common graph,
track, clip, note, mixer, import/relink and automation edits are included. One
accepted gesture is one step; selection, scrolling and graph-node placement are
GUI state and are not undoable. New/Open resets history; Save retains it.
Undo/redo stops and resets transport and resets editor selections/layout. The
candidate is installed before moving the history cursor: validation, asset-plan
or backend failure retains the current document and history position. Missing
assets retain the existing silent/reporting behavior. A new edit after Undo
removes the redo branch; the oldest state is evicted at capacity. Allocation
ID high-water marks survive Undo/branching so abandoned IDs are not reused. History is
session-only and Undo marks the document dirty even if it matches a saved state.
External WAV files are never deleted or restored by Undo; recording itself cannot
be undone while active. An allocation failure retaining a new history snapshot
reports an error; the accepted edit remains in the document.
With mixer focus, M/S toggles mute/solo, Left/Right changes gain by 0.05,
Shift+Left/Right changes pan, and Up/Down selects a track. Native sliders also
support keyboard navigation; Ctrl+1/2/3 switches views, Ctrl+4 opens Piano roll,
F5/F8/Space controls transport and F9 panics, as before. There is no multiselection,
clipboard editing, track rename or automation-point dragging yet.
## Verification and limits
`test_mixer` verifies exact stereo gain/pan, mute/solo precedence, automation
samples and block equivalence, stereo graph phase/routing, WAV mixing, v4 exact
roundtrip/truncations/malformed records, lane capacities and history eviction and
branching. Backend fault injection verifies stereo registration failure, output
names, output separation and atomic meters. GUI tests edit lanes with mouse
events, use mixer keys and exercise undo/redo, failed installation rollback,
branching, save/reopen and history reset. Live JACK MIDI acceptance verifies
saved/reopened hard-right playback and stereo peaks using only software clients.
A native Xvfb mouse smoke check covers sliders and automation drawing.
Physical stereo devices, listening quality, realtime endurance and high-density
project performance remain unverified; no new dependency was introduced.