Skip to content

Commit ab9a7ee

Browse files
committed
Adding code for MIDI for Makers guide
Adding six examples for the MIDI for Makers guide. Three MIDI out (basic keyboard, BLE sequencer, CC pots) and three MIDI in (UART to USB, display MIDI messages and control motors).
1 parent 8116cfe commit ab9a7ee

File tree

6 files changed

+391
-0
lines changed
  • MIDI_for_Makers

6 files changed

+391
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import time
5+
import adafruit_ble
6+
import touchio
7+
import board
8+
import adafruit_midi
9+
import adafruit_ble_midi
10+
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
11+
from adafruit_midi.note_on import NoteOn
12+
from adafruit_midi.note_off import NoteOff
13+
14+
# CLUE cap touch setup
15+
c_touch = touchio.TouchIn(board.D0)
16+
f_touch = touchio.TouchIn(board.D1)
17+
g_touch = touchio.TouchIn(board.D2)
18+
19+
# array of touch pads
20+
pads = [c_touch, f_touch, g_touch]
21+
22+
# BLE MIDI setup
23+
midi_service = adafruit_ble_midi.MIDIService()
24+
advertisement = ProvideServicesAdvertisement(midi_service)
25+
26+
ble = adafruit_ble.BLERadio()
27+
if ble.connected:
28+
for c in ble.connections:
29+
c.disconnect()
30+
31+
# midi setup
32+
midi = adafruit_midi.MIDI(midi_out=midi_service, out_channel=0)
33+
34+
print("advertising")
35+
ble.start_advertising(advertisement)
36+
37+
# MIDI note numbers for C, F and G major triads
38+
c_triad = (60, 64, 67)
39+
f_triad = (65, 69, 72)
40+
g_triad = (67, 71, 74)
41+
42+
# array of triads
43+
triads = [c_triad, f_triad, g_triad]
44+
45+
# touch debounce states
46+
c_pressed = False
47+
f_pressed = False
48+
g_pressed = False
49+
50+
# array of debounce states
51+
triad_states = [c_pressed, f_pressed, g_pressed]
52+
53+
# beginning triad
54+
active_triad = c_triad
55+
# variable for triad index
56+
z = 0
57+
58+
while True:
59+
# BLE connection
60+
print("Waiting for connection")
61+
while not ble.connected:
62+
pass
63+
print("Connected")
64+
time.sleep(1.0)
65+
66+
# while BLE is connected...
67+
while ble.connected:
68+
# iterate through the touch inputs
69+
for i in range(3):
70+
inputs = pads[i]
71+
# if a touch input is detected...
72+
if inputs.value and triad_states[i] is False:
73+
# debounce state activated
74+
triad_states[i] = True
75+
# update triad
76+
active_triad = triads[i]
77+
print(active_triad)
78+
# after touch input...
79+
if not inputs.value and triad_states[i] is True:
80+
# reset debounce state
81+
triad_states[i] = False
82+
# send triad arpeggios out with half second delay
83+
midi.send(NoteOn(active_triad[z]))
84+
time.sleep(0.5)
85+
midi.send(NoteOff(active_triad[z]))
86+
time.sleep(0.5)
87+
# increase index by 1
88+
z += 1
89+
# reset index at end of triad
90+
if z > 2:
91+
z = 0
92+
93+
# BLE connection
94+
print("Disconnected")
95+
print()
96+
ble.start_advertising(advertisement)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import board
5+
import digitalio
6+
import usb_midi
7+
import adafruit_midi
8+
from adafruit_midi.note_on import NoteOn
9+
from adafruit_midi.note_off import NoteOff
10+
11+
# midi setup
12+
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0)
13+
14+
# midi note numbers
15+
midi_notes = [60, 64, 67, 72]
16+
17+
# digital pins for the buttons
18+
key_pins = [board.D5, board.D6, board.D9, board.D10]
19+
20+
# array for buttons
21+
keys = []
22+
23+
# setup buttons as inputs
24+
for key in key_pins:
25+
key_pin = digitalio.DigitalInOut(key)
26+
key_pin.direction = digitalio.Direction.INPUT
27+
key_pin.pull = digitalio.Pull.UP
28+
keys.append(key_pin)
29+
30+
# states for buttons
31+
key0_pressed = False
32+
key1_pressed = False
33+
key2_pressed = False
34+
key3_pressed = False
35+
36+
# array for button states
37+
key_states = [key0_pressed, key1_pressed, key2_pressed, key3_pressed]
38+
39+
while True:
40+
41+
# iterate through 4 buttons
42+
for i in range(4):
43+
inputs = keys[i]
44+
# if button is pressed...
45+
if not inputs.value and key_states[i] is False:
46+
# update button state
47+
key_states[i] = True
48+
# send NoteOn for corresponding MIDI note
49+
midi.send(NoteOn(midi_notes[i], 120))
50+
51+
# if the button is released...
52+
if inputs.value and key_states[i] is True:
53+
# send NoteOff for corresponding MIDI note
54+
midi.send(NoteOff(midi_notes[i], 120))
55+
key_states[i] = False
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import board
5+
import pwmio
6+
import usb_midi
7+
import adafruit_midi
8+
from adafruit_midi.note_off import NoteOff
9+
from adafruit_midi.note_on import NoteOn
10+
from adafruit_motor import servo
11+
12+
# pwm setup for servo
13+
pwm = pwmio.PWMOut(board.D2, duty_cycle=2 ** 15, frequency=50)
14+
15+
# servo setup
16+
motor = servo.Servo(pwm)
17+
18+
# midi setup
19+
midi = adafruit_midi.MIDI(
20+
midi_in=usb_midi.ports[0], in_channel=0, midi_out=usb_midi.ports[1], out_channel=0
21+
)
22+
23+
while True:
24+
# receive midi input
25+
msg = midi.receive()
26+
27+
if msg is not None:
28+
# if a NoteOn message is received...
29+
if isinstance(msg, NoteOn):
30+
# servo set to 180 degrees
31+
motor.angle = 180
32+
# if a NoteOff message is received...
33+
if isinstance(msg, NoteOff):
34+
# servo set to 0 degrees
35+
motor.angle = 0
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import board
5+
import usb_midi
6+
import adafruit_midi
7+
import simpleio
8+
from analogio import AnalogIn
9+
from adafruit_midi.control_change import ControlChange
10+
from adafruit_midi.pitch_bend import PitchBend
11+
12+
# midi setup
13+
midi = adafruit_midi.MIDI(
14+
midi_in=usb_midi.ports[0], in_channel=0, midi_out=usb_midi.ports[1], out_channel=0
15+
)
16+
17+
# potentiometer setup
18+
mod_pot = AnalogIn(board.A0)
19+
pitchDown_pot = AnalogIn(board.A1)
20+
pitchUp_pot = AnalogIn(board.A2)
21+
sus_pot = AnalogIn(board.A3)
22+
23+
# function to read analog input
24+
def val(pin):
25+
return pin.value
26+
27+
# variables for last read value
28+
# defaults to 0
29+
# no pitchbend is 8192
30+
mod_val2 = 0
31+
pitchDown_val2 = 8192
32+
pitchUp_val2 = 8192
33+
sus_val2 = 0
34+
35+
while True:
36+
37+
# map range of analog input to midi values
38+
# pitchbend range is 0 to 16383 with 8192 centered or no pitchbend
39+
mod_val1 = round(simpleio.map_range(val(mod_pot), 0, 65535, 0, 127))
40+
pitchDown_val1 = round(simpleio.map_range(val(pitchDown_pot), 0, 65535, 0, 8192))
41+
pitchUp_val1 = round(simpleio.map_range(val(pitchUp_pot), 0, 65535, 8192, 16383))
42+
sus_val1 = round(simpleio.map_range(val(sus_pot), 0, 65535, 0, 127))
43+
44+
# if modulation value is updated...
45+
if abs(mod_val1 - mod_val2) > 2:
46+
# update mod_val2
47+
mod_val2 = mod_val1
48+
# create integer
49+
modulation = int(mod_val2)
50+
# create CC message
51+
modWheel = ControlChange(1, modulation)
52+
# send CC message
53+
midi.send(modWheel)
54+
55+
# pitchbend down value is updated...
56+
if abs(pitchDown_val1 - pitchDown_val2) > 75:
57+
# update pitchDown_val2
58+
pitchDown_val2 = pitchDown_val1
59+
# create PitchBend message
60+
pitchDown = PitchBend(int(pitchDown_val2))
61+
# send PitchBend message
62+
midi.send(pitchDown)
63+
64+
# pitchbend up value is updated...
65+
if abs(pitchUp_val1 - pitchUp_val2) > 75:
66+
# updated pitchUp_val2
67+
pitchUp_val2 = pitchUp_val1
68+
# create PitchBend message
69+
pitchUp = PitchBend(int(pitchUp_val2))
70+
# send PitchBend message
71+
midi.send(pitchUp)
72+
73+
# sustain value is updated...
74+
if abs(sus_val1 - sus_val2) > 2:
75+
# update sus_val2
76+
sus_val2 = sus_val1
77+
# create integer
78+
sustain = int(sus_val2)
79+
# create CC message
80+
sustainPedal = ControlChange(64, sustain)
81+
# send CC message
82+
midi.send(sustainPedal)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import board
5+
import busio
6+
import adafruit_midi
7+
import usb_midi
8+
from adafruit_midi.control_change import ControlChange
9+
from adafruit_midi.pitch_bend import PitchBend
10+
from adafruit_midi.note_off import NoteOff
11+
from adafruit_midi.note_on import NoteOn
12+
13+
# uart setup
14+
uart = busio.UART(board.TX, board.RX, baudrate=31250)
15+
# midi channel setup
16+
midi_in_channel = 1
17+
midi_out_channel = 1
18+
# midi setup
19+
# UART is setup as the input
20+
# USB is setup as the output
21+
midi = adafruit_midi.MIDI(
22+
midi_in=uart,
23+
midi_out=usb_midi.ports[1],
24+
in_channel=(midi_in_channel - 1),
25+
out_channel=(midi_out_channel - 1),
26+
debug=False,
27+
)
28+
29+
print("MIDI UART In/USB Out")
30+
print("Default output channel:", midi.out_channel + 1)
31+
32+
# array of message types
33+
messages = (NoteOn, NoteOff, PitchBend, ControlChange)
34+
35+
while True:
36+
# receive MIDI input from UART
37+
msg = midi.receive()
38+
39+
# if the input is a recognized message...
40+
if msg is not None:
41+
for i in range(0, 3):
42+
# iterate through message types
43+
# makes it so that you aren't sending any unnecessary messages
44+
if isinstance(msg, messages[i]):
45+
# send the input out via USB
46+
midi.send(msg)
47+
print(msg)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import board
5+
import busio
6+
import usb_midi
7+
import adafruit_midi
8+
import displayio
9+
import terminalio
10+
from adafruit_display_text import label
11+
import adafruit_displayio_ssd1306
12+
from adafruit_midi.control_change import ControlChange
13+
from adafruit_midi.note_off import NoteOff
14+
from adafruit_midi.note_on import NoteOn
15+
from adafruit_midi.pitch_bend import PitchBend
16+
17+
displayio.release_displays()
18+
19+
oled_reset = board.D1
20+
21+
# I2C setup for display
22+
i2c = busio.I2C(board.SCL1, board.SDA1)
23+
display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset)
24+
25+
# midi setup
26+
print(usb_midi.ports)
27+
midi = adafruit_midi.MIDI(
28+
midi_in=usb_midi.ports[0], in_channel=0, midi_out=usb_midi.ports[1], out_channel=0
29+
)
30+
31+
msg = midi.receive()
32+
33+
# display width and height setup
34+
WIDTH = 128
35+
HEIGHT = 32
36+
BORDER = 5
37+
38+
# display setup
39+
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT)
40+
41+
splash = displayio.Group()
42+
display.show(splash)
43+
44+
# text area setup
45+
text = "MIDI Messages"
46+
text_area = label.Label(
47+
terminalio.FONT, text=text, color=0xFFFFFF, x=28, y=HEIGHT // 2+1)
48+
splash.append(text_area)
49+
50+
while True:
51+
# receive midi messages
52+
msg = midi.receive()
53+
54+
if msg is not None:
55+
# if a NoteOn message...
56+
if isinstance(msg, NoteOn):
57+
string_msg = 'NoteOn'
58+
# get note number
59+
string_val = str(msg.note)
60+
# if a NoteOff message...
61+
if isinstance(msg, NoteOff):
62+
string_msg = 'NoteOff'
63+
# get note number
64+
string_val = str(msg.note)
65+
# if a PitchBend message...
66+
if isinstance(msg, PitchBend):
67+
string_msg = 'PitchBend'
68+
# get value of pitchbend
69+
string_val = str(msg.pitch_bend)
70+
# if a CC message...
71+
if isinstance(msg, ControlChange):
72+
string_msg = 'ControlChange'
73+
# get CC message number
74+
string_val = str(msg.control)
75+
# update text area with message type and value of message as strings
76+
text_area.text = (string_msg + " " + string_val)

0 commit comments

Comments
 (0)