A web-based tool and piano roll editor for inspecting, repairing, and adjusting MIDI files generated by audio-to-MIDI transcription models (such as Transkun or Onsets and Frames).
Audio-to-MIDI transcription models frequently produce timing and dynamic range artifacts:
- Orphaned Notes: Due to polyphonic masking or slight timing estimation offsets, individual notes in a chord often release 20–100ms before a sustain pedal (CC64) onset occurs. Because their note-off precedes the pedal-on event, these notes are not held by the sustain envelope and cut off prematurely.
- Duration Truncation: Transcription models can underestimate note durations, producing clipped or overly staccato note-offs.
- Velocity Compression: Transcriptions often map velocities to a narrow dynamic range.
- Identifies notes that release within a configurable lookback window (
$N$ ms) prior to a sustain pedal (CC64$\ge$ 64) onset. - Extends the note-off timestamp to overlap with the pedal onset, ensuring the note is sustained through the pedal hold segment.
- Visualizes repaired notes in green on the piano roll.
- Displays CC64 pedal events and active sustain hold segments below the piano roll.
- Drag nodes horizontally to adjust timing or vertically across the threshold (64) to toggle between pedal ON (127) and OFF (0).
- Double-click empty space to insert a new node, or double-click an existing node to delete it.
- HTML5 2D canvas piano roll rendering an 88-key layout with pitch labels and measure/beat grid lines.
- Visualizes sustained resonance tails indicating the sounding duration until pedal release or the next note of the same pitch.
- Includes a minimap overview of the full piece with a draggable viewport window.
- Supports horizontal and vertical zoom, panning, and trackpad gestures.
- Displays a 128-bin velocity histogram with transfer curve mapping.
- Adjustable input black point (minimum threshold), gamma (midtone power curve), and white point (maximum threshold).
- Auto-levels button detects the minimum and maximum velocities in the file and normalizes them across the 1–127 range.
- Click to Select: Click any note to select and highlight it with a high-contrast white outline.
- Rectangular Marquee Selection: Drag across the piano roll canvas to select multiple notes within a marquee box.
- Shift-Modifiers:
Shift + Clicktoggles individual notes;Shift + Dragadds notes to the existing selection. - Live Sound Preview: Newly selected notes automatically sound through the active SoundFont on click, shift-click, and marquee sweep. Clicking keys on the left vertical piano keyboard also sounds that pitch.
- Nudge Position:
←/→nudges start time back or forward by 4 ticks (40 ticks withShift). - Nudge Duration:
⌥←/⌥→(Alt/Option+ Arrow keys) lengthens or shortens note duration by 4 ticks (40 ticks withShift, minimum 1 tick). - Delete Notes: Press
DeleteorBackspaceto remove selected notes with full undo/redo history support. - Configurable Increments: Hotkeys and nudge tick increments are centralized in
src/config/editorConfig.ts.
- Dedicated 4th card in the bottom inspector panel replacing floating hover cards.
- Single Note Mode: Displays pitch name/MIDI #, start position (ticks & seconds/ms), duration (ticks & seconds/ms), velocity (current & original), sustain status, orphan gap, and hotkey legend.
- Multi-Note Selection Mode: Displays note count badge, pitch range (
C3 – G5), total time span, velocity range, tick span, and multi-note editing guide.
- Constant Duration Offset: Adds or subtracts a fixed millisecond offset across all note durations.
- Minimum Note Duration: Sets a lower bound on note duration to remove micro-duration artifacts.
- Audio playback powered by
spessasynth_librunning in a Web Audio Worklet. - Streams SoundFont presets on-demand from
https://gifx.co/soundfonts/(Yamaha Grand, Chateau Grand, Abbey Steinway D, SC-55, TimGM6mb, etc.) with support for loading custom local.sf2files. - Transport controls include play/pause, loop, return to zero, playback speed multiplier (0.5x–2.0x), follow playhead mode, active voice counter, and timeline scrubbing.
- Original MIDI data remains unmodified in memory; modifiers are applied non-destructively to a derived note list.
- Bypass toggle allows A/B comparison between raw input and modified output.
- Full undo/redo history stack (
Cmd/Ctrl+Z,Cmd/Ctrl+Shift+Z) supporting note deletions, nudges (coalesced), CC64 edits, and modifier updates.
- Drag-and-drop support for
.midand.midifiles, plus a built-in demo file. - Exports standard Type 0/1 binary MIDI files with updated note durations and CC64 events.
| Action | Shortcut / Interaction |
|---|---|
| Play / Pause | Space |
| Rewind to Start | Home or 0 |
| Toggle Looping | L |
| Undo | Cmd / Ctrl + Z |
| Redo | Cmd / Ctrl + Shift + Z (or Cmd / Ctrl + Y) |
| Select & Sound Note | Click note in piano roll |
| Toggle Note Selection | Shift + Click note |
| Marquee Box Select | Click & drag on empty canvas grid (sounds newly swept notes) |
| Extend Marquee Selection | Shift + Click & drag on canvas grid |
| Deselect All Notes | Click empty space on canvas grid |
| Nudge Note Position | ← / → (±4 ticks; hold Shift for ±40 ticks) |
| Nudge Note Duration | ⌥← / ⌥→ (Option / Alt + Arrows; hold Shift for ±40 ticks) |
| Delete Selected Note(s) | Delete or Backspace |
| Sound Piano Key | Click key on left vertical keyboard ruler |
| Zoom Horizontal | Cmd / Ctrl + Mouse Wheel / Pinch |
| Scroll Timeline | Shift + Mouse Wheel / Two-finger horizontal swipe |
| Add Sustain Node | Double-click empty space in the Sustain lane |
| Delete Sustain Node | Double-click an existing sustain node |
| Move / Toggle Node | Drag sustain node horizontally (time) or vertically (ON/OFF) |
| Scrub Playhead | Click or drag on the timeline ruler |
- Node.js (v18 or higher)
- npm
# Clone the repository
git clone https://github.com/mmontag/miditool.git
cd miditool
# Install dependencies
npm install
# Start the development server
npm run devOpen http://localhost:3088 in your browser.
npm run dev: Starts the Vite development server on port 3088.npm run build: Type-checks and builds the production bundle indist/.npm run preview: Previews the production build locally.npm run test: Runs unit tests for history and storage modules.node deploy.mjs: Builds and deploys the production bundle tohttps://gifx.co/miditool.
- Framework: React 19 + TypeScript
- Build Tool: Vite 6
- Styling: Tailwind CSS v4
- Audio Synthesis:
spessasynth_lib - MIDI Parsing & Export:
@tonejs/midi - Icons: Lucide React
- Graphics: HTML5 2D Canvas
- Architecture: Tagged opcode non-destructive edit stack with local persistence
MIT
