550 lines
10 KiB
Python
550 lines
10 KiB
Python
import board
|
|
import usb_hid
|
|
|
|
import ulab.numpy as np
|
|
from adafruit_hid.consumer_control import ConsumerControl
|
|
from adafruit_hid.consumer_control_code import ConsumerControlCode
|
|
from kb import KMKKeyboard
|
|
|
|
from kmk.extensions.RGB import RGB, AnimationModes
|
|
from kmk.keys import KC
|
|
from kmk.modules.layers import Layers
|
|
from kmk.modules.midi import MidiKeys
|
|
from kmk.modules.potentiometer import PotentiometerHandler
|
|
|
|
keyboard = KMKKeyboard()
|
|
keyboard.modules.append(Layers())
|
|
keyboard.modules.append(MidiKeys())
|
|
|
|
rgb_ext = RGB(
|
|
val_default=10,
|
|
val_limit=100, # out of 255
|
|
pixel_pin=keyboard.rgb_pixel_pin,
|
|
num_pixels=keyboard.rgb_num_pixels,
|
|
refresh_rate=30,
|
|
animation_speed=3,
|
|
animation_mode=AnimationModes.STATIC,
|
|
)
|
|
keyboard.extensions.append(rgb_ext)
|
|
|
|
_______ = KC.TRNS
|
|
XXXXXXX = KC.NO
|
|
|
|
BASE_LAYER_IDX = 0
|
|
FN1_LAYER_IDX = 1
|
|
FN2_LAYER_IDX = 2
|
|
FN3_LAYER_IDX = 3
|
|
MIDI_LAYER_IDX = 4
|
|
|
|
FN1 = KC.MO(FN1_LAYER_IDX)
|
|
FN2 = KC.MO(FN2_LAYER_IDX)
|
|
FN3 = KC.MO(FN3_LAYER_IDX)
|
|
MIDI = KC.TG(MIDI_LAYER_IDX)
|
|
|
|
RGB_TOG = KC.RGB_TOG
|
|
RAINBOW = KC.RGB_MODE_RAINBOW
|
|
|
|
|
|
def get_kb_rgb_obj(keyboard):
|
|
rgb = None
|
|
for ext in keyboard.extensions:
|
|
if type(ext) is RGB:
|
|
rgb = ext
|
|
break
|
|
return rgb
|
|
|
|
|
|
cc = ConsumerControl(usb_hid.devices)
|
|
keyboard.last_level = -1
|
|
|
|
# Gnome in Linux
|
|
level_steps = 17
|
|
level_inc_step = 1
|
|
|
|
# Windows 10
|
|
# level_steps = 100
|
|
# level_inc_step = 1
|
|
|
|
level_lut = [int(x) for x in np.linspace(0, level_steps, 64).tolist()]
|
|
|
|
|
|
def set_sys_vol(state):
|
|
# convert to 0-100
|
|
new_pos = int((state['position'] / 127) * 64)
|
|
level = level_lut[new_pos]
|
|
# print(f"new vol level: {level}")
|
|
# print(f"last: {keyboard.last_level}")
|
|
|
|
# check if uninitialized
|
|
if keyboard.last_level == -1:
|
|
keyboard.last_level = level
|
|
return
|
|
|
|
level_diff = abs(keyboard.last_level - level)
|
|
if level_diff > 0:
|
|
# set volume to new level
|
|
# vol_direction = "unknown"
|
|
if level > keyboard.last_level:
|
|
# vol_direction = "up"
|
|
cmd = ConsumerControlCode.VOLUME_INCREMENT
|
|
else:
|
|
# vol_direction = "down"
|
|
cmd = ConsumerControlCode.VOLUME_DECREMENT
|
|
|
|
# print(f"Setting system volume {vol_direction} by {level_diff} to reach {level}")
|
|
for i in range(int(level_diff / level_inc_step)):
|
|
cc.send(cmd)
|
|
|
|
keyboard.last_level = level
|
|
return
|
|
|
|
|
|
# LEDs Color or animation speed
|
|
hue_lut = [int(x) for x in np.linspace(0, 360, 127).tolist()]
|
|
|
|
|
|
def set_led_var(state):
|
|
rgb = get_kb_rgb_obj(keyboard)
|
|
if rgb is None:
|
|
return
|
|
|
|
if rgb.animation_mode == AnimationModes.STATIC:
|
|
rgb.hue = hue_lut[state['position']]
|
|
else:
|
|
rgb.animation_speed = int((state['position'] / 127) * 5)
|
|
rgb._do_update()
|
|
return
|
|
|
|
|
|
def set_led_brightness(state):
|
|
rgb = get_kb_rgb_obj(keyboard)
|
|
if rgb is None:
|
|
return
|
|
|
|
rgb.val = int((state['position'] / 127) * rgb.val_limit)
|
|
rgb._do_update()
|
|
return
|
|
|
|
|
|
def slider_1_handler(state):
|
|
set_sys_vol(state)
|
|
|
|
|
|
# reserve middle four values - software detent
|
|
pb_lut = []
|
|
pb_lut[00:29] = [int(x) for x in np.linspace(0, 8192, 30).tolist()]
|
|
pb_lut[30:33] = [8192 for x in range(4)] # midpoint - no bend
|
|
pb_lut[34:63] = [int(x) for x in np.linspace(8192, 8192 * 2, 30)]
|
|
|
|
|
|
def slider_2_handler(state):
|
|
if keyboard.active_layers[0] == MIDI_LAYER_IDX:
|
|
# use as MIDI Pitch wheel
|
|
# use 64 values
|
|
bend_idx = int((state['position'] / 127) * 64)
|
|
bend = pb_lut[bend_idx]
|
|
key = KC.MIDI_PB(bend)
|
|
keyboard.tap_key(key)
|
|
else:
|
|
set_led_var(state)
|
|
|
|
|
|
keyboard.__midi_velocity = 0
|
|
|
|
|
|
def slider_3_handler(state):
|
|
if keyboard.active_layers[0] == MIDI_LAYER_IDX:
|
|
# use as MIDI note velocity
|
|
keyboard.__midi_velocity = int((state['position'] / 127) * 127)
|
|
else:
|
|
set_led_brightness(state)
|
|
|
|
|
|
faders = PotentiometerHandler()
|
|
faders.pins = (
|
|
(board.RV1, slider_1_handler, False),
|
|
(board.RV2, slider_2_handler),
|
|
(board.RV3, slider_3_handler),
|
|
)
|
|
keyboard.modules.append(faders)
|
|
|
|
|
|
def set_midi_vel(key, keyboard, *args):
|
|
key.meta.velocity = keyboard.__midi_velocity
|
|
return True
|
|
|
|
|
|
def MN(note: str):
|
|
midi_keypress = KC.MIDI_NOTE(note, 1)
|
|
midi_keypress.before_press_handler(set_midi_vel)
|
|
return midi_keypress
|
|
|
|
|
|
keyboard.keymap = [
|
|
[ # Base Layer
|
|
KC.ESC,
|
|
KC.GRAVE,
|
|
KC.N1,
|
|
KC.N2,
|
|
KC.N3,
|
|
KC.N4,
|
|
KC.N5,
|
|
KC.N6,
|
|
KC.N7,
|
|
KC.N8,
|
|
KC.N9,
|
|
KC.N0,
|
|
KC.BSLS,
|
|
KC.DEL,
|
|
KC.MINS,
|
|
KC.EQUAL,
|
|
KC.TAB,
|
|
KC.Q,
|
|
KC.W,
|
|
KC.E,
|
|
KC.R,
|
|
KC.T,
|
|
KC.Y,
|
|
KC.U,
|
|
KC.I,
|
|
KC.O,
|
|
KC.P,
|
|
KC.BACKSPACE,
|
|
KC.LBRC,
|
|
KC.RBRC,
|
|
KC.LCTRL,
|
|
KC.A,
|
|
KC.S,
|
|
KC.D,
|
|
KC.F,
|
|
KC.G,
|
|
KC.H,
|
|
KC.J,
|
|
KC.K,
|
|
KC.L,
|
|
KC.SCLN,
|
|
KC.QUOT,
|
|
KC.ENTER,
|
|
KC.QUOT,
|
|
KC.HOME,
|
|
KC.LSFT,
|
|
KC.Z,
|
|
KC.X,
|
|
KC.C,
|
|
KC.V,
|
|
KC.B,
|
|
KC.N,
|
|
KC.M,
|
|
KC.COMM,
|
|
KC.DOT,
|
|
KC.SLSH,
|
|
KC.RSFT,
|
|
KC.UP,
|
|
KC.END,
|
|
FN1,
|
|
KC.LGUI,
|
|
KC.LALT,
|
|
KC.SPC,
|
|
KC.ENTER,
|
|
KC.RGUI,
|
|
KC.RALT,
|
|
FN2,
|
|
KC.LEFT,
|
|
KC.DOWN,
|
|
KC.RIGHT,
|
|
],
|
|
[ # FN1 Layer
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
RGB_TOG,
|
|
RAINBOW,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
XXXXXXX,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
FN3,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
],
|
|
[ # FN2 Layer
|
|
_______,
|
|
_______,
|
|
KC.F1,
|
|
KC.F2,
|
|
KC.F3,
|
|
KC.F4,
|
|
KC.F5,
|
|
KC.F6,
|
|
KC.F7,
|
|
KC.F8,
|
|
KC.F9,
|
|
KC.F10,
|
|
KC.F11,
|
|
KC.F12,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
FN3,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
XXXXXXX,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
],
|
|
[ # FN3 Layer
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
MIDI,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
XXXXXXX,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
XXXXXXX,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
],
|
|
[ # MIDI Layer
|
|
MIDI,
|
|
MN('E3'),
|
|
MN('F#3'),
|
|
MN('G#3'),
|
|
MN('A#3'),
|
|
XXXXXXX,
|
|
MN('C#4'),
|
|
MN('D#4'),
|
|
XXXXXXX,
|
|
MN('F#4'),
|
|
MN('G#4'),
|
|
MN('A#4'),
|
|
MN('C5'),
|
|
MN('C#5'),
|
|
_______,
|
|
_______,
|
|
_______,
|
|
MN('F3'),
|
|
MN('G3'),
|
|
MN('A3'),
|
|
MN('B3'),
|
|
MN('C4'),
|
|
MN('D4'),
|
|
MN('E4'),
|
|
MN('F4'),
|
|
MN('G4'),
|
|
MN('A4'),
|
|
MN('B4'),
|
|
_______,
|
|
_______,
|
|
_______,
|
|
XXXXXXX,
|
|
MN('C#2'),
|
|
MN('D#2'),
|
|
XXXXXXX,
|
|
MN('F#2'),
|
|
MN('G#2'),
|
|
MN('A#2'),
|
|
XXXXXXX,
|
|
MN('C#3'),
|
|
MN('D#3'),
|
|
XXXXXXX,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
MN('B1'),
|
|
MN('C2'),
|
|
MN('D2'),
|
|
MN('E2'),
|
|
MN('F2'),
|
|
MN('G2'),
|
|
MN('A2'),
|
|
MN('B2'),
|
|
MN('C3'),
|
|
MN('D3'),
|
|
MN('E3'),
|
|
_______,
|
|
_______,
|
|
XXXXXXX,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
XXXXXXX,
|
|
_______,
|
|
_______,
|
|
_______,
|
|
],
|
|
]
|
|
|
|
# keyboard.debug_enabled = True
|
|
|
|
if __name__ == '__main__':
|
|
keyboard.go()
|