Skip to content

Commit 84a3aaf

Browse files
authored
Merge pull request #2033 from adafruit/midi_for_makers
Adding code for MIDI for Makers guide
2 parents 7dfa499 + ab9a7ee commit 84a3aaf

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)