|
4 | 4 | # In Ableton, choose "Launchpad Mini Mk3" as controller with MacroPad 2040 as in and out |
5 | 5 | # Use empty fifth scene to allow "unlaunching" of tracks with encoder modifier |
6 | 6 | import board |
7 | | -from digitalio import DigitalInOut, Pull |
8 | | -import keypad |
| 7 | +from adafruit_macropad import MacroPad |
9 | 8 | import displayio |
10 | 9 | import terminalio |
11 | | -import neopixel |
12 | | -import rotaryio |
13 | 10 | from adafruit_simplemath import constrain |
14 | 11 | from adafruit_display_text import label |
15 | | -from adafruit_debouncer import Debouncer |
16 | 12 | import usb_midi |
17 | 13 | import adafruit_midi |
18 | 14 | from adafruit_midi.control_change import ControlChange |
19 | 15 | from adafruit_midi.note_off import NoteOff |
20 | 16 | from adafruit_midi.note_on import NoteOn |
21 | 17 | from adafruit_midi.midi_message import MIDIUnknownEvent |
22 | 18 |
|
| 19 | +macropad = MacroPad() |
| 20 | + |
23 | 21 | TITLE_TEXT = "Live Launcher 2040" |
24 | 22 | print(TITLE_TEXT) |
25 | 23 | TRACK_NAMES = ["DRUM", "BASS", "SYNTH"] # Customize these |
26 | 24 | LIVE_CC_NUMBER = 74 # CC number to send w encoder |
27 | 25 | FADER_TEXT = "cutoff" # change for intended CC name |
28 | 26 |
|
29 | | - |
| 27 | +# --- MIDI recieve is complex, so not using macropad.midi |
30 | 28 | midi = adafruit_midi.MIDI( |
31 | 29 | midi_in=usb_midi.ports[0], |
32 | 30 | in_channel=(0, 1, 2), |
33 | 31 | midi_out=usb_midi.ports[1], |
34 | 32 | out_channel=0 |
35 | 33 | ) |
36 | 34 |
|
37 | | -# ---Specify key pins--- |
38 | | -key_pins = ( |
39 | | - board.KEY1, board.KEY2, board.KEY3, |
40 | | - board.KEY4, board.KEY5, board.KEY6, |
41 | | - board.KEY7, board.KEY8, board.KEY9, |
42 | | - board.KEY10, board.KEY11, board.KEY12 |
43 | | -) |
44 | | -# ---Create keypad object--- |
45 | | -keys = keypad.Keys(key_pins, value_when_pressed=False, pull=True) |
46 | 35 |
|
47 | 36 | # ---Official Launchpad colors--- |
48 | 37 | LP_COLORS = ( |
|
76 | 65 | modifier = False # use to add encoder switch modifier to keys for clip mute |
77 | 66 | MODIFIER_NOTES = [41, 42, 43, 41, 42, 43, 41, 42, 43, 41, 42, 43] # blank row in Live |
78 | 67 |
|
79 | | -# ---Encoder setup--- |
80 | | -encoder = rotaryio.IncrementalEncoder(board.ENCODER_B, board.ENCODER_A) |
81 | | -sw = DigitalInOut(board.ENCODER_SWITCH) |
82 | | -sw.switch_to_input(pull=Pull.UP) |
83 | | -switch = Debouncer(sw) |
84 | 68 | last_position = 0 # encoder position state |
85 | 69 |
|
86 | 70 | # ---NeoPixel setup--- |
87 | 71 | BRIGHT = 0.125 |
88 | 72 | DIM = 0.0625 |
89 | | -pixels = neopixel.NeoPixel(board.NEOPIXEL, 12, brightness=BRIGHT, auto_write=False) |
| 73 | +macropad.pixels.brightness = BRIGHT |
90 | 74 |
|
91 | 75 | # ---Display setup--- |
92 | 76 | display = board.DISPLAY |
|
97 | 81 | FONT = terminalio.FONT |
98 | 82 | # Draw a title label |
99 | 83 | title = TITLE_TEXT |
100 | | -title_area = label.Label(FONT, text=title, color=0xFFFFFF,x=6, y=3) |
| 84 | +title_area = label.Label(FONT, text=title, color=0xFFFFFF, x=6, y=3) |
101 | 85 | screen.append(title_area) |
102 | 86 |
|
103 | 87 | # --- create display strings and positions |
|
139 | 123 | group = displayio.Group(max_size=4, x=x, y=y) |
140 | 124 | group.append(label_area) |
141 | 125 | screen.append(group) |
142 | | - labels.append(label_area) # these can be individually addressed later |
| 126 | + labels.append(label_area) # these are individually addressed later |
143 | 127 |
|
144 | 128 | num = 1 |
145 | 129 |
|
|
158 | 142 | ) |
159 | 143 | # send neopixel lightup code to key, text to display |
160 | 144 | if msg_in.note in LP_PADS: |
161 | | - pixels[LP_PADS[msg_in.note]] = LP_COLORS[msg_in.velocity] |
162 | | - pixels.show() |
| 145 | + macropad.pixels[LP_PADS[msg_in.note]] = LP_COLORS[msg_in.velocity] |
| 146 | + macropad.pixels.show() |
163 | 147 | if msg_in.velocity == 21: # active pad is indicated by Live as vel 21 |
164 | 148 | labels[LP_PADS[msg_in.note]+3].text = "o" |
165 | 149 | else: |
166 | 150 | labels[LP_PADS[msg_in.note]+3].text = "." |
167 | 151 |
|
168 | | - elif ( |
169 | | - isinstance(msg_in, NoteOff) |
170 | | - or isinstance(msg_in, NoteOn) |
171 | | - and msg_in.velocity == 0 |
172 | | - ): |
| 152 | + elif isinstance(msg_in, NoteOff): |
| 153 | + print( |
| 154 | + "received NoteOff", |
| 155 | + "from channel", |
| 156 | + msg_in.channel + 1, |
| 157 | + "\n" |
| 158 | + ) |
| 159 | + |
| 160 | + elif isinstance(msg_in, NoteOn) and msg_in.velocity == 0: |
173 | 161 | print( |
174 | 162 | "received NoteOff", |
175 | 163 | "from channel", |
|
200 | 188 | elif msg_in is not None: |
201 | 189 | midi.send(msg_in) |
202 | 190 |
|
203 | | - event = keys.events.get() # check for keypad events |
| 191 | + key_event = macropad.keys.events.get() # check for keypad events |
204 | 192 |
|
205 | | - if not event: # Event is None; no keypad event happened, do other stuff |
| 193 | + if not key_event: # Event is None; no keypad event happened, do other stuff |
206 | 194 |
|
207 | | - position = encoder.position # store encoder position state |
| 195 | + position = macropad.encoder # store encoder position state |
208 | 196 | cc_position = constrain((position + CC_OFFSET), 0, 127) # lock to cc range |
209 | 197 | if last_position is None or position != last_position: |
210 | 198 |
|
|
219 | 207 | cc_val_text_area.text = str(cc_position) |
220 | 208 | last_position = position |
221 | 209 |
|
222 | | - switch.update() # check the encoder switch w debouncer |
223 | | - if switch.fell: |
| 210 | + macropad.encoder_switch_debounced.update() # check the encoder switch w debouncer |
| 211 | + if macropad.encoder_switch_debounced.pressed: |
224 | 212 | print("Mod") |
225 | 213 | push_text_area.text = "[.]" |
226 | 214 | modifier = True |
227 | | - pixels.brightness = DIM |
228 | | - pixels.show() |
| 215 | + macropad.pixels.brightness = DIM |
229 | 216 |
|
230 | | - if switch.rose: |
| 217 | + if macropad.encoder_switch_debounced.released: |
231 | 218 | modifier = False |
232 | 219 | push_text_area.text = "[o]" |
233 | | - pixels.brightness = BRIGHT |
234 | | - pixels.show() |
| 220 | + macropad.pixels.brightness = BRIGHT |
235 | 221 |
|
236 | 222 | continue |
237 | 223 |
|
238 | | - num = event.key_number |
| 224 | + num = key_event.key_number |
239 | 225 |
|
240 | | - if event.pressed and not modifier: |
| 226 | + if key_event.pressed and not modifier: |
241 | 227 | midi.send(NoteOn(LIVE_NOTES[num], 127)) |
242 | 228 | print("\nsent note", LIVE_NOTES[num], "\n") |
243 | 229 |
|
244 | | - if event.pressed and modifier: |
| 230 | + if key_event.pressed and modifier: |
245 | 231 | midi.send(NoteOn(MODIFIER_NOTES[num], 127)) |
246 | 232 |
|
247 | | - if event.released and not modifier: |
| 233 | + if key_event.released and not modifier: |
248 | 234 | midi.send(NoteOff(LIVE_NOTES[num], 0)) |
249 | 235 |
|
250 | | - if event.released and modifier: |
| 236 | + if key_event.released and modifier: |
251 | 237 | midi.send(NoteOff(MODIFIER_NOTES[num], 0)) |
252 | 238 |
|
253 | | - pixels.show() |
| 239 | + macropad.pixels.show() |
0 commit comments