|
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