jam-buddy / MIDI_TO_GP5.md
salgadev's picture
Sync from GitHub 6feaf31d
b2e4883 verified
|
Raw
History Blame Contribute Delete
2.77 kB
# MIDI β†’ GP5/6 converter β€” design
## Goal
Convert a keyswitched MIDI file (one track at a time) back to a Guitar Pro 5/6 file.
## Direction
Mirror of `gp5_to_keyswitched_mid.py`. Where the forward script uses
`detect_techniques` to read articulations from `note.effect.*`, the reverse
script needs to infer articulations from the keyswitch note that
precedes each pitched note.
## Architecture
```
midi_to_gp5.py
β”œβ”€β”€ parse MIDI β†’ flat list of (track_name, channel, notes, keyswitches)
β”œβ”€β”€ classify tracks (guitar / bass / drums)
β”œβ”€β”€ for each pitched note, look at the preceding keyswitch note and
β”‚ in the same tick β†’ infer the technique
β”œβ”€β”€ build a Song with one Track per MIDI track
└── write via guitarpro.write()
```
## Inference rules (keyswitch β†’ technique)
Same dictionary as the forward script, inverted. Driven by `KEYSWITCH_NOTES`
which maps MIDI note number β†’ technique name:
| Note | Technique | GP5 effect |
|------|-----------|------------|
| 17 / 18 | sustain | (no effect β€” sustain is the default) |
| 20 | palm_mute | `effect.palmMute = True` |
| 9 | harmonic | `effect.harmonic = HarmonicEffect(type=Natural)` |
| 23 | slide_down | `effect.slides = [SlideType.shiftSlideTo]` (with next-note direction) |
| 24 | slide_up | same |
| 26 | hammer | `effect.hammer = True` |
| 27 | slide_in | `effect.grace = GraceEffect(transition=slide)` |
| 91 | bend | `effect.bend = BendEffect(points=[...])` |
Drum notes use standard GM mappings (MIDI 36 = kick, 38 = snare, 42 = hi-hat closed).
## Open questions
1. **Tie detection**: notes whose `note_on` happens before the previous
`note_off` for the same pitch β†’ ties. Inferred from MIDI timing.
2. **Bend reconstruction**: reading pitch wheel events from MIDI is
possible but fragile. Most keyswitch-instrumented MIDIs don't include
pitch bend. Initially: skip bend (write straight notes).
3. **Slide direction (up/down)**: target pitch is the next note on the
same channel. We don't know the target string, so we use the pitch
comparison and let the bar position fill in.
4. **String/fret selection**: pick the lowest playable fret on the
appropriate string. Not unique; heuristic only.
5. **Tuning**: read from existing GP5 file or default to standard EADGBE.
6. **Track routing**: user passes `--track-name "Distortion Guitar"` and
`--instrument guitar|bass|drums` to control the new GP track.
## File layout
```
midi_to_gp5.py # the converter
tests/
test_midi_to_gp5.py # round-trip tests
expected/
*.mid # input fixtures (committed)
*.gp5 # expected outputs (committed)
```
## Status
- [x] Design above
- [ ] MIDI parser
- [ ] Track classifier
- [ ] Articulation inferer
- [ ] Song builder
- [ ] Tests