A tin whistle game for practicing tunes from MIDI files.
I quickly put this together as a fun side project to help me practice. There is much room for improvement, but should work fine enought if you just want to practice some songs on a high D whistle. Feel free to contribute or open issues for bugs and feature requests!
Dependencies are handled via uv. To start whistle, run:
uv run whistle.py Made with MIDI files from thesession.org in mind.
If you want to use another sound for playback, there is a script ./res/generate_samples.py that generates WAV samples from a SoundFont file. The current SoundFont used is from WARBL.
| Key | Action |
|---|---|
| SPACE | Play / Pause |
| S | Stop |
| L | Load MIDI file |
| Q / ESC | Quit |
| Down | Decrease tempo (-5 BPM) |
| Up | Increase tempo (+5 BPM) |
| Left | Rewind |
| Right | Fast-forward |
| j | Playback volume down |
| k | Playback volume up |
Features I want to implement but probably never will:
- Metronome and count-in options (easy).
- Support whistles in different keys (easy).
- Custom fingering charts (easy).
- Audio input or support for wind MIDI controllers such as WARBL.
Only supports the high D whistle for now as this is hard-coded in midi.py, but it is not difficult to generalize.
For now, supported MIDI files must be of the following format:
MetaMessage('text', text='note track', time=0)
MetaMessage('set_tempo', tempo=500000, time=0)
MetaMessage('key_signature', key='D', time=0)
MetaMessage('time_signature', numerator=4, denominator=4, clocks_per_click=48, notated_32nd_notes_per_beat=8, time=0)
MetaMessage('track_name', name='Wise Maid, The', time=0)
note_on channel=0 note=62 velocity=120 time=1
note_off channel=0 note=62 velocity=0 time=239
note_on channel=0 note=64 velocity=60 time=1
...
note_off channel=0 note=66 velocity=0 time=195
note_on channel=0 note=62 velocity=120 time=45
note_off channel=0 note=62 velocity=0 time=435
MetaMessage('end_of_track', time=70)
In other words:
- Single track MIDI files only.
- Notes must be in the range of D4 (MIDI 62) to D6 (MIDI 86).
- No chords (only one note at a time).
- Every note on event must have a corresponding note off event before the next note on event.
- Tempo and time signature changes are not supported.
