Skip to content

fix(editor): a MIDI create-import no longer silently loses the drums#354

Merged
ChrisBeWithYou merged 2 commits into
mainfrom
feat/midi-drum-autosplit
Jul 22, 2026
Merged

fix(editor): a MIDI create-import no longer silently loses the drums#354
ChrisBeWithYou merged 2 commits into
mainfrom
feat/midi-drum-autosplit

Conversation

@ChrisBeWithYou

Copy link
Copy Markdown
Contributor

The bug

Create a project from a multi-track MIDI (drums + bass + guitar + keys) and the drums silently disappear — you get every part except the drums, with no warning.

Root cause is in core: list_midi_tracks deliberately excludes channel-9 (a keys-import of a GM-percussion channel yields an empty arrangement), so a drums track never reaches the create picker at all. The dedicated "Add Drums" flow handles MIDI drums correctly; the generic create-import just drops them.

The fix (editor-only, no core change)

Reuse the drum path core already ships:

  • /import-midi now also returns the channel-9 drum_tracks (via the existing list_drum_tracks) alongside the pitched tracks.
  • The create flow auto-imports each drum track as its own type:"drums" arrangement — the same auto-split the Guitar Pro create-import already does — running after the pitched import so each drum part has a pitched sibling to materialize beside.
  • Drums ride a separate list (createState.midiDrumTracks) from the pitched picker, so the existing pitched selection/import path is completely untouched — no row-id/index collision (which matters for format-0 files that split pitched + drums across one track index). A drums-only MIDI still imports as a drums session.
  • /import-drums-midi now accepts the create-flow upload path (slopsmith_midi_…) in addition to the Add-Drums list path (slopsmith_drums_midi_…), so the picker reuses the file it already staged.
  • The drum-tab stash step (sort hits → add-as-extra-or-primary → materialize beside a pitched part → land as a region) is factored into a shared _stashImportedDrumTab that the Add-Drums modal now reuses too (DRY, one behavior).

Scope

This is the "MIDI ch9 auto-split" slice of the multitrack-P1 remainder. The rest of that card (instrument-type-as-data, drums-as-arrangements, several drum parts, the Add-Drums flow, GP auto-split) already shipped in #335#345 — this brings MIDI create-import to parity with the GP path. Two related residuals are left for follow-ups: whole-song GP import still folds multiple drum tracks into one part, and re-typing an arrangement to/from drums is still deferred.

Tests

  • tests/midi_drum_autosplit.test.mjs (6 cases) pins the stateful wiring, not just a pure helper: per-track routing to import-drums-midi with the right track_index/arrangement_name, materialization of one type:"drums" part per track, skip of note-less tracks (no backend call), resilience when one track's import fails (the rest still import), the no-session/no-path/empty-list guards, and the shared _stashImportedDrumTab (hit-sort, dirty flag, selection clear, add-vs-primary).
  • Full pytest green (381 passed, 5 skipped); lint clean (0 errors). JS suite unchanged apart from the two known-on-main reds (mixer_meter_teardown, song_fit).
  • Runtime-verified end-to-end on the real host: a synthesized MIDI with a channel-9 drums track + a pitched track returns drum_tracks: [(1, 'Drums', 6 notes, is_drums=True, ch=9)] from /import-midi while the pitched track stays pitched, and /import-drums-midi on the create-flow path converts it to a 6-hit drum_tab (error=None).

🤖 Generated with Claude Code

Core's `list_midi_tracks` excludes channel-9 (a keys-import of a drum
channel yields an empty arrangement), so when you created a project from
a multi-track MIDI the drum track never reached the picker and vanished —
a full-band MIDI came in with everything except its drums.

/import-midi now also returns the channel-9 `drum_tracks` (via the
existing `list_drum_tracks`), and the create flow auto-imports each as
its own type:"drums" arrangement, mirroring the auto-split the Guitar Pro
create-import already does. Drums ride a SEPARATE list from the pitched
picker, so the existing pitched selection/import path is untouched (no
row-id or index collision); a drums-only MIDI still imports as a drums
session. /import-drums-midi now accepts the create-flow upload path
(slopsmith_midi_) as well as the Add-Drums list path, and the drum-tab
stash step (sort hits, add-as-extra-or-primary, materialize beside a
pitched part, land as a region) is factored into a shared
_stashImportedDrumTab that the Add-Drums modal now reuses too.

Tests: tests/midi_drum_autosplit.test.mjs pins the stateful wiring
(per-track routing, request params, empty/failed-track resilience,
guards, and the shared stash). Full pytest green (381); lint clean; the
only JS reds are the two known-on-main failures (mixer_meter_teardown,
song_fit). Runtime-verified end-to-end on the real host: a synthesized
MIDI with a ch9 drums track surfaces in drum_tracks and converts to a
6-hit drum_tab through the create-flow path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017xGPjDBF8NTwTK7VQvizix
Signed-off-by: ChrisBeWithYou <chris@rifflarr.local>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@ChrisBeWithYou, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 27 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 55e330e8-95d4-4a90-9b42-0dafa6d78ff2

📥 Commits

Reviewing files that changed from the base of the PR and between ba4f924 and a3f0a7e.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • routes.py
  • src/arrangement.js
  • src/create.js
  • src/import.js
  • tests/midi_drum_autosplit.test.mjs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/midi-drum-autosplit

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.

@ChrisBeWithYou
ChrisBeWithYou merged commit 33fa3d1 into main Jul 22, 2026
4 checks 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