-
-
Notifications
You must be signed in to change notification settings - Fork 41k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flesh out MIDI support #1112
Flesh out MIDI support #1112
Conversation
tone array: text data bss dec hex filename 0 25698 0 25698 6462 satan_newsboytko.hex 0x6480 bytes written into 0x7000 bytes memory (89.73%). note on array: text data bss dec hex filename 0 25802 0 25802 64ca satan_newsboytko.hex 0x6500 bytes written into 0x7000 bytes memory (90.18%).
…iments) satan/keymaps/midi MIDI_ENABLE = no text data bss dec hex filename 0 17080 0 17080 42b8 satan_midi.hex MIDI_ENABLE = yes #define MIDI_TONE_KEYCODE_OCTAVES 3 // default text data bss dec hex filename 0 20846 0 20846 516e satan_midi.hex MIDI_ENABLE = yes #define MIDI_TONE_KEYCODE_OCTAVES 2 // fewer octaves text data bss dec hex filename 0 20846 0 20846 516e satan_midi.hex
This looks pretty awesome! It looks like you've removed the ability to turn MIDI on and off at runtime, which breaks keymaps. That's why the CI check failed. What was your reasoning for that? |
Thank goodness for the CI build. :) Here was my thinking: Technically MIDI was always "on" ... the device was initialized and everything but Anyway, since MIDI notes can be bound to specific keys in the keymap now (as it appears might have been the original intent but was never fully implemented?) MI_ON makes little sense. MI_OFF has been repurposed for "send CC for all midi notes off". Options to resolve:
What are your thoughts on these solutions? |
Nice! I saw your email but hadn't had a chance to respond yet. My thinking with the midi mode as it is currently is the same as the music mode for keyboards with audio enabled - it can be turned on and off (this worked last I checked, but that was a while ago), can play notes (via midi), and doesn't take up extra room in the keymap. The midi notes as keycodes was possible early on (it might still be if the defines were updated), but I didn't find it very useful - the method I have in there currently allows for remapping to different modes/scales/setups more easily than if they were bound directly to keys. I'd be happy to rename |
Ok, I've done a more careful audit. See below for more details of what I found, and my proposal for how to move forward ... Specifically, here's what
Observations:
Proposed Changes: Here's how I think we should move the code forward:
Net result:
What do you guys think? |
return false; | ||
} | ||
// basic | ||
// uint8_t note = (midi_starting_note + SCALE[record->event.key.col + midi_offset])+12*(MATRIX_ROWS - record->event.key.row); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SCALE
is used here - these are the 4 modes I have supported right now. They need to be worked into an option to adjust things at runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, okay. I considered commented code unused :) It wasn't clear to me whether it was experimental or something you intend people to use, since there isn't a way to turn it on in the keymap or anything.
I turn MIDI off by default to save room on the chip (we're currently very close to being maxed out) - I leave the keycodes in there so all people have to do is compile with the I'm fine with the MIDI mode moving to the audio/music mode section, but I would like to be able to use it without having to enable audio. It might make more sense to keep things in the MIDI section, and have a shared key-to-note mapping function somewhere else, so there's not any duplicated code. |
Thanks for elaborating on how you use midi mode. It certainly helps me understand the intent. When you say "I leave the keycodes in there", you mean The fact that any given layout is comfortable on one board but not another is exactly what motivated my changes to have it defined in the keymap rather than some hardcoded default. While a matrix-based layout might make sense for you on your ortholinear board it doesn't work at all for me. I can understand not wanting to bloat the keymap, which is why I didn't define a keycode for every MIDI note (which would also be pretty awkward because it would force you to set up a layer per octave, etc.), but instead defined a smaller number of 'tone' keycodes and octave/transpose shift, just like traditional dedicated MIDI instruments have. As for moving midi mode into The more I think about it, I wonder if what we are dealing with here are two different but equally valid ways to use MIDI which should be behind different Makefile options. I think of "midi mode" as a more "basic" use case for someone who just wants to bootstrap a MIDI device with minimal cost and is okay with a hardcoded layout, while other "advanced" users want to use the keyboard as a full-on MIDI instrument complete with custom layouts. What if we had |
Yeah, the As far as I know, my boards are the only ones to really advertise (and limited at that) the MIDI functionality, so I was planning on people either using it with them, or building something custom, in which case they wouldn't be using my framework at all :) glad to see that change though! What music code are you pulling from that file? Maybe it makes sense to move things into one of three files categories/naming schemes:
The basic/advanced split sounds good, but let's make it a flag set in |
Here's a direct link to the diff of my The category split and |
MIDI_ENABLE = no text data bss dec hex filename 0 17080 0 17080 42b8 satan_midi.hex MIDI_ENABLE = yes MIDI_BASIC undefined MIDI_ADVANCED undefined text data bss dec hex filename 0 19494 0 19494 4c26 satan_midi.hex MIDI_ENABLE = yes #define MIDI_BASIC MIDI_ADVANCED undefined text data bss dec hex filename 0 19788 0 19788 4d4c satan_midi.hex MIDI_ENABLE = yes MIDI_BASIC undefined #define MIDI_ADVANCED text data bss dec hex filename 0 20846 0 20846 516e satan_midi.hex MIDI_ENABLE = yes #define MIDI_BASIC #define MIDI_ADVANCED text data bss dec hex filename 0 21140 0 21140 5294 satan_midi.hex
Update existing keymaps to enable MIDI_BASIC functionality. Also added an option MIDI_ENABLE_STRICT to be strict about keycode use (which also reduces memory footprint at runtime)
Pushed new iteration with all changes as discussed. As an added bonus, music recordings now also play MIDI notes, and recordings use 75% less memory :) |
MIDI_ENABLE = no text data bss dec hex filename 0 17080 0 17080 42b8 satan_midi.hex MIDI_ENABLE = yes MIDI_BASIC undefined MIDI_ADVANCED undefined text data bss dec hex filename 0 19494 0 19494 4c26 satan_midi.hex +2414 bytes (vs. MIDI_ENABLE = no) MIDI_ENABLE = yes 0 20846 0 20846 516e satan_midi.hex +1352 bytes (vs. MIDI_ENABLE = yes, MIDI_BASIC off, MIDI_ADVANCED off) MIDI_ENABLE = yes #define MIDI_BASIC #define MIDI_ADVANCED text data bss dec hex filename 0 21292 0 21292 532c satan_midi.hex +1798 bytes (vs. MIDI_ENABLE = yes, MIDI_BASIC off, MIDI_ADVANCED off) Conclusion: +2400 to 4200, depending on config
@@ -8,36 +17,41 @@ int music_offset = 7; | |||
static bool music_sequence_recording = false; | |||
static bool music_sequence_recorded = false; | |||
static bool music_sequence_playing = false; | |||
static float music_sequence[16] = {0}; | |||
static uint8_t music_sequence[16] = {0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks - I knew that was a bad idea :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the one advantage I could see to using a float here is you could theoretically record things like pitch bends that are between notes in the chromatic scale, but I think once you go down that road the logical conclusion is recording full samples which will use a lot more memory.
Perfect - let me test things out a bit, and we'll get this merged :) |
Yeah, I've done some testing on my end but it would be good to make sure audio is working as expected. I don't have a keyboard that supports audio (C6 pin is used) so I couldn't test it properly, but I did validate that the frequency is correct with |
#ifdef MIDI_BASIC | ||
void process_midi_basic_noteon(uint8_t note); | ||
void process_midi_basic_noteoff(uint8_t note); | ||
void process_midi_basic_stop_all_notes(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably be named process_midi_basic_all_notes_off
to align better with names used in process_music.c
bool process_audio(uint16_t keycode, keyrecord_t *record); | ||
void process_audio_noteon(uint8_t note); | ||
void process_audio_noteoff(uint8_t note); | ||
void process_audio_stop_all_notes(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably be named process_audio_all_notes_off
to align better with names used in process_music.c
@@ -9,7 +9,7 @@ CONSOLE_ENABLE = no # Console for debug(+400) | |||
COMMAND_ENABLE = yes # Commands for debug and configuration | |||
NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | |||
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality | |||
MIDI_ENABLE = no # MIDI controls | |||
MIDI_ENABLE = no # MIDI support (+3800) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be updated to reflect new estimates (2400 to 4200)
Hey @jackhumbert any update on this? |
Not yet - hoping to be able to get this merged next week :) |
Gonna go ahead and merge this :) thanks! |
* Update crimsonkeyboards_resume1800_default.json Updated .json so that scroll lock and num lock shows up properly.
QMK supports MIDI, but the existing implementation is basically just a proof of concept. As part-time musician, the idea of being able to use my keyboard as a MIDI controller is appealing, so I added some features to make MIDI more useful:
I've built a few keymaps on top of this for my personal use which you can see in my fork under
satan/keymaps/newsboytko
. I've used these keymaps in the studio and on stage during live performances :)Configuration
Config options for MIDI allow some flexibility so the user can opt into the functionality they need (and not pay for stuff they don't). The options are described in the template
config.h
:MIDI_BASIC
is on par with previous functionality, but is now better integrated with music/audio. For example, music recordings can now play back audio, MIDI notes, or both.MIDI_ADVANCED
is more geared toward users who want to use their keyboard as a full-blown MIDI instrument, including custom layouts (keymaps) and expression features (sustain, modulation, etc.)You can of course turn on both feature sets and get everything, or neither and write custom actions that use the MIDI protocol directly.
keyboards/satan/keymaps/midi
is an example keymap that uses all features.Compatibility
Existing keymaps that are using
MI_ON
andMI_OFF
have been opted intoMIDI_BASIC
for parity with previous behavior. Though many of them don't appear to be actually using any of MIDI functionality (e.g. they setMIDI_ENABLE = no
in the Makefile). If we wanted to root these out, we could do so by changing the default ofMIDI_ENABLE_STRICT
inquantum_keycodes.h
.