Skip to content

Undo, save and playback fixes found by the equivalence harness - #397

Open
thacer13 wants to merge 19 commits into
mainfrom
undo-save-playback-fixes
Open

thacer13 wants to merge 19 commits into
mainfrom
undo-save-playback-fixes

Conversation

@thacer13

Copy link
Copy Markdown
Collaborator

Nineteen fixes, each one where Lemon Studio's state went out of step with itself: an undo that did not give the
project back, a save that did not reopen as saved, or playback that did not hold what the project says. They were found
by the equivalence harness of the control-plane plan (specs roadmap/control-plane.md part 2, step 0), which drives the
app on FL's 151 bundled projects with random clicks, drags, wheels and keys, and checks at the end of each trace that
undo goes back to the start, redo to the end, a saved copy opens as the same project and the engine holds the project.
They go in before the refactor so that its steps can each be held to "no change at all".

Each fix has a test that fails without it. The whole os-app suite passes.

Undo

  • Undo and redo of a pattern edit leave the pattern shown, as in FL. Measured on FL 24.1.1: a step sequencer edit
    and a piano roll note in one pattern, undone and redone while another pattern was shown; FL kept showing the other.
    Lemon switched to the pattern edited.
  • Undo of a whole-project step (adding an effect, channel and track edits) puts back the rack's loop mode and type
    with its lengths, the mixer's slot colours and icons and the rack's loop points; it leaves the pattern shown, except
    for steps that make or remove patterns (a clone, a delete), which show the pattern they showed.
  • An edit no longer drops the knob step before it when the edit renumbers what the step names (a track deleted
    after a knob on a later track was wheeled: the knob's step read as unchanged and went).
  • Undo of a send level puts back no level record when the route had none (it left one at unity, and the saved file
    differed).
  • A piano roll tool's preview (Chop, Quantize and the others) is put back in its own pattern when another pattern is
    shown while the dialog is open; before, the previewed notes stayed, with no undo step.
  • Undo steps FL makes and Lemon did not: a drag in the channel rack's graph editor ("Graph editor change velocity",
    ui/undo-steps.md), Shift+wheel moving a channel (Move channel), Open audio editor adding Tesla (measured on FL
    24.1.1: "Insert effect plugin").

Save

  • The rack's loop lengths follow the pattern shown: each pattern keeps its own, as the file stores them; a save
    wrote the lengths of the pattern opened over the pattern shown.
  • A saved project opens again on the pattern shown when it was saved, with that pattern's loops.
  • A mixer track's equaliser is saved.
  • Loop mode with every channel following the pattern survives a save.
  • Stereo separation moves in 64ths, the steps the file keeps (measured on FL 24.1.1); it was continuous and only
    rounded at save.
  • A new audio or automation clip holds the offsets FL writes for it (float −1.0, flp/events/playlist.md); it held
    the pattern clips' encoding until a save and reopen.

Playback

  • A song with no clips plays the pattern shown, not the pattern the project was opened or saved on.
  • A save hands what it writes into the project to playback (the tempo, song mode, the pattern shown, the rack's
    groups and loops, the playlist's view): the engine kept the project from before the save until the next edit.
  • Tempo changes while playing reach recording and the latency box, which timed beats at the tempo of Play.
  • A playlist solo is over once it no longer holds, as in the channel rack and the mixer.

Measured

The harness's recording of FL's 151 bundled projects (one 300-step trace each), on main and on this branch:

What the end checks report Traces on main With these fixes
a saved copy opens on another pattern than the one shown 96 0
a mixer track's equaliser not as saved 50 0
redo to the end shows another pattern than the edit left 36 0
undo to the start leaves a mixer slot filled 33 0
stereo separation not as saved 20 0
a send level after undo or save not as it was, or a channel moved with no undo step 4 0
a resave writes other loop lengths 2 0
any of these 139 0

How to check

cargo test -p os-app --bin lemonstudio (the new tests are named after what they check). The harness itself comes
in its own pull request; on this branch's build its recording of the 151 projects reports nothing that is not on its accepted list.

🤖 Generated with Claude Code

thacer13 and others added 19 commits November 10, 2026 06:10
The count-in, one-click and track recording clip lengths, the score log, an audio file's clip length and the
latency box's beat unit read project.tempo, which holds the tempo as last opened or saved, not the tempo playing
(State.tempo). Found by the equivalence harness survey.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cons and the rack's loop points

The snapshot of a whole-project step (Side) kept the slot names but not the slot colours, the icons or Advanced
looping's loop points. Undoing a mixer track delete or move left the colours and icons on the tracks they had
moved to, and undoing a channel delete lost its loop points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ith that pattern's loops

The current pattern (event 67) was read on open but never written back, so a project always reopened on the
pattern it was first opened with, while the rack saved its loop lengths into the pattern shown at save: those
loops came back on the wrong pattern or not at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ck and the mixer

The playlist kept its solo's saved track states across an arrangement switch, track moves and undo. Soloing
again then wrote the first arrangement's states, by track number, onto the tracks shown. A solo whose shape no
longer holds now starts afresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tern holds a note so it is saved

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Saving into a file wrote a track's volume, pan and stereo separation but never its equaliser, and a new track got
the default bands: every EQ edit was lost on save. Found by the equivalence harness's round trip (Drumloop Masher:
a band's frequency dragged, saved, opened again at the old value).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pattern whose loop mode is on with every channel following it (FL's file: follow entries, no lengths, no
loop_off) opened with loop mode on, but a save wrote no loops, so it opened again with loop mode off. The rack
now writes follow entries for that state, and leaves a pattern's loops as the file has them while they say what
the rack holds. Found by the equivalence harness (Inner Days SH-1 Rework, opened and saved twice).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… menu and Alt+Up / Down

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n moves in 64ths, as measured on FL

FL 24.1.1 records "Insert effect plugin" when Open audio editor adds Edison; Lemon's Tesla made no step (the
toolbar button and Open audio editor and record too). FL's separation knob sets whole 64ths, the steps the file
keeps (audio/mixer.md); Lemon's was continuous and only rounded at save.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e (it left one at unity: the saved file differed)

Found by the equivalence harness (System/Render tests/Hardcore.flp, undo-to-start).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its own, and a save no longer writes the lengths of the pattern opened over the pattern shown

Found by the equivalence harness (Electroconductor - Inner Days - Original.flp: switch pattern, save, the pattern's loop lengths gone).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n when another pattern is shown meanwhile

The tool dialogs (Chop, Quantize, Flam and the others) preview on the notes without an undo step. A switch to
another pattern while one was open (New pattern, the pattern selector) left the previewed notes in the old pattern:
cancel, Accept and the next preview each skipped the put-back, so no undo could bring the notes back. Found by the
equivalence harness (3OSC, Ogun: undo to the start left a chopped note).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on FL 24.1.1 (2026-11-09, hidden display): a step sequencer edit and a piano roll note added in one pattern,
then another pattern shown; undo and redo changed the first pattern's notes and FL kept showing the other. Lemon
switched to the pattern edited. Found by the equivalence harness (redo to the end showed another pattern than before,
6 of 151 projects).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ui/undo-steps.md measured "Graph editor change velocity", one per drag, on FL 24.1.1; Lemon recorded none, so undo
skipped the drag and took back the edit before it. A press that changes nothing leaves no step. Reported by the
lead's FL parity audit (2026-11-08, row "Graph editor undo step").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…with its lengths, and leaves the pattern shown

The project snapshot (Add effect, channel and track edits) held the rack's loop lengths but not its loop mode or type:
after an undo the rack paired one pattern's lengths with another's mode, and the next pattern switch wrote that into
the pattern without an undo step (equivalence harness, DEDZII - NIGHT TERROR). The undo also showed the pattern shown
when the step was made; it now leaves the pattern shown, as FL does for pattern edits (2318a9c0), except for steps that
make or remove patterns (a clone, a delete), which show the pattern they showed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ject was opened or saved on

The engine plays the project's current pattern in song mode when the playlist has no clips; play_project handed it
the pattern from the last open or save, so a switch was not heard until a save. It now hands the pattern shown, and a
pattern switch reaches playback. Found by the equivalence harness (I'll Be Your Madonna: after Save new version, the
engine held another pattern than the project).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rs what the step names

An edit judged whether the newest pressed step had changed anything after making its own change: a mixer track
deleted before a wheeled knob's track put another track's value in that place, the knob's step read as unchanged and
was dropped, so undo could not take the turn back. The check now runs before the edit. Found by the equivalence
harness (nucleon - Fruity Delay 3: stereo separation wheeled, a track deleted).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A save writes the interface's part of the project into it (the tempo, song mode, the pattern shown, the rack's groups
and loops, the playlist's view); the engine kept the project from before, so it held another project than the one
saved until the next edit. The save now marks the project changed when it wrote something new, as an edit does.
Found by the equivalence harness (I'll Be Your Madonna, Electro: Save new version, then the engine was behind).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oat -1.0, not the pattern clips' ff bytes)

Painting a channel clip kept the pattern encoding in memory; the save wrote -1.0, so the reopened project
differed from the one saved (found by the equivalence harness on Olbaid - Sytrus Essentials: fill paint, save).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant