MIDI module and docs

This commit is contained in:
DonutCables 2022-03-02 23:22:58 -05:00 committed by Kyle Brown
parent de1d602b25
commit e52af4f58a
3 changed files with 139 additions and 6 deletions

18
docs/midi.md Normal file
View File

@ -0,0 +1,18 @@
# MIDI
The MIDI module adds keymap entries for sending MIDI data streams. It will require adding the `adafruit_midi` library from the [Adafruit CircuitPython Bundle](https://circuitpython.org/libraries) to your device's folder.
Add it to your keyboard's modules list with:
```python
from kmk.modules.midi import MidiKeys
keyboard.modules.append(MidiKeys())
```
## Keycodes
|Key |Description |
|-----------------|------------------------------------------------------------------------|
|`KC.MIDI_CC()` |Sends a ControlChange message; accepts two integer arguments of `0`-`15`(controller number) then `0`-`127`(control value) |
|`KC.MIDI_NOTE()` |Sends a Note message with both 'On' and 'Off' segments; accepts two integer arguments of `0`-`127`(note number) and `0`-`127`(velocity) |
|`KC.MIDI_PB()` |Sends a Pitch Wheel message; accepts a single integer argument of `0`-`16383`, centered on `8192` |
|`KC.MIDI_PC()` |Sends a Program Change message; accepts a single integer argument of `0`-`127`(program number) |
|`KC.MIDI_START()` |Sends a Start message; accepts no arguments |
|`KC.MIDI_STOP()` |Sends a Stop message; accepts no arguments |

View File

@ -4,20 +4,27 @@ the ability to alter the core code in any way. Unlike extensions, these are not
sandbox, and can make massive changes to normal operation. sandbox, and can make massive changes to normal operation.
## Core Modules ## Core Modules
These modules are proveded in all builds and can be enabled. Currently offered These modules are provided in all builds and can be enabled. Currently offered
modules are modules are
- [Layers](layers.md): Adds layer support (Fn key) to allow many more keys to be - [Layers](layers.md): Adds layer support (Fn key) to allow many more keys to be
put on your keyboard put on your keyboard.
- [ModTap](modtap.md): Adds support for augmented modifier keys to act as one key - [ModTap](modtap.md): Adds support for augmented modifier keys to act as one key
when tapped, and modifier when held. when tapped, and modifier when held.
- [Mouse keys](mouse_keys.md): Adds mouse keycodes - [Mouse keys](mouse_keys.md): Adds mouse keycodes.
- [OneShot](oneshot.md): Adds support for oneshot/sticky keys. - [OneShot](oneshot.md): Adds support for oneshot/sticky keys.
- [Power](power.md): Power saving features. This is mostly useful when on battery power. - [Power](power.md): Power saving features. This is mostly useful when on battery power.
- [Split](split_keyboards.md): Keyboards split in two. Seems ergonomic! - [Split](split_keyboards.md): Keyboards split in two. Seems ergonomic!
- [TapDance](tapdance.md): Different key actions depending on how often it is pressed. - [TapDance](tapdance.md): Different key actions depending on how often it is pressed.
### Require Libraries
These modules can be used without specific hardware, but require additional libraries such as the `Adafruit CircuitPython Bundle`.
- [MIDI](midi.md): Adds sending MIDI data in the form of keymap entries.
### Peripherals ### Peripherals
- [ADNS9800](adns9800.md): Controlling ADNS9800 optical sensor These modules are for specific hardware and may require additional libraries to function.
- [Encoder](encoder.md): Handling rotary encoders - [ADNS9800](adns9800.md): Controlling ADNS9800 optical sensor.
- [Pimoroni trackball](pimoroni_trackball.md): Handling a small I2C trackball made by Pimoroni - [Encoder](encoder.md): Handling rotary encoders.
- [Pimoroni trackball](pimoroni_trackball.md): Handling a small I2C trackball made by Pimoroni.

108
kmk/modules/midi.py Normal file
View File

@ -0,0 +1,108 @@
# Originally put together by xs5871 on the KMK Firmware Discord/Matrix channel
import usb_midi
from kmk.modules import Module
from kmk.keys import make_argumented_key
import adafruit_midi
from adafruit_midi.control_change import ControlChange
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn
from adafruit_midi.pitch_bend import PitchBend
from adafruit_midi.program_change import ProgramChange
from adafruit_midi.start import Start
from adafruit_midi.stop import Stop
class midiNoteValidator:
def __init__(self, note=69, velocity=64, channel=None):
self.note = note
self.velocity = velocity
self.channel = channel
class MidiKeys(Module):
def __init__(self):
make_argumented_key(
names=('MIDI_CC',),
validator=ControlChange,
on_press=self.on_press,
)
make_argumented_key(
names=('MIDI_NOTE',),
validator=midiNoteValidator,
on_press=self.note_on,
on_release=self.note_off,
)
make_argumented_key(
names=('MIDI_PB',),
validator=PitchBend,
on_press=self.on_press,
)
make_argumented_key(
names=('MIDI_PC',),
validator=ProgramChange,
on_press=self.on_press,
)
make_argumented_key(
names=('MIDI_START',),
validator=Start,
on_press=self.on_press,
)
make_argumented_key(
names=('MIDI_STOP',),
validator=Stop,
on_press=self.on_press,
)
try:
self.midi = adafruit_midi.MIDI(
midi_out=usb_midi.ports[1], out_channel=0
)
except IndexError:
self.midi = None
# if debug_enabled:
print('No midi device found.')
def during_bootup(self, keyboard):
return None
def before_matrix_scan(self, keyboard):
return None
def after_matrix_scan(self, keyboard):
return None
def process_key(self, keyboard, key, is_pressed, int_coord):
return key
def before_hid_send(self, keyboard):
return None
def after_hid_send(self, keyboard):
return None
def on_powersave_enable(self, keyboard):
return None
def on_powersave_disable(self, keyboard):
return None
def send(self, message):
if self.midi:
self.midi.send(message)
def on_press(self, key, keyboard, *args, **kwargs):
self.send(key.meta)
def note_on(self, key, keyboard, *args, **kwargs):
self.send(NoteOn(key.meta.note, key.meta.velocity, channel=key.meta.channel))
def note_off(self, key, keyboard, *args, **kwargs):
self.send(NoteOff(key.meta.note, key.meta.velocity, channel=key.meta.channel))