Skip to content

DRAFT: Multi MIDI File Import - #564

Open
szydek wants to merge 51 commits into
charlesvestal:mainfrom
szydek:multi-midi-import
Open

DRAFT: Multi MIDI File Import#564
szydek wants to merge 51 commits into
charlesvestal:mainfrom
szydek:multi-midi-import

Conversation

@szydek

@szydek szydek commented Jun 6, 2026

Copy link
Copy Markdown

Summary

Enhances the MIDI upload workflow to support multiple files with independent track assignments. Users can now build complete multi-track sets by uploading several MIDI files at once, assigning each to tracks 1-4.

Features

  • Multi-file selection: Upload one or more .mid/.midi files simultaneously
  • Per-file track assignment: Each file gets its own Track 1-4 dropdown
  • Smart slot filling: Multiple files targeting the same track fill empty clip slots sequentially
  • Create new or add to existing: Support for both new set creation and adding clips to existing sets
  • Visual color selection: Color swatch dropdowns for pad and clip colors
  • BPM preservation: Maintains existing set tempo when adding clips

Changes

  • Replaces single-file upload with multi-file interface
  • Removes "MIDI Type" dropdown (no longer needed)
  • Dynamic track assignment UI appears after file selection
  • New save_uploaded_file() helper for batch processing
  • Path aggregation for multi-file new set creation

Testing

  • Single file → new set
  • Multiple files → new set (different tracks)
  • Multiple files → existing set
  • Same track → fills empty clip slots
  • Clip colors inherit from pad color for new sets

szydek added 30 commits May 24, 2026 22:00
- Pad grid (bottom-to-top, matching hardware layout) with BPM, colors, active fill
- Active pad highlighted with color fill + pulsing orange border, updates every 2s
- Storage, memory, and CPU load bars
- Sets table with BPM, key, mode, Camelot code
- Camelot key filter buttons
- Dark/light theme toggle with localStorage persistence
- /overview/api/data, /active-slot, /system endpoints
- Uses os.getxattr() instead of subprocess/getfattr
- Update base_handler.py to generate semi-transparent RGBA backgrounds (20% opacity)
  with solid borders for occupied pads, matching Overview page behavior
- Add shared CSS variables (--pg-*) to style.css for consistent theming
- Add disabled pad opacity (0.5-0.6) for non-selectable pads
- Add shared JavaScript to base.html for selected pad highlighting (40% opacity)
- Ensure all pages (Overview, Restore, Set Inspector, MIDI Upload) share consistent
  grid layout, colors, borders, and active state styling
- Add global dark mode toggle button to base.html header
- Add dark mode CSS variables and styles to style.css
- Update base.html JavaScript to handle theme toggle and persist to localStorage
- Remove local dark mode from overview.html (theme button, local CSS, local JS)
- Update overview.html to use global #app-wrap.dark for dark mode detection
- Add dark mode variable overrides for Overview page custom CSS
- Ensure consistent dark mode across all pages: Overview, Restore, Set Inspector, MIDI
- Add restore mode toggle button (+ Restore Set) to Overview page
- Restore form appears inline with file upload, color picker dropdown, and target pad selection
- Use the main pad grid for restore: free pads become clickable with dashed borders
- Add client-side color dropdown with JavaScript and /overview/api/colors endpoint
- Add POST /overview/api/restore endpoint for handling uploads
- Remove standalone Restore page navigation link (redirects to Overview)
- Update renderPadGrid to support restoreMode with click handlers on free pads
- Add CSS for restore-mode grid styling and selected pad highlighting
- All restore UX now happens in context of the Overview page's existing pad grid
- Add generate_multichannel_midi_set() to parse MIDI by channel and create multi-track set
- Each MIDI channel (up to 4) becomes a separate track with its own clip
- Error handling for >4 channels with clear user message
- Add 'Multi-Channel (≤4 channels)' option to MIDI type dropdown
- Update handler dispatch to route multichannel type to new function
- Add explanatory help text for all MIDI type options
@szydek szydek changed the title DRAFT: Feat: Multi MIDI File Import DRAFT: feat: Multi MIDI File Import Jun 6, 2026
@szydek szydek changed the title DRAFT: feat: Multi MIDI File Import Feat: Multi MIDI File Import Jun 26, 2026
@szydek

szydek commented Jun 26, 2026

Copy link
Copy Markdown
Author

@charlesvestal - During my testing, this seems to be pretty useful for importing MIDI. I'd be curious to know what you think. Note that it builds upon #563
Thanks!

@szydek szydek changed the title Feat: Multi MIDI File Import feat: Multi MIDI File Import Jun 26, 2026
@charlesvestal

Copy link
Copy Markdown
Owner

Thanks for this — multi-file import with per-track assignment is genuinely useful, and the math.ceil clip-length fix (plus the new test for exact-bar boundaries) is a nice correctness improvement. The core note-extraction in assign_midi_to_track reads well.

A few things before it can merge:

1. It's stacked on #563. This branch was cut from the Overview PR, so the diff contains all of #563. Once #563 lands, please rebase onto main so the diff shrinks to just the MIDI-import changes — much easier to review in isolation, and it depends on #563's generate_pad_grid(..., free_only=True) signature anyway.

2. The drum / 808 path is silently dropped. Removing the "MIDI Type" dropdown deletes the midi_type == 'drum'generate_drum_set_from_file() branch, so all imports now go through the melodic midi_template.abl with no drum-note remapping onto the 808 layout. generate_drum_set_from_file is still imported but never called. If dropping drum import is intended, let's say so and remove the dead import/def; if not, it needs to stay reachable. (Worth noting #559's use case is drum patterns.)

3. A couple of safety basics:

  • assign_midi_to_track does os.path.join("/data/UserData/UserLibrary/Sets", set_name) with no sanitization on set_name — a ../-style name would write outside the sets dir. Please sanitize/validate.
  • No server-side .mid/.midi check (the accept= attribute is client-only). A non-MIDI upload currently fails deep inside mido with a vague message.
  • save_uploaded_file() writes every file to a fixed uploads/ dir by basename, so two selected files named clip.mid overwrite each other before processing (and the server is threaded). Give each upload a unique temp name.

4. "Add to existing" + partial failures. When a set's UUID isn't found, the code falls back to a bare Sets/<name> path that doesn't exist, so it silently creates a new set instead of appending. And when some files in a batch fail, the aggregate is still reported as success: True — the user sees a green banner even though clips are missing. Both should surface as clear errors.

On #559: this adds track-level import but not per-slot targeting in the Set Inspector, so I don't think it closes #559 — I'll keep that open for the inspector-integration work.

Happy to merge #563 first and then take another pass at this once it's rebased.

@szydek szydek changed the title feat: Multi MIDI File Import DRAFT: Multi MIDI File Import Jul 15, 2026
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.

2 participants