Skip to content

fix: studio save, memory and storage issues in multitrack recording - #28

Open
Nowkoo wants to merge 6 commits into
mainfrom
fix/multitrack-recording-bugs
Open

Nowkoo wants to merge 6 commits into
mainfrom
fix/multitrack-recording-bugs

Conversation

@Nowkoo

@Nowkoo Nowkoo commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Fixes bugs and performance problems found while reviewing the multitrack studio released in v3.3.0, focused on server-thread stalls, memory use and disk growth. One commit per topic.

Correctness

  • Stopping a take no longer blocks the server thread. The final take is written by the shared FIFO writer after any older checkpoint; it stays in memory while saving, and edits are refused until the write completes. A failed write keeps the take for retry.
  • Keeping a take uses the track's current volume and mute, not the mix captured when recording started.
  • Stop cancels private samples (previews, backing tracks, metronome) already sent to the client. They now use the Players category and are stopped per sound; live instruments and jukeboxes keep Records and are not cut.
  • Studio files share a 32 MB read/write limit, checked before replacing the previous file, so a saved project can always be read back.

Memory and server-thread time
Measured with 36 projects of 7,500 notes (TF Main limits):

  • Decoded notes share one copy of each instrument and sample name: a project goes from about 1.11 MB to 0.22 MB of heap.
  • The library, /music projects, the 36-project limit and deletion read a per-owner library.index of project summaries instead of decoding every project. Listing goes from about 1.9 s and 40 MB to under 5 ms. The index is keyed by file size and modification time and rebuilds itself when missing, stale or damaged. The first listing after upgrading builds it once.
  • Saves no longer reparse the selected file each time (also on every checkpoint), and serialize the project once for both copies.
  • Disconnect and shutdown write only unsaved takes instead of every cached project, and a disconnect evicts the cached project. "Take saved" is sent only for finished takes.
  • Jukebox playback reads the record once a second instead of copying the block state every tick. Ejecting or breaking still stops it immediately.
  • The jukebox click handler checks the block type before getState(), and ItemsAdder station lookups cache their reflective methods.

Disk

  • Edition IDs are derived from their content, so republishing unchanged music reuses the earlier edition instead of adding a file.
  • New publish-cooldown-seconds in studio.yml (default 30, 0 disables).
  • Startup removes studio-*.tmp files left by an interrupted write.

Behaviour changes

  • The delete confirmation compares a project summary (title, track count, length, pending take). Mix-only changes no longer block a confirmed deletion.
  • Identical republications share an edition ID.

Validation

  • Java 21 mvn clean verify: 298 tests passed; 100% instruction and branch coverage, with no production exclusions.
  • Still to check on TF Dev with a real client: the audio behaviour of Stop and the Players slider.

🤖 Generated with Claude Code

@github-actions github-actions Bot added the size:L 100-499 effective changed lines (tests excluded in mixed PRs). label Oct 11, 2026
@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b9970592-6757-4eb5-880f-69178bb787c1

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Nowkoo and others added 5 commits October 11, 2026 20:46
Decoded notes now share one copy of each instrument and sample name,
cutting a 7,500-note project from about 1.1 MB to 0.2 MB of heap. Saves
check the legacy single-project layout once per owner instead of parsing
the selected file on every save and checkpoint. The sample-name pattern
is compiled once, and publishing checks audibility without building a
full timeline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cached projects already match their files except for a final take that
is still saving or whose write failed. Disconnects and shutdown now
retry only those, instead of rewriting every cached project and risking
the shutdown timeout. A disconnect evicts a current project from memory.
"Take saved" is announced only for finished takes, not for these saves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The library, /music projects, the 36-project limit and deletion now use
project summaries (title, tracks, length, pending slot) instead of
decoding every project on the server thread. Summaries are cached in a
per-owner library.index file keyed by each project file's size and
modification time. save() updates it, and listing rebuilds missing,
stale or damaged entries, so files changed outside the studio stay
correct.

With 36 projects of 7,500 notes, listing drops from about 1.9 s and
40 MB to under 5 ms. The first listing after upgrading builds the index
once.

The delete confirmation keeps a summary rather than the whole project,
and rejects the deletion if the summary changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Published editions are kept forever because discs reference them, and
republishing over a recorded disc added a new file every two clicks.
Edition IDs are now derived from their content, so republishing
unchanged music reuses the earlier edition. A configurable
publish-cooldown-seconds (default 30, 0 disables) limits how often a
player can publish.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Jukebox playback reads the cheap block type every tick and the record,
  which copies the block state and item, once a second. Ejecting or
  breaking the jukebox still stops playback immediately.
- The jukebox click handler checks the block type before getState(), so
  right-clicking chests no longer copies their inventories.
- ItemsAdder station lookups resolve their reflective methods once
  instead of on every right-click and menu refresh.
- Saving serializes the project once for both copies.
- Startup removes studio-*.tmp files left by an interrupted write.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Nowkoo Nowkoo changed the title fix: save studio takes asynchronously and preserve playback controls fix: studio save, memory and storage issues in multitrack recording Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 effective changed lines (tests excluded in mixed PRs).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant