(Made a couple edits to fix a crash that was happening when the pitch bend went beyond 7. I’m not sure why it was happening but I limited to 7 and it seems stable now. And a few more to fix the color issues. Its getting there. )
Hey guys! Just messing around with what I have, and I got an old Adafruit Macropad to fully control a daisy seed with Daisy-Seed-7-Voice-VA-Synthesizer loaded on it. I have not touched the daisy code, just altered the Macropad midi code. Its not perfect, but heres the circuitPython code for the Macropad and a video demo. Any help on cleaning up the code would be phenomenal. Let me know your thoughts!
# SPDX-FileCopyrightText: 2022 John Park for Adafruit Industries
# SPDX-License-Identifier: MIT
# Macropad MIDI Tester
# Play MIDI notes with keys
# Click encoder to switch modes
# Turn encoder to adjust CC, ProgramChange, or PitchBend
from adafruit_macropad import MacroPad
from adafruit_macropad import ProgramChange
from rainbowio import colorwheel
CC_NUM = 7 # select your CC number
macropad = MacroPad(rotation=180) # create the macropad object, rotate orientation
macropad.display.auto_refresh = False # avoid lag
# --- Pixel setup --- #
key_color = colorwheel(130) # fill with cyan to start
macropad.pixels.brightness = 0.5
macropad.pixels.fill(key_color)
# --- MIDI variables ---
mode = 0
mode_text = ["Paramater", ("CC #%s" % (CC_NUM)), "Pitch Bend"]
midi_values = [0, 16, 8] # bank, cc value, pitch
# Chromatic scale starting with C3 as bottom left keyswitch (or use any notes you like)
midi_notes = [57, 58, 59, 54, 55, 56, 51, 52, 53, 48, 49, 50]
# --- Display text setup ---
text_lines = macropad.display_text("Caidens Synth Beta")
text_lines[0].text = "Paramater: {}".format(
midi_values[0] + 1
) # Patch display offset by 1
if midi_values[0] + 1 == 1:
text_lines[1].text = "Master Tuning"
elif midi_values[0] + 1 == 2:
text_lines[1].text = "Osc #1 Waveform"
elif midi_values[0] + 1 == 3:
text_lines[1].text = "Osc #2 Waveform"
elif midi_values[0] + 1 == 4:
text_lines[1].text = "Oscillator Mix"
elif midi_values[0] + 1 == 5:
text_lines[1].text = "Oscillator #2 De-Tune"
elif midi_values[0] + 1 == 6:
text_lines[1].text = "Oscillator #2 Scale"
elif midi_values[0] + 1 == 7:
text_lines[1].text = "Resonance"
elif midi_values[0] + 1 == 8:
text_lines[1].text = "Osc #1 Pulse Width"
elif midi_values[0] + 1 == 9:
text_lines[1].text = "Osc #2 Pulse Width"
elif midi_values[0] + 1 == 10:
text_lines[1].text = "VCF Attack"
elif midi_values[0] + 1 == 11:
text_lines[1].text = "VCF Decay"
elif midi_values[0] + 1 == 12:
text_lines[1].text = "VCF Sustain"
elif midi_values[0] + 1 == 13:
text_lines[1].text = "VCF Release"
elif midi_values[0] + 1 == 14:
text_lines[1].text = "VCA Attack"
elif midi_values[0] + 1 == 15:
text_lines[1].text = "VCA Decay"
elif midi_values[0] + 1 == 16:
text_lines[1].text = "VCA Sustain"
elif midi_values[0] + 1 == 17:
text_lines[1].text = "VCA Release"
elif midi_values[0] + 1 == 18:
text_lines[1].text = "VCF Key Follow"
elif midi_values[0] + 1 == 19:
text_lines[1].text = "ENV Key Follow"
elif midi_values[0] + 1 == 20:
text_lines[1].text = "Velocity Routing"
elif midi_values[0] + 1 == 21:
text_lines[1].text = "VCF Envelope level"
elif midi_values[0] + 1 == 22:
text_lines[1].text = "Mod Wheel LFO Rate"
elif midi_values[0] + 1 == 23:
text_lines[1].text = "PWM LFO Rate"
elif midi_values[0] + 1 == 24:
text_lines[1].text = "PWM LFO Mod"
elif midi_values[0] + 1 == 25:
text_lines[1].text = "PWM2 LFO Rate"
elif midi_values[0] + 1 == 26:
text_lines[1].text = "PWM2 LFO Mod"
elif midi_values[0] + 1 == 27:
text_lines[1].text = "VCA/VCF LFO rate"
elif midi_values[0] + 1 == 28:
text_lines[1].text = "VCA/VCF LFO Mod"
elif midi_values[0] + 1 == 29:
text_lines[1].text = "VCA/VCF LFO Waveform"
text_lines.show()
last_knob_pos = macropad.encoder # store knob position state
while True:
while macropad.keys.events: # check for key press or release
key_event = macropad.keys.events.get()
if key_event:
if key_event.pressed:
key = key_event.key_number
macropad.midi.send(
macropad.NoteOn(midi_notes[key], 120)
) # send midi noteon
macropad.pixels[key] = colorwheel(188) # light up green
if midi_values[0] + 1 == 1:
text_lines[1].text = "Master Tuning"
elif midi_values[0] + 1 == 2:
text_lines[1].text = "Osc #1 Waveform"
elif midi_values[0] + 1 == 3:
text_lines[1].text = "Osc #2 Waveform"
elif midi_values[0] + 1 == 4:
text_lines[1].text = "Oscillator Mix"
elif midi_values[0] + 1 == 5:
text_lines[1].text = "Oscillator #2 De-Tune"
elif midi_values[0] + 1 == 6:
text_lines[1].text = "Oscillator #2 Scale"
elif midi_values[0] + 1 == 7:
text_lines[1].text = "Resonance"
elif midi_values[0] + 1 == 8:
text_lines[1].text = "Osc #1 Pulse Width"
elif midi_values[0] + 1 == 9:
text_lines[1].text = "Osc #2 Pulse Width"
elif midi_values[0] + 1 == 10:
text_lines[1].text = "VCF Attack"
elif midi_values[0] + 1 == 11:
text_lines[1].text = "VCF Decay"
elif midi_values[0] + 1 == 12:
text_lines[1].text = "VCF Sustain"
elif midi_values[0] + 1 == 13:
text_lines[1].text = "VCF Release"
elif midi_values[0] + 1 == 14:
text_lines[1].text = "VCA Attack"
elif midi_values[0] + 1 == 15:
text_lines[1].text = "VCA Decay"
elif midi_values[0] + 1 == 16:
text_lines[1].text = "VCA Sustain"
elif midi_values[0] + 1 == 17:
text_lines[1].text = "VCA Release"
elif midi_values[0] + 1 == 18:
text_lines[1].text = "VCF Key Follow"
elif midi_values[0] + 1 == 19:
text_lines[1].text = "ENV Key Follow"
elif midi_values[0] + 1 == 20:
text_lines[1].text = "Velocity Routing"
elif midi_values[0] + 1 == 21:
text_lines[1].text = "VCF Envelope level"
elif midi_values[0] + 1 == 22:
text_lines[1].text = "Mod Wheel LFO Rate"
elif midi_values[0] + 1 == 23:
text_lines[1].text = "PWM LFO Rate"
elif midi_values[0] + 1 == 24:
text_lines[1].text = "PWM LFO Mod"
elif midi_values[0] + 1 == 25:
text_lines[1].text = "PWM2 LFO Rate"
elif midi_values[0] + 1 == 26:
text_lines[1].text = "PWM2 LFO Mod"
elif midi_values[0] + 1 == 27:
text_lines[1].text = "VCA/VCF LFO rate"
elif midi_values[0] + 1 == 28:
text_lines[1].text = "VCA/VCF LFO Mod"
elif midi_values[0] + 1 == 29:
text_lines[1].text = "VCA/VCF LFO Waveform"
if key_event.released:
key = key_event.key_number
macropad.midi.send(macropad.NoteOff(midi_notes[key], 0))
macropad.pixels[
key
] = key_color # return to color set by encoder bank value
if midi_values[0] + 1 == 1:
text_lines[1].text = "Master Tuning"
elif midi_values[0] + 1 == 2:
text_lines[1].text = "Osc #1 Waveform"
elif midi_values[0] + 1 == 3:
text_lines[1].text = "Osc #2 Waveform"
elif midi_values[0] + 1 == 4:
text_lines[1].text = "Oscillator Mix"
elif midi_values[0] + 1 == 5:
text_lines[1].text = "Oscillator #2 De-Tune"
elif midi_values[0] + 1 == 6:
text_lines[1].text = "Oscillator #2 Scale"
elif midi_values[0] + 1 == 7:
text_lines[1].text = "Resonance"
elif midi_values[0] + 1 == 8:
text_lines[1].text = "Osc #1 Pulse Width"
elif midi_values[0] + 1 == 9:
text_lines[1].text = "Osc #2 Pulse Width"
elif midi_values[0] + 1 == 10:
text_lines[1].text = "VCF Attack"
elif midi_values[0] + 1 == 11:
text_lines[1].text = "VCF Decay"
elif midi_values[0] + 1 == 12:
text_lines[1].text = "VCF Sustain"
elif midi_values[0] + 1 == 13:
text_lines[1].text = "VCF Release"
elif midi_values[0] + 1 == 14:
text_lines[1].text = "VCA Attack"
elif midi_values[0] + 1 == 15:
text_lines[1].text = "VCA Decay"
elif midi_values[0] + 1 == 16:
text_lines[1].text = "VCA Sustain"
elif midi_values[0] + 1 == 17:
text_lines[1].text = "VCA Release"
elif midi_values[0] + 1 == 18:
text_lines[1].text = "VCF Key Follow"
elif midi_values[0] + 1 == 19:
text_lines[1].text = "ENV Key Follow"
elif midi_values[0] + 1 == 20:
text_lines[1].text = "Velocity Routing"
elif midi_values[0] + 1 == 21:
text_lines[1].text = "VCF Envelope level"
elif midi_values[0] + 1 == 22:
text_lines[1].text = "Mod Wheel LFO Rate"
elif midi_values[0] + 1 == 23:
text_lines[1].text = "PWM LFO Rate"
elif midi_values[0] + 1 == 24:
text_lines[1].text = "PWM LFO Mod"
elif midi_values[0] + 1 == 25:
text_lines[1].text = "PWM2 LFO Rate"
elif midi_values[0] + 1 == 26:
text_lines[1].text = "PWM2 LFO Mod"
elif midi_values[0] + 1 == 27:
text_lines[1].text = "VCA/VCF LFO rate"
elif midi_values[0] + 1 == 28:
text_lines[1].text = "VCA/VCF LFO Mod"
elif midi_values[0] + 1 == 29:
text_lines[1].text = "VCA/VCF LFO Waveform"
macropad.encoder_switch_debounced.update() # check the knob switch for press or release
if macropad.encoder_switch_debounced.pressed:
mode = (mode + 1) % 3
if mode == 0:
text_lines[0].text = "Mode: %s %d" % (
mode_text[mode],
midi_values[mode] + 1,
)
elif mode == 1:
text_lines[0].text = "Mode: %s %d" % (
mode_text[mode],
int(midi_values[mode] * 4.1),
)
else:
text_lines[0].text = "Mode: %s %d" % (
mode_text[mode],
midi_values[mode] - 8,
)
macropad.red_led = macropad.encoder_switch
text_lines[1].text = " " # clear the note line
if macropad.encoder_switch_debounced.released:
if midi_values[0] + 1 == 1:
text_lines[1].text = "Master Tuning"
elif midi_values[0] + 1 == 2:
text_lines[1].text = "Osc #1 Waveform"
elif midi_values[0] + 1 == 3:
text_lines[1].text = "Osc #2 Waveform"
elif midi_values[0] + 1 == 4:
text_lines[1].text = "Oscillator Mix"
elif midi_values[0] + 1 == 5:
text_lines[1].text = "Oscillator #2 De-Tune"
elif midi_values[0] + 1 == 6:
text_lines[1].text = "Oscillator #2 Scale"
elif midi_values[0] + 1 == 7:
text_lines[1].text = "Resonance"
elif midi_values[0] + 1 == 8:
text_lines[1].text = "Osc #1 Pulse Width"
elif midi_values[0] + 1 == 9:
text_lines[1].text = "Osc #2 Pulse Width"
elif midi_values[0] + 1 == 10:
text_lines[1].text = "VCF Attack"
elif midi_values[0] + 1 == 11:
text_lines[1].text = "VCF Decay"
elif midi_values[0] + 1 == 12:
text_lines[1].text = "VCF Sustain"
elif midi_values[0] + 1 == 13:
text_lines[1].text = "VCF Release"
elif midi_values[0] + 1 == 14:
text_lines[1].text = "VCA Attack"
elif midi_values[0] + 1 == 15:
text_lines[1].text = "VCA Decay"
elif midi_values[0] + 1 == 16:
text_lines[1].text = "VCA Sustain"
elif midi_values[0] + 1 == 17:
text_lines[1].text = "VCA Release"
elif midi_values[0] + 1 == 18:
text_lines[1].text = "VCF Key Follow"
elif midi_values[0] + 1 == 19:
text_lines[1].text = "ENV Key Follow"
elif midi_values[0] + 1 == 20:
text_lines[1].text = "Velocity Routing"
elif midi_values[0] + 1 == 21:
text_lines[1].text = "VCF Envelope level"
elif midi_values[0] + 1 == 22:
text_lines[1].text = "Mod Wheel LFO Rate"
elif midi_values[0] + 1 == 23:
text_lines[1].text = "PWM LFO Rate"
elif midi_values[0] + 1 == 24:
text_lines[1].text = "PWM LFO Mod"
elif midi_values[0] + 1 == 25:
text_lines[1].text = "PWM2 LFO Rate"
elif midi_values[0] + 1 == 26:
text_lines[1].text = "PWM2 LFO Mod"
elif midi_values[0] + 1 == 27:
text_lines[1].text = "VCA/VCF LFO rate"
elif midi_values[0] + 1 == 28:
text_lines[1].text = "VCA/VCF LFO Mod"
elif midi_values[0] + 1 == 29:
text_lines[1].text = "VCA/VCF LFO Waveform"
macropad.red_led = macropad.encoder_switch
if last_knob_pos is not macropad.encoder: # knob has been turned
knob_pos = macropad.encoder # read encoder
knob_delta = knob_pos - last_knob_pos # compute knob_delta since last read
last_knob_pos = knob_pos # save new reading
if mode == 0: # ProgramChange
midi_values[mode] = min(
max(midi_values[mode] + knob_delta, 0), 28
) # delta + minmax
macropad.midi.send(
macropad.ProgramChange(midi_values[mode])
) # midi send ProgramChange
macropad.midi.send(macropad.ControlChange(0, int(midi_values[mode]) + 98))
key_color = colorwheel(
int(midi_values[mode]) + 130
) # change key_color as patches change
macropad.pixels.fill(key_color)
text_lines[0].text = "Mode: %s %d" % (
mode_text[mode],
midi_values[mode] + 1,
)
if mode == 1: # CC
midi_values[mode] = min(
max(midi_values[mode] + knob_delta, 0), 31
) # scale the value
macropad.midi.send(
macropad.ControlChange(CC_NUM, int(midi_values[mode] * 4.1))
)
text_lines[0].text = "Mode: %s %d" % (
mode_text[mode],
int(midi_values[mode] * 4.1),
)
if mode == 2: # PitchBend
midi_values[mode] = min(
max(midi_values[mode] + knob_delta, 0), 15
) # smaller range
macropad.midi.send(
macropad.PitchBend((midi_values[mode] * 1024))
) # range * mult = 16384
text_lines[0].text = "Mode: %s %d" % (
mode_text[mode],
midi_values[mode] - 8,
)
last_knob_pos = macropad.encoder
macropad.display.refresh()
PS: This is my first time attempting CircuitPython, thats why that big if/else list of parameters is all over the place. I need some help making that into a class so I can just call it when I need it and slim down the controller code. Or perhaps someone has a better idea. I’m extremely open to suggestions.
Finally I’d LOVE to get my Mac out of the mix and just use the daisy as a USB host like I can on a teensy. Any ideas about that would be amazing. The Macropad has Stemma QT out but I’m not sure what to do with that. Thanks again!
The Macropad code above actually works perfectly with:
Daisy-Seed-7-Voice-VA-Synthesizer
Daisy-Seed-Synthesizer-with-KarlsenLPF
And works with this as well you just have to change the names of the parameters but it’s all the same concept.
STM32-Daisy-Seed-NucleoSynth Public