Skip to content

Feat/library stems midi first class#29

Merged
danieljtrujillo merged 3 commits into
mainfrom
feat/library-stems-midi-first-class
Jun 14, 2026
Merged

Feat/library stems midi first class#29
danieljtrujillo merged 3 commits into
mainfrom
feat/library-stems-midi-first-class

Conversation

@danieljtrujillo

Copy link
Copy Markdown
Collaborator

feat(library): make stems & MIDI first-class]

Stems and MIDI in the library can now be played, favorited, deleted, and
routed anywhere audio goes, instead of only offering a right-click send menu.

  • DB schema v5: favorite column on stems + midis; get/set-favorite/delete
    methods for both.
  • Endpoints: PATCH/DELETE /api/library/stems/{id} and
    PATCH/DELETE /api/midi/file/{id} (delete removes the file + row, leaves
    the parent track and siblings intact).
  • Library STEMS/MIDI rows get inline play/pause, favorite star, and delete;
    MIDI right-click now routes to editor/init/inpaint/chimera.
  • Shared lib/midiSynth.ts extracts the offline synth voice + WAV encoder
    (renderNotesToBlob / renderStepNotesToBlob / renderMidiBufferToBlob);
    PianoRoll delegates to it so previews, the editor bounce, and library MIDI
    all sound identical. midiIdToSendable() makes any library MIDI a lazy
    SendableAudio.

fix: module-list reliability, Windows MIDI/stems incidents, Suno a11y

Settings 'Backend Modules' could show a false 'No modules found' when opened
during a backend (re)start, because the modal fetched on open and silently
blanked on any error. Now the catalog loads once on backend-ready into a
shared moduleStore (retry-until-success, cached) and Settings just reads it,
so there is nothing to fail on open; a real error shows an error + Retry.

Also:

  • MIDI (Windows): basic-pitch's emoji status output no longer crashes MIDI
    conversion on cp1252 consoles — its stdout/stderr is captured into a text
    buffer (engine.py), so transcription failures report the real cause.
  • Stems sidecar: probe now checks all critical packages (demucs/torch/
    torchaudio/torchcrepe), and ensure_running installs deps BEFORE spawning
    when any are missing instead of letting run_backend.py self-install and burn
    the 300s readiness window; the timeout error now names the dep state.
  • Suno API key field is wrapped in a with an associated label and
    autoComplete=off (silences the 'password field not in a form' warning).
  • docs: record Phase I (stems/MIDI), G15 (device errors + Quest video-in),
    and H1/H2 status in the plan.

fix(generate): reliably surface freshly-generated tracks in the library (G1)

After a generation completes the backend writes artifacts synchronously, but
the library list index can lag that write by a beat — when it did, the entry
wasn't in the just-refreshed list and the track silently failed to appear
('manual reload'). Now the post-generation reconciliation retries the refresh
a few times until the expected <job_id>_ id shows up, and on genuine
failure surfaces a visible status message instead of only logging.

Verified the rest of the add-to-library chain end-to-end: the /api/library/
import endpoint (200 + full entry), the frontend contract, importEntry's
in-place store update, and the backend's <job_id>_ id scheme all match.

docs: record G15 research findings (Quest video-in without MQDH — scrcpy+OBS
virtual cam Tier 1 needs only a VJ device picker; raw passthrough is Tier 2
via the Unity Passthrough Camera API).

Stems and MIDI in the library can now be played, favorited, deleted, and
routed anywhere audio goes, instead of only offering a right-click send menu.

- DB schema v5: favorite column on stems + midis; get/set-favorite/delete
  methods for both.
- Endpoints: PATCH/DELETE /api/library/stems/{id} and
  PATCH/DELETE /api/midi/file/{id} (delete removes the file + row, leaves
  the parent track and siblings intact).
- Library STEMS/MIDI rows get inline play/pause, favorite star, and delete;
  MIDI right-click now routes to editor/init/inpaint/chimera.
- Shared lib/midiSynth.ts extracts the offline synth voice + WAV encoder
  (renderNotesToBlob / renderStepNotesToBlob / renderMidiBufferToBlob);
  PianoRoll delegates to it so previews, the editor bounce, and library MIDI
  all sound identical. midiIdToSendable() makes any library MIDI a lazy
  SendableAudio.
Settings 'Backend Modules' could show a false 'No modules found' when opened
during a backend (re)start, because the modal fetched on open and silently
blanked on any error. Now the catalog loads once on backend-ready into a
shared moduleStore (retry-until-success, cached) and Settings just reads it,
so there is nothing to fail on open; a real error shows an error + Retry.

Also:
- MIDI (Windows): basic-pitch's emoji status output no longer crashes MIDI
  conversion on cp1252 consoles — its stdout/stderr is captured into a text
  buffer (engine.py), so transcription failures report the real cause.
- Stems sidecar: probe now checks all critical packages (demucs/torch/
  torchaudio/torchcrepe), and ensure_running installs deps BEFORE spawning
  when any are missing instead of letting run_backend.py self-install and burn
  the 300s readiness window; the timeout error now names the dep state.
- Suno API key field is wrapped in a <form> with an associated label and
  autoComplete=off (silences the 'password field not in a form' warning).
- docs: record Phase I (stems/MIDI), G15 (device errors + Quest video-in),
  and H1/H2 status in the plan.
…ry (G1)

After a generation completes the backend writes artifacts synchronously, but
the library list index can lag that write by a beat — when it did, the entry
wasn't in the just-refreshed list and the track silently failed to appear
('manual reload'). Now the post-generation reconciliation retries the refresh
a few times until the expected <job_id>_<index> id shows up, and on genuine
failure surfaces a visible status message instead of only logging.

Verified the rest of the add-to-library chain end-to-end: the /api/library/
import endpoint (200 + full entry), the frontend contract, importEntry's
in-place store update, and the backend's <job_id>_<index> id scheme all match.

docs: record G15 research findings (Quest video-in without MQDH — scrcpy+OBS
virtual cam Tier 1 needs only a VJ device picker; raw passthrough is Tier 2
via the Unity Passthrough Camera API).
@danieljtrujillo danieljtrujillo merged commit 5212839 into main Jun 14, 2026
1 check passed
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