updated to include more button functions, accelerometer cc
This commit is contained in:
parent
0ba59ff228
commit
d9af575340
1 changed files with 125 additions and 55 deletions
|
|
@ -1,12 +1,26 @@
|
|||
# SPDX-FileCopyrightText: 2023 John Park for Adafruit
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Meowsic Toy Piano MIDI Keyboard
|
||||
# Cyber Cat MIDI Keyboard conversion for Meowsic Cat Piano
|
||||
|
||||
# Functions:
|
||||
# --28 keys
|
||||
# --left five toe buttons: patches
|
||||
# --right five toe buttons: picking CC number for ice cream cone control
|
||||
# --volume arrows: octave up/down
|
||||
# --tempo arrows: pitchbend up/down
|
||||
# --on switch: reset
|
||||
# --nose button: midi panic
|
||||
# --record button: ice cream cone CC enable/disable (led indicator)
|
||||
# --play button: start stop arp or sequence in soft synth via cc 16 0/127
|
||||
# --treble clef button: hold notes (use nose to turn off all notes)
|
||||
# --face button: momentary CC 0/127 on CC number 17
|
||||
|
||||
import keypad
|
||||
import board
|
||||
import busio
|
||||
import supervisor
|
||||
import digitalio
|
||||
from adafruit_simplemath import map_range
|
||||
from adafruit_msa3xx import MSA311
|
||||
import usb_midi
|
||||
|
|
@ -15,11 +29,13 @@ from adafruit_midi.note_on import NoteOn
|
|||
from adafruit_midi.note_off import NoteOff
|
||||
from adafruit_midi.control_change import ControlChange
|
||||
from adafruit_midi.program_change import ProgramChange
|
||||
# from adafruit_midi.start import Start
|
||||
# from adafruit_midi.stop import Stop
|
||||
from adafruit_midi.pitch_bend import PitchBend
|
||||
|
||||
supervisor.runtime.autoreload = False # prevent unwanted restarts due to OS weirdness
|
||||
supervisor.runtime.autoreload = True # set False to prevent unwanted restarts due to OS weirdness
|
||||
|
||||
ledpin = digitalio.DigitalInOut(board.A3)
|
||||
ledpin.direction = digitalio.Direction.OUTPUT
|
||||
ledpin.value = True
|
||||
|
||||
i2c = board.STEMMA_I2C()
|
||||
msa = MSA311(i2c)
|
||||
|
|
@ -33,7 +49,7 @@ midi_uart = busio.UART(board.TX, None, baudrate=31250)
|
|||
|
||||
midi_usb_channel = 1
|
||||
midi_usb = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=midi_usb_channel-1)
|
||||
midi_serial_channel = 4
|
||||
midi_serial_channel = 1
|
||||
midi_serial = adafruit_midi.MIDI(midi_out=midi_uart, out_channel=midi_serial_channel-1)
|
||||
|
||||
octave = 4
|
||||
|
|
@ -59,9 +75,20 @@ def send_pc(bank, folder, patch):
|
|||
midi_usb.send(ProgramChange(patch))
|
||||
midi_serial.send(ProgramChange(patch))
|
||||
|
||||
def send_bend(bend_val):
|
||||
midi_usb.send(PitchBend(bend_val))
|
||||
midi_serial.send(PitchBend(bend_val))
|
||||
def send_bend(bend_start, bend_val, rate, dir):
|
||||
b = bend_start
|
||||
if dir is 0:
|
||||
while b > bend_val + rate:
|
||||
print(b)
|
||||
b = b - rate
|
||||
midi_usb.send(PitchBend(b))
|
||||
midi_serial.send(PitchBend(b))
|
||||
if dir is 1:
|
||||
while b < bend_val - rate:
|
||||
print(b)
|
||||
b = b + rate
|
||||
midi_usb.send(PitchBend(b))
|
||||
midi_serial.send(PitchBend(b))
|
||||
|
||||
def send_midi_panic():
|
||||
for x in range(128):
|
||||
|
|
@ -69,94 +96,137 @@ def send_midi_panic():
|
|||
midi_serial.send(NoteOff(x, 0))
|
||||
|
||||
# key ranges
|
||||
piano_keys = range(0, 28) # note 'range()' excludes last value, so add one
|
||||
toes = ( list(range(28, 33)) + list(range(35, 40)) ) # L/R toe series is interruped by 33, 34
|
||||
piano_keys = range(0, 28) # 'range()' excludes last value, so add one
|
||||
patch_toes = list(range(28, 33))
|
||||
cc_toes = list(range(35, 40))
|
||||
clef_button = 33
|
||||
nose_button = 47
|
||||
face_button = 34
|
||||
record_button = 44
|
||||
play_button = 45
|
||||
vol_down_button = 43
|
||||
vol_up_button = 42
|
||||
tempo_down_button = 41
|
||||
tempo_up_button = 40
|
||||
|
||||
# patch assigments
|
||||
patch_list = (
|
||||
(0,0,0), # piano
|
||||
(1,0,0), # bells
|
||||
(1,0,1), # meow
|
||||
(2,0,0), # organ
|
||||
(3,0,0), # banjo
|
||||
(4,0,1), # rock
|
||||
(5,0,0), # blues
|
||||
(6,0,0), # samba
|
||||
(7,0,1), # tencho
|
||||
(8,0,4) # disco
|
||||
(0, 0, 0), # bank 0, folder 0, patch 0
|
||||
(1, 0, 0),
|
||||
(1, 0, 1),
|
||||
(2, 0, 0),
|
||||
(3, 0, 0),
|
||||
)
|
||||
|
||||
pb_max = 16383 # bend up value
|
||||
pb_default = 8192 # bend center value
|
||||
pb_min = 0 # bend down value
|
||||
pb_change_rate = 100 # interval for pitch bend, lower number is slower
|
||||
pb_return_rate = 100 # interval for pitch bend release
|
||||
|
||||
# accelerometer filtering variables
|
||||
slop = 0.2 # threshold for accelerometer send
|
||||
filter_percent = 0.5 # ranges from 0.0 to 1.0
|
||||
accel_data_y = msa.acceleration[1]
|
||||
last_accel_data_y = msa.acceleration[1]
|
||||
|
||||
cone_mode = False # mod wheel vs pitch bend
|
||||
# midi cc variables
|
||||
cc_enable = True
|
||||
cc_numbers = (1, 43, 44, 14, 15) # mod wheel, filter cutoff, resonance, user, user
|
||||
cc_current = 0
|
||||
cc_play = 16
|
||||
cc_face_number = 17
|
||||
|
||||
started = False # state of arp/seq play
|
||||
note_hold = False
|
||||
|
||||
print("Cyber Cat MIDI Keyboard")
|
||||
|
||||
|
||||
while True:
|
||||
if cc_enable:
|
||||
new_data_y = msa.acceleration[1]
|
||||
accel_data_y = ((new_data_y * filter_percent) + (1-filter_percent) * accel_data_y) # smoothed
|
||||
accel_data_y = ((new_data_y * filter_percent) + (1-filter_percent) * accel_data_y) # smooth
|
||||
if abs(accel_data_y - last_accel_data_y) > slop:
|
||||
if cone_mode is True: # pitch bend mode
|
||||
pitch = int(map_range(accel_data_y, 9, -9, 0, 16383))
|
||||
send_bend(pitch)
|
||||
|
||||
else:
|
||||
modulation = int(map_range(accel_data_y, 9, -9, 0, 127))
|
||||
send_cc(1, modulation)
|
||||
|
||||
send_cc(cc_numbers[cc_current], modulation)
|
||||
last_accel_data_y = accel_data_y
|
||||
|
||||
event = key_matrix.events.get()
|
||||
if event:
|
||||
if event.pressed:
|
||||
key = event.key_number
|
||||
|
||||
# Note keys
|
||||
if key in piano_keys: # its one of the piano keys
|
||||
if key in piano_keys:
|
||||
send_note_on(key, octave)
|
||||
# Patch buttons (cat toes)
|
||||
if key in toes:
|
||||
pc_key = toes.index(key) # remove offset for patch list indexing
|
||||
|
||||
# Volume buttons
|
||||
if key is vol_down_button:
|
||||
octave = min(max((octave - 1), 0), 7)
|
||||
if key is vol_up_button:
|
||||
octave = min(max((octave + 1), 0), 7)
|
||||
|
||||
# Tempo buttons
|
||||
if key is tempo_down_button:
|
||||
send_bend(pb_default, pb_min, pb_change_rate, 0)
|
||||
if key is tempo_up_button:
|
||||
send_bend(pb_default, pb_max, pb_change_rate, 1)
|
||||
|
||||
# Patch buttons (left cat toes)
|
||||
if key in patch_toes:
|
||||
pc_key = patch_toes.index(key) # remove offset for patch list indexing
|
||||
send_pc(patch_list[pc_key][0], patch_list[pc_key][1], patch_list[pc_key][2])
|
||||
# Play key
|
||||
|
||||
# cc buttons (right cat toes)
|
||||
if key in cc_toes:
|
||||
cc_current = cc_toes.index(key) # remove offset for cc list indexing
|
||||
|
||||
# Play key -- use MIDI learn to have arp/seq start or stop with this
|
||||
if key is play_button:
|
||||
if not started:
|
||||
# use midi learning and a CC
|
||||
send_cc(16, 127) # map to seq/arp on/off Synth One
|
||||
# midi_usb.send(Start())
|
||||
send_cc(cc_play, 127) # map to seq/arp on/off Synth One, e.g.
|
||||
started = True
|
||||
else:
|
||||
send_cc(16, 0)
|
||||
# midi_usb.send(Stop())
|
||||
send_cc(cc_play, 0)
|
||||
started = False
|
||||
# Record key
|
||||
|
||||
# Record key -- enable icecream cone
|
||||
if key is record_button:
|
||||
if cone_mode:
|
||||
send_bend(8191) # 'zero' out pitch bend to center position
|
||||
cone_mode = False
|
||||
else:
|
||||
send_cc(1, 64) # 'zero' out the mod wheel to center position
|
||||
cone_mode = True
|
||||
if cc_enable is True:
|
||||
cc_enable = False
|
||||
ledpin.value = False
|
||||
|
||||
elif cc_enable is False:
|
||||
send_cc(cc_numbers[cc_current], 0) # zero it
|
||||
cc_enable = True
|
||||
ledpin.value = True
|
||||
|
||||
# Clef
|
||||
if key is clef_button: # octave down
|
||||
octave = min(max((octave - 1), 0), 7 )
|
||||
if key is clef_button: # hold
|
||||
note_hold = not note_hold
|
||||
|
||||
# Face
|
||||
if key is face_button: # octave up
|
||||
octave = min(max((octave + 1), 0), 7 )
|
||||
# STOP
|
||||
if key is face_button: # momentary cc
|
||||
send_cc(cc_face_number, 127)
|
||||
|
||||
# Nose
|
||||
if key is nose_button:
|
||||
send_midi_panic() # all notes off
|
||||
|
||||
if event.released:
|
||||
key = event.key_number
|
||||
if key in piano_keys:
|
||||
if not note_hold:
|
||||
send_note_off(key, octave)
|
||||
if note_hold:
|
||||
pass
|
||||
|
||||
if key is face_button: # momentary cc release
|
||||
send_cc(cc_face_number, 0)
|
||||
|
||||
if key is tempo_down_button:
|
||||
send_bend(pb_min, pb_default, pb_return_rate, 1)
|
||||
|
||||
if key is tempo_up_button:
|
||||
send_bend(pb_max, pb_default, pb_return_rate, 0)
|
||||
|
|
|
|||
Loading…
Reference in a new issue