feat(studio): automation lanes in the timeline, and automate/un-automate from the panel - #3018
Closed
vanceingalls wants to merge 2 commits into
Closed
feat(studio): automation lanes in the timeline, and automate/un-automate from the panel#3018vanceingalls wants to merge 2 commits into
vanceingalls wants to merge 2 commits into
Conversation
Draws each automated parameter as its own lane under the audio clip, on the same disclosure caret the keyframe lanes use — that caret is the DAW automation triangle. One lane per parameter rather than a selector to swap between them, so two envelopes can be read and edited without hiding either. Editing is the DAW gesture set: double-click the line to add a point, drag to shape it, right-click a point to remove it. Dragging writes live so playback is not interrupted, and a local draft carries the point under the pointer — the live write deliberately skips the refresh, so the stored value does not move until the edit comes back around, and without the draft the point would not follow the cursor. Everything the lane knows about a parameter comes from the FX registry: range, unit, and whether it reads logarithmically. A log knob is drawn and dragged on a log axis, so the curve on screen is the curve the audio thread plays. Lanes are bound to the chain the way preview and the render bind them, so one whose effect was deleted is dropped rather than drawn against the wrong axis. Row height reserves each lane, the envelope is inset so a point at the clip's first or last frame is drawn whole rather than half outside it, and pressing a lane on an unselected clip selects it — lanes sit below the clip bar, where the timeline's own selection handler never sees the press. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An automated parameter's control is disabled, since a value set there would be overwritten by the envelope on the next tick — the lane is the value now. Each automatable parameter gets a toggle beside it: adding a lane seeds it with a single point at the value the control already holds, so switching to an envelope never changes the sound, only where the value comes from. Toggling it off deletes that lane and hands the value back. Parameters no envelope can drive have no toggle at all — the worklet-backed dynamics, a WaveShaper's curve, a convolution impulse — and neither does a chain node with no id, since a lane addresses nodes by id. Adding an effect now mints one. Writes go through a new commit that persists without reloading the preview but still re-reads the selection. Both halves are needed: the reload restarts every playing track, and without the resync the panel keeps reading the snapshot it was built with, so a second edit computes from a pre-edit value and appears to do nothing — deleting one effect made every later delete a no-op. Carve is on that path too, and decodes its source in an OfflineAudioContext: opening a second output device mid-playback makes the running track glitch while the hardware is reconfigured. Turning carve off now also drops the filters it generated, which otherwise kept dipping the bed with nothing to explain it. AudioFxGroup moves into its own module — PropertyPanelFlat was already at its size budget — and both panel sections read automation through one helper, which is what surfaced that resolving against an absent chain would have deleted every FX lane the moment someone automated a volume. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Superseded by stack #3027. This PR carried the studio UI in one diff (+2397); it is now #3023 lane geometry and plumbing, #3024 the lane component, #3025 the non-reloading write path + volume, #3026 the per-parameter surface — each under 1000 LOC, with the pure lane maths extracted into its own module along the way. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #3017. The UI.
Lanes. Each automated parameter draws its own lane under the audio clip, on
the same disclosure caret the keyframe lanes use — that caret is the DAW
automation triangle. One lane per parameter rather than a selector to swap
between them, so two envelopes can be read and edited without hiding either.
Double-click the line to add a point, drag to shape it, right-click a point to
remove it.
Everything the lane knows comes from the FX registry — range, unit, log scale —
so a log knob is drawn and dragged on a log axis, and the curve on screen is
the curve the audio thread plays.
Panel. An automated parameter's control is disabled, since a value set there
would be overwritten by the envelope on the next tick. Each automatable
parameter gets a toggle: adding a lane seeds it with a single point at the value
the control already holds, so switching to an envelope never changes the sound,
only where the value comes from. Parameters no envelope can drive have no toggle
at all.
Things that took more than one attempt
refresh, so the stored value does not move under the pointer; the lane needed a
local draft. Releasing it then snapped back until the draft was made to survive
until the prop changed rather than until the drag ended — which in turn
needed the parsed attribute cached, or a fresh object each playhead tick threw
the drag away.
but does not resync the selection, so the panel kept computing from the
snapshot it was built with. Added a commit that skips the reload and resyncs;
both halves are needed, and they were fighting each other.
does not parse the chain, and resolving against an absent chain drops every
lane it cannot resolve. Now "no chain" means "do not resolve" rather than "drop".
AudioContextjust to decode;it decodes in an
OfflineAudioContext, which touches no device. Turning carveoff now also drops the filters it generated.
AudioFxGroupmoves into its own module andAUTOMATION_LANE_Hinto its own —PropertyPanelFlatandtimelineLayoutwere both at the 600-line studio limit.🤖 Generated with Claude Code