Skip to content

Commit b40e63c

Browse files
committed
add simple arpeggiator example
1 parent 4732122 commit b40e63c

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2024 Tod Kurt
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
# This example shows both receiving and sending MIDI messages
6+
# by implementing a simple arpeggiator.
7+
# MIDI notes send to MIDI In are arpeggiated to MIDI Output.
8+
9+
import time
10+
import usb_midi
11+
import tmidi
12+
13+
midi = tmidi.MIDI(midi_in=usb_midi.ports[0], midi_out=usb_midi.ports[1])
14+
# if serial midi
15+
# uart = busio.UART(rx=board.RX, tx=board.TX, timeout=0.000)
16+
# midi = tmidi.MIDI(midi_in=uart, midi_out=uart)
17+
18+
tempo = 120 # bpm
19+
notes_per_beat = 2 # 1 = quarter-note, 2 = 8th, 4 = 16th
20+
note_time = 60 / tempo / notes_per_beat
21+
gate_percent = 0.5
22+
23+
pressed_notes = []
24+
note_i = 0
25+
last_note_time = 0
26+
gate_time = 0
27+
while True:
28+
# handle midi input
29+
if msg := midi.receive():
30+
if msg.type == tmidi.NOTE_ON and msg.velocity > 0:
31+
print("note on", msg)
32+
pressed_notes.append(msg.note)
33+
elif msg.type == tmidi.NOTE_OFF or (
34+
msg.type == tmidi.NOTE_ON and msg.velocity == 0
35+
):
36+
if msg.note in pressed_notes:
37+
midi.send(msg) # send the note off
38+
pressed_notes.remove(msg.note)
39+
note_i = 0
40+
41+
# do midi output
42+
if len(pressed_notes) == 0:
43+
continue
44+
45+
now = time.monotonic()
46+
if now - last_note_time >= note_time:
47+
last_note_time = now
48+
note_on = tmidi.Message(tmidi.NOTE_ON, pressed_notes[note_i], 127)
49+
print("arp note_on: ", note_on)
50+
midi.send(note_on)
51+
gate_time = note_time * gate_percent
52+
53+
if gate_time > 0 and now - last_note_time >= gate_time:
54+
gate_time = 0
55+
note_off = tmidi.Message(tmidi.NOTE_OFF, pressed_notes[note_i], 127)
56+
print("arp note_off:", note_off)
57+
midi.send(note_off)
58+
note_i = (note_i + 1) % len(pressed_notes)

tmidi.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@
144144
}
145145

146146

147-
# pylint: disable=chained-comparison
148147
def _is_channel_message(status_byte):
149148
return status_byte >= NOTE_OFF and status_byte < SYSEX
150149

@@ -202,7 +201,6 @@ class Message:
202201
print("note off:", msg.note, msg.velocity)
203202
elif msg.type == tmidi.PROGRAM_CHANGE:
204203
print("program change:", msg.value)
205-
206204
"""
207205

208206
def __init__(self, mtype=SYSTEM_RESET, data0=0, data1=0, channel=0):
@@ -226,7 +224,6 @@ def __bytes__(self):
226224
def __repr__(self):
227225
return self.__str__()
228226

229-
# pylint: disable=consider-using-f-string
230227
def __str__(self):
231228
mtype = self.type
232229
type_str = "Message(" + _MSG_TYPE_NAMES.get(mtype, "Unknown")
@@ -403,7 +400,6 @@ def receive(self):
403400

404401
return message
405402

406-
# pylint: disable=unnecessary-dunder-call
407403
def send(self, msg, channel=None):
408404
"""Send a MIDI message.
409405

0 commit comments

Comments
 (0)