MIDI module and docs
This commit is contained in:
		
							
								
								
									
										18
									
								
								docs/midi.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								docs/midi.md
									
									
									
									
									
										Normal 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                     |
 | 
			
		||||
@@ -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.
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
 | 
			
		||||
- [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
 | 
			
		||||
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.
 | 
			
		||||
- [Power](power.md): Power saving features. This is mostly useful when on battery power.
 | 
			
		||||
- [Split](split_keyboards.md): Keyboards split in two. Seems ergonomic!
 | 
			
		||||
- [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
 | 
			
		||||
- [ADNS9800](adns9800.md): Controlling ADNS9800 optical sensor
 | 
			
		||||
- [Encoder](encoder.md): Handling rotary encoders
 | 
			
		||||
- [Pimoroni trackball](pimoroni_trackball.md): Handling a small I2C trackball made by Pimoroni
 | 
			
		||||
These modules are for specific hardware and may require additional libraries to function.
 | 
			
		||||
- [ADNS9800](adns9800.md): Controlling ADNS9800 optical sensor.
 | 
			
		||||
- [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
									
								
							
							
						
						
									
										108
									
								
								kmk/modules/midi.py
									
									
									
									
									
										Normal 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))
 | 
			
		||||
		Reference in New Issue
	
	Block a user