|
| 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) |
0 commit comments