Skip to content

Commit d9af575

Browse files
committed
updated to include more button functions, accelerometer cc
1 parent 0ba59ff commit d9af575

File tree

1 file changed

+125
-55
lines changed

1 file changed

+125
-55
lines changed

Meowsic_MIDI/code.py

Lines changed: 125 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
# SPDX-FileCopyrightText: 2023 John Park for Adafruit
22
#
33
# SPDX-License-Identifier: MIT
4-
# Meowsic Toy Piano MIDI Keyboard
4+
# Cyber Cat MIDI Keyboard conversion for Meowsic Cat Piano
5+
6+
# Functions:
7+
# --28 keys
8+
# --left five toe buttons: patches
9+
# --right five toe buttons: picking CC number for ice cream cone control
10+
# --volume arrows: octave up/down
11+
# --tempo arrows: pitchbend up/down
12+
# --on switch: reset
13+
# --nose button: midi panic
14+
# --record button: ice cream cone CC enable/disable (led indicator)
15+
# --play button: start stop arp or sequence in soft synth via cc 16 0/127
16+
# --treble clef button: hold notes (use nose to turn off all notes)
17+
# --face button: momentary CC 0/127 on CC number 17
518

619
import keypad
720
import board
821
import busio
922
import supervisor
23+
import digitalio
1024
from adafruit_simplemath import map_range
1125
from adafruit_msa3xx import MSA311
1226
import usb_midi
@@ -15,11 +29,13 @@
1529
from adafruit_midi.note_off import NoteOff
1630
from adafruit_midi.control_change import ControlChange
1731
from adafruit_midi.program_change import ProgramChange
18-
# from adafruit_midi.start import Start
19-
# from adafruit_midi.stop import Stop
2032
from adafruit_midi.pitch_bend import PitchBend
2133

22-
supervisor.runtime.autoreload = False # prevent unwanted restarts due to OS weirdness
34+
supervisor.runtime.autoreload = True # set False to prevent unwanted restarts due to OS weirdness
35+
36+
ledpin = digitalio.DigitalInOut(board.A3)
37+
ledpin.direction = digitalio.Direction.OUTPUT
38+
ledpin.value = True
2339

2440
i2c = board.STEMMA_I2C()
2541
msa = MSA311(i2c)
@@ -33,7 +49,7 @@
3349

3450
midi_usb_channel = 1
3551
midi_usb = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=midi_usb_channel-1)
36-
midi_serial_channel = 4
52+
midi_serial_channel = 1
3753
midi_serial = adafruit_midi.MIDI(midi_out=midi_uart, out_channel=midi_serial_channel-1)
3854

3955
octave = 4
@@ -59,104 +75,158 @@ def send_pc(bank, folder, patch):
5975
midi_usb.send(ProgramChange(patch))
6076
midi_serial.send(ProgramChange(patch))
6177

62-
def send_bend(bend_val):
63-
midi_usb.send(PitchBend(bend_val))
64-
midi_serial.send(PitchBend(bend_val))
78+
def send_bend(bend_start, bend_val, rate, dir):
79+
b = bend_start
80+
if dir is 0:
81+
while b > bend_val + rate:
82+
print(b)
83+
b = b - rate
84+
midi_usb.send(PitchBend(b))
85+
midi_serial.send(PitchBend(b))
86+
if dir is 1:
87+
while b < bend_val - rate:
88+
print(b)
89+
b = b + rate
90+
midi_usb.send(PitchBend(b))
91+
midi_serial.send(PitchBend(b))
6592

6693
def send_midi_panic():
6794
for x in range(128):
6895
midi_usb.send(NoteOff(x, 0))
6996
midi_serial.send(NoteOff(x, 0))
7097

7198
# key ranges
72-
piano_keys = range(0, 28) # note 'range()' excludes last value, so add one
73-
toes = ( list(range(28, 33)) + list(range(35, 40)) ) # L/R toe series is interruped by 33, 34
99+
piano_keys = range(0, 28) # 'range()' excludes last value, so add one
100+
patch_toes = list(range(28, 33))
101+
cc_toes = list(range(35, 40))
74102
clef_button = 33
75103
nose_button = 47
76104
face_button = 34
77105
record_button = 44
78106
play_button = 45
107+
vol_down_button = 43
108+
vol_up_button = 42
109+
tempo_down_button = 41
110+
tempo_up_button = 40
79111

80112
# patch assigments
81113
patch_list = (
82-
(0,0,0), # piano
83-
(1,0,0), # bells
84-
(1,0,1), # meow
85-
(2,0,0), # organ
86-
(3,0,0), # banjo
87-
(4,0,1), # rock
88-
(5,0,0), # blues
89-
(6,0,0), # samba
90-
(7,0,1), # tencho
91-
(8,0,4) # disco
114+
(0, 0, 0), # bank 0, folder 0, patch 0
115+
(1, 0, 0),
116+
(1, 0, 1),
117+
(2, 0, 0),
118+
(3, 0, 0),
92119
)
93120

121+
pb_max = 16383 # bend up value
122+
pb_default = 8192 # bend center value
123+
pb_min = 0 # bend down value
124+
pb_change_rate = 100 # interval for pitch bend, lower number is slower
125+
pb_return_rate = 100 # interval for pitch bend release
126+
94127
# accelerometer filtering variables
95128
slop = 0.2 # threshold for accelerometer send
96129
filter_percent = 0.5 # ranges from 0.0 to 1.0
97130
accel_data_y = msa.acceleration[1]
98131
last_accel_data_y = msa.acceleration[1]
99132

100-
cone_mode = False # mod wheel vs pitch bend
133+
# midi cc variables
134+
cc_enable = True
135+
cc_numbers = (1, 43, 44, 14, 15) # mod wheel, filter cutoff, resonance, user, user
136+
cc_current = 0
137+
cc_play = 16
138+
cc_face_number = 17
139+
101140
started = False # state of arp/seq play
141+
note_hold = False
142+
143+
print("Cyber Cat MIDI Keyboard")
102144

103145

104146
while True:
105-
new_data_y = msa.acceleration[1]
106-
accel_data_y = ((new_data_y * filter_percent) + (1-filter_percent) * accel_data_y) # smoothed
107-
if abs(accel_data_y - last_accel_data_y) > slop:
108-
if cone_mode is True: # pitch bend mode
109-
pitch = int(map_range(accel_data_y, 9, -9, 0, 16383))
110-
send_bend(pitch)
111-
112-
else:
147+
if cc_enable:
148+
new_data_y = msa.acceleration[1]
149+
accel_data_y = ((new_data_y * filter_percent) + (1-filter_percent) * accel_data_y) # smooth
150+
if abs(accel_data_y - last_accel_data_y) > slop:
113151
modulation = int(map_range(accel_data_y, 9, -9, 0, 127))
114-
send_cc(1, modulation)
115-
116-
last_accel_data_y = accel_data_y
152+
send_cc(cc_numbers[cc_current], modulation)
153+
last_accel_data_y = accel_data_y
117154

118155
event = key_matrix.events.get()
119156
if event:
120157
if event.pressed:
121158
key = event.key_number
159+
122160
# Note keys
123-
if key in piano_keys: # its one of the piano keys
161+
if key in piano_keys:
124162
send_note_on(key, octave)
125-
# Patch buttons (cat toes)
126-
if key in toes:
127-
pc_key = toes.index(key) # remove offset for patch list indexing
163+
164+
# Volume buttons
165+
if key is vol_down_button:
166+
octave = min(max((octave - 1), 0), 7)
167+
if key is vol_up_button:
168+
octave = min(max((octave + 1), 0), 7)
169+
170+
# Tempo buttons
171+
if key is tempo_down_button:
172+
send_bend(pb_default, pb_min, pb_change_rate, 0)
173+
if key is tempo_up_button:
174+
send_bend(pb_default, pb_max, pb_change_rate, 1)
175+
176+
# Patch buttons (left cat toes)
177+
if key in patch_toes:
178+
pc_key = patch_toes.index(key) # remove offset for patch list indexing
128179
send_pc(patch_list[pc_key][0], patch_list[pc_key][1], patch_list[pc_key][2])
129-
# Play key
180+
181+
# cc buttons (right cat toes)
182+
if key in cc_toes:
183+
cc_current = cc_toes.index(key) # remove offset for cc list indexing
184+
185+
# Play key -- use MIDI learn to have arp/seq start or stop with this
130186
if key is play_button:
131187
if not started:
132-
# use midi learning and a CC
133-
send_cc(16, 127) # map to seq/arp on/off Synth One
134-
# midi_usb.send(Start())
188+
send_cc(cc_play, 127) # map to seq/arp on/off Synth One, e.g.
135189
started = True
136190
else:
137-
send_cc(16, 0)
138-
# midi_usb.send(Stop())
191+
send_cc(cc_play, 0)
139192
started = False
140-
# Record key
193+
194+
# Record key -- enable icecream cone
141195
if key is record_button:
142-
if cone_mode:
143-
send_bend(8191) # 'zero' out pitch bend to center position
144-
cone_mode = False
145-
else:
146-
send_cc(1, 64) # 'zero' out the mod wheel to center position
147-
cone_mode = True
196+
if cc_enable is True:
197+
cc_enable = False
198+
ledpin.value = False
199+
200+
elif cc_enable is False:
201+
send_cc(cc_numbers[cc_current], 0) # zero it
202+
cc_enable = True
203+
ledpin.value = True
148204

149205
# Clef
150-
if key is clef_button: # octave down
151-
octave = min(max((octave - 1), 0), 7 )
206+
if key is clef_button: # hold
207+
note_hold = not note_hold
208+
152209
# Face
153-
if key is face_button: # octave up
154-
octave = min(max((octave + 1), 0), 7 )
155-
# STOP
210+
if key is face_button: # momentary cc
211+
send_cc(cc_face_number, 127)
212+
213+
# Nose
156214
if key is nose_button:
157215
send_midi_panic() # all notes off
158216

159217
if event.released:
160218
key = event.key_number
161219
if key in piano_keys:
162-
send_note_off(key, octave)
220+
if not note_hold:
221+
send_note_off(key, octave)
222+
if note_hold:
223+
pass
224+
225+
if key is face_button: # momentary cc release
226+
send_cc(cc_face_number, 0)
227+
228+
if key is tempo_down_button:
229+
send_bend(pb_min, pb_default, pb_return_rate, 1)
230+
231+
if key is tempo_up_button:
232+
send_bend(pb_max, pb_default, pb_return_rate, 0)

0 commit comments

Comments
 (0)