Skip to content

Instantly share code, notes, and snippets.

@logsol
Last active November 21, 2018 13:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save logsol/f9532b5799c5c12c8e15f99b077a7a55 to your computer and use it in GitHub Desktop.
Save logsol/f9532b5799c5c12c8e15f99b077a7a55 to your computer and use it in GitHub Desktop.
Reads input from multiple Midi input devices via plug&play and sends them to an Axoloti

Install

pip3 install python-rtmidi

Run

python3 chip_midi_delegate.py

#!/usr/bin/env python
import logging
import sys
import time
import rtmidi.midiutil
import os
os.system('sudo echo "Welcome!"')
class MidiHandler(object):
def __init__(self, name, channel):
self.name = name
self.channel = channel
def __call__(self, event, data=None):
message, deltatime = event
if target is None:
return
if 'Axoloti Core' in self.name or 'Audio Kontrol 1' in self.name:
status = None
data1 = message[1]
data2 = message[2]
if(message[0] >= 144 and message[0] <= 159): # note on
status = 144
if(message[0] >= 128 and message[0] <= 143): # note off
status = 128
if(message[0] >= 176 and message[0] <= 191): # cc
status = 176
if(status is not None):
returnChannel = message[0]-status+1
if(any(list(filter(lambda item: item['channel'] == returnChannel, controllers)))):
controller = list(filter(lambda item: item['channel'] == returnChannel, controllers))[0]
if(channelMap[0] in controller['name'] and status == 128): # for midi mix change note off to note on vel=0
status = 144
data2 = 0
controller['returnPort'].send_message([status, data1, data2])
return
alteredMessage = message[:]
alteredMessage[0] += self.channel-1
try:
target.send_message(alteredMessage)
except:
print('MIDI SEND ERROR');
print(self.name, message, alteredMessage)
# These lines introduce huge latency
# if message[0] == 144:
# os.system('sudo i2cset -f -y 0 0x34 0x93 0x1')
# else:
# os.system('sudo i2cset -f -y 0 0x34 0x93 0x0')
channelMap = [
'MIDI Mix', #1
'LPD8', #2
'GarageKey mini', #3
'K-Mix MIDI 1', #4
'K-Mix MIDI 2', #5
'K-Mix MIDI 3' #6
]
midiin = rtmidi.MidiIn()
midiout = rtmidi.MidiOut()
controllers = []
target = None
def updateOutputTarget():
global target
names = midiout.get_ports()
existenceCheck = False
for name in names:
if 'Axoloti Core' in name or 'Audio Kontrol 1' in name:
if 'RtMidiIn Client' in name:
continue
existenceCheck = True
if target is not None:
break;
print ('+ Found Axoloti or AK1. Adding it as midi target')
try:
target, port_name = rtmidi.midiutil.open_midiport(name, "output")
except (EOFError, KeyboardInterrupt):
print('Failed to open midi port', name)
break
if target is not None and existenceCheck is False:
print ('+ Removing Axo target')
try:
target.close_port()
except ValueError:
print('could not close target midi port')
pass
target = None
def updateControllerList():
names = midiin.get_ports()
returnPortNames = midiout.get_ports()
cachedControllerNames = [tmp['name'] for tmp in controllers]
for name in names:
if not list(filter(lambda item: item['name'] == name, controllers)):
blacklist = ['Midi Through', 'RtMidiOut Client', 'IAC Driver KASE']#, 'K-Mix Audio Control', 'K-Mix Expander']
if any([s for s in blacklist if s in name]):
continue
port = None
if not name:
continue
try:
port, port_name = rtmidi.midiutil.open_midiport(name)
except (EOFError, KeyboardInterrupt, ValueError):
print('Failed to open midi port', name)
if not port:
continue
try:
returnPort, port_name = rtmidi.midiutil.open_midiport(name, "output")
except (EOFError, KeyboardInterrupt):
print('Failed to open RETURN midi port', name)
channel = 3
if any([s for s in channelMap if s in name]):
channel = channelMap.index([s for s in channelMap if s in name][0]) +1
port.set_callback(MidiHandler(name, channel))
controllers.append(dict(port=port, name=name, channel=channel, returnPort=returnPort))
print('> Adding controller', name)
try:
cachedControllerNames.remove(name)
except ValueError:
pass
for removed in cachedControllerNames:
removedController = [item for item in controllers if item['name'] == removed]
if removedController:
removedController = removedController[0]
try:
removedController['port'].close_port()
removedController['returnPort'].close_port()
except ValueError:
print('could not close midi port', removedController)
pass
try:
controllers.remove(removedController)
print('> Removing controller', removedController['name'])
except ValueError:
print('could not remove from controllers', removedController['name'])
pass
else:
print('problem: could not find controller to remove!')
try:
# just wait for keyboard interrupt in main thread
while True:
updateOutputTarget()
updateControllerList()
time.sleep(3)
except KeyboardInterrupt:
print('')
finally:
print("Exit.")
del midiin
del midiout
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment