Skip to content

Instantly share code, notes, and snippets.

@PeteMidi
Created July 20, 2020 23:57
Show Gist options
  • Save PeteMidi/cfdd9483c8f5fa4433a2bcfead9c0ada to your computer and use it in GitHub Desktop.
Save PeteMidi/cfdd9483c8f5fa4433a2bcfead9c0ada to your computer and use it in GitHub Desktop.
TD-3 arpeggiator in Python 3 using numpy and Mido
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on July 7 2020
@author: Pete Midi
"""
import mido
import numpy as np
# print available port names
print('Inputs:')
inputs = mido.get_input_names()
print(inputs)
print('Outputs:')
outputs = mido.get_output_names()
print(outputs)
# print received sequence notes
print_note_flag = False
# open ports
# inputs
name_in_td3 = 'mio10:mio10 MIDI 1' # sequence master
name_in_kbd = 'QuNexus' # keyboard chord notes
port_in_td3 = mido.open_input([s for s in inputs if s.startswith(name_in_td3)][0])
port_in_kbd = mido.open_input([s for s in inputs if s.startswith(name_in_kbd)][0])
# outputs
name_out_td3 = 'mio10:mio10 MIDI 1' # arpeggio slave
port_out_td3 = mido.open_output([s for s in outputs if s.startswith(name_out_td3)][0])
#name_out_fx = 'mio10:mio10 MIDI 2' # delay effect clock sync
#port_out_fx = mido.open_output([s for s in outputs if s.startswith(name_out_fx)][0])
# midi channels (0,1,...,15)
chan_out_td3 = 1 # arpeggio channel out
chan_in_td3 = 0 # trigger sequence channel in
# init
msg_ctrl = mido.Message('control_change', control=123, value=0, channel=chan_out_td3) # all notes off
msg_note = mido.Message('note_on', note=60, velocity=0, channel=chan_out_td3)
port_out_td3.send(msg_ctrl)
# helper function to close all midi ports
def close_ports():
#%% close ports
print('close ports!')
vd = locals()
keys = list(vd.keys())
for k in keys:
if k.startswith('port'):
if k.startswith('port_out_td3'):
for note_num in range(128):
msg_note = mido.Message('note_on', note=note_num, velocity=0, channel=chan_out_td3)
vd[k].send(msg_note)
vd[k].close()
# trigger map definition: sequence master input trigger notes
trig_c2c3 = np.array([36,48], dtype=int)
trig_c2c3c4 = np.array([36,48,60], dtype=int)
trig_c2g2c3 = np.array([36,43,48], dtype=int)
trig_c2g2c3g3 = np.array([36,43,48,55], dtype=int)
trig_c2c3g3c4 = np.array([36,48,55,60], dtype=int)
trig_vec = trig_c2g2c3 # trigger map selection
# chord note ring buffer init
chord_in_vec = np.array(trig_vec, dtype = np.int8)
chord_on_vec = np.full(trig_vec.size, -1, dtype = np.int8)
chord_idx = 0 # chord note write index (position)
# chord index reset time
reset_time = 48 # clock tics (96 per measure)
clock_counter = 0
clock_counter_old = 0
stop_flag = False
note_stop = -1 # exit script note number - change this acc. to your keyboard range!
# loop
while not stop_flag:
for msg in port_in_td3.iter_pending():
if msg.type == 'start' or msg.type == 'stop':
print(clock_counter)
clock_counter = 0
#port_out_fx.send(msg)
if msg.type == 'clock':
clock_counter += 1
#port_out_fx.send(msg)
if msg.type == 'note_on' and msg.channel == chan_in_td3: # arpeggiator trigger notes
if print_note_flag:
print(msg)
i_vec = (trig_vec==msg.note)
if i_vec.max() > 0:
msg.channel = chan_out_td3
note_out = chord_in_vec[i_vec.argmax()]
chord_on_vec[i_vec.argmax()] = note_out
msg.note = note_out
port_out_td3.send(msg)
if msg.type == 'note_off' and msg.channel == chan_in_td3: # arpeggiator trigger notes
i_vec = (trig_vec==msg.note)
if i_vec.max() > 0:
msg.channel = chan_out_td3
msg.velocity = 0
note_out = chord_on_vec[i_vec.argmax()]
if note_out < 0: # faulty !
note_out = chord_in_vec[i_vec.argmax()]
else:
chord_on_vec[i_vec.argmax()] = -1
msg.note = note_out
port_out_td3.send(msg)
for msg in port_in_kbd.iter_pending():
if msg.type == 'note_on' and msg.velocity > 0: # arpeggiator chord notes
if clock_counter - clock_counter_old > reset_time:
chord_idx = 0 # start filling array from begin
else:
chord_idx = (chord_idx + 1) % len(chord_in_vec)
clock_counter_old = clock_counter
chord_in_vec[chord_idx] = msg.note
# print(chord_in_vec)
if msg.note == note_stop:
stop_flag = True
stop_flag = False
close_ports()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment