303 lines
6.6 KiB
Python
303 lines
6.6 KiB
Python
#!/usr/bin/python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
LPD8
|
|
v0.7.0
|
|
|
|
LPD8 Handler.
|
|
Start a dedicated thread to handle incoming events from LPD8 midi controller.
|
|
|
|
Depending on selected destination computer (Prog Chg + Pad number) actions will be done
|
|
locally or forwarded via OSC to given computer. Remote computer must run bhorpad or
|
|
maxwellator.
|
|
|
|
# Note
|
|
|
|
# Program Change button selected : change destination computer
|
|
|
|
# CC rotary -> midi CC.
|
|
|
|
|
|
by Sam Neurohack
|
|
from /team/laser
|
|
|
|
|
|
"""
|
|
|
|
|
|
import time
|
|
import rtmidi
|
|
from rtmidi.midiutil import open_midiinput
|
|
from threading import Thread
|
|
from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON, NOTE_OFF,
|
|
PITCH_BEND, POLY_PRESSURE, PROGRAM_CHANGE)
|
|
|
|
from mido import MidiFile
|
|
import mido
|
|
import sys
|
|
import os
|
|
ljpath = r'%s' % os.getcwd().replace('\\','/')
|
|
|
|
from . import midi3, launchpad
|
|
#import midimacros, maxwellmacros
|
|
import traceback
|
|
|
|
from queue import Queue
|
|
#from libs import macros
|
|
import json, subprocess
|
|
from .OSC3 import OSCServer, OSCClient, OSCMessage
|
|
import socket
|
|
|
|
|
|
myIP = "127.0.0.1"
|
|
|
|
print('LPD8 startup...')
|
|
myHostName = socket.gethostname()
|
|
print(("Name of the localhost is {}".format(myHostName)))
|
|
#myIP = socket.gethostbyname(myHostName)
|
|
print(("IP address of the localhost is {}".format(myIP)))
|
|
|
|
|
|
print(('Used IP', myIP))
|
|
OSCinPort = 8080
|
|
maxwellatorPort = 8090
|
|
|
|
LPD8queue = Queue()
|
|
|
|
mode = "maxwell"
|
|
mididest = 'Session 1'
|
|
|
|
midichannel = 1
|
|
CChannel = 0
|
|
CCvalue = 0
|
|
Here = -1
|
|
|
|
ModeCallback = ''
|
|
computerIP = ['127.0.0.1','192.168.2.95','192.168.2.52','127.0.0.1',
|
|
'127.0.0.1','127.0.0.1','127.0.0.1','127.0.0.1']
|
|
computer = 0
|
|
|
|
|
|
# /cc cc number value
|
|
def cc(ccnumber, value, dest=mididest):
|
|
|
|
midi3.MidiMsg([CONTROLLER_CHANGE+midichannel-1,ccnumber,value], dest)
|
|
|
|
def NoteOn(note,velocity, dest=mididest):
|
|
midi3.NoteOn(note,velocity, mididest)
|
|
|
|
def NoteOff(note, dest=mididest):
|
|
midi3.NoteOn(note, mididest)
|
|
|
|
|
|
def ComputerUpdate(comput):
|
|
global computer
|
|
|
|
computer = comput
|
|
|
|
|
|
|
|
# Client to export buttons actions from LPD8 or bhoreal
|
|
|
|
def SendOSC(ip,port,oscaddress,oscargs=''):
|
|
|
|
oscmsg = OSCMessage()
|
|
oscmsg.setAddress(oscaddress)
|
|
oscmsg.append(oscargs)
|
|
|
|
osclient = OSCClient()
|
|
osclient.connect((ip, port))
|
|
|
|
print(("sending OSC message : ", oscmsg, "to", ip, ":", port))
|
|
|
|
try:
|
|
osclient.sendto(oscmsg, (ip, port))
|
|
oscmsg.clearData()
|
|
return True
|
|
except:
|
|
print(('Connection to', ip, 'refused : died ?'))
|
|
return False
|
|
|
|
|
|
#
|
|
# Events from LPD8 buttons
|
|
#
|
|
|
|
# Process events coming from LPD8 in a separate thread.
|
|
|
|
def MidinProcess(LPD8queue):
|
|
global computer
|
|
|
|
|
|
while True:
|
|
LPD8queue_get = LPD8queue.get
|
|
msg = LPD8queue_get()
|
|
#print (msg)
|
|
|
|
# Note
|
|
if msg[0]==NOTE_ON:
|
|
|
|
# note mode
|
|
ModeNote(msg[1], msg[2], mididest)
|
|
|
|
'''
|
|
# ModeOS
|
|
if msg[2] > 0:
|
|
ModeOS(msg[0])
|
|
'''
|
|
|
|
|
|
# Program Change button selected : change destination computer
|
|
if msg[0]==PROGRAM_CHANGE:
|
|
|
|
print(("Program change : ", str(msg[1])))
|
|
# Change destination computer mode
|
|
print(("Destination computer",int(msg[1])))
|
|
computer = int(msg[1])
|
|
|
|
|
|
# CC rotary -> midi CC.
|
|
if msg[0] == CONTROLLER_CHANGE:
|
|
|
|
print(("CC :", msg[1], msg[2]))
|
|
|
|
if computer == 0 or computer == 1:
|
|
cc(int(msg[1]), int(msg[2]))
|
|
|
|
else:
|
|
SendOSC(computerIP[computer-1], maxwellatorPort, '/cc', [int(msg[1]), int(msg[2])])
|
|
|
|
#
|
|
# Notes = midi notes
|
|
#
|
|
|
|
def ModeNote(note, velocity, mididest):
|
|
|
|
|
|
print(('computer',computer))
|
|
|
|
# todo : decide whether its 0 or 1 !!!
|
|
if computer == 0 or computer == 1:
|
|
midi3.NoteOn(arg, velocity, mididest)
|
|
|
|
|
|
if velocity == 127:
|
|
pass
|
|
#print ('NoteON', BhorNoteXY(x,y),notename , "velocity", velocity )
|
|
#Disp(notename)
|
|
else:
|
|
midi3.NoteOff(arg)
|
|
#print ('NoteOFF', BhorNoteXY(x,y),notename , "velocity", velocity )
|
|
|
|
|
|
|
|
#
|
|
# Notes = OS Macros
|
|
#
|
|
|
|
def ModeOS(arg):
|
|
|
|
|
|
macroname = 'n'+arg
|
|
macronumber = findMacros(macroname,'OS')
|
|
if macronumber != -1:
|
|
|
|
eval(macros['OS'][macronumber]["code"])
|
|
else:
|
|
print("no Code yet")
|
|
|
|
|
|
|
|
LPD8queue = Queue()
|
|
|
|
|
|
# LPD8 Mini call back : new msg forwarded to LPD8 queue
|
|
class LPD8AddQueue(object):
|
|
def __init__(self, port):
|
|
self.port = port
|
|
#print("LPD8AddQueue", self.port)
|
|
self._wallclock = time.time()
|
|
|
|
def __call__(self, event, data=None):
|
|
message, deltatime = event
|
|
self._wallclock += deltatime
|
|
print()
|
|
print(("[%s] @%0.6f %r" % (self.port, self._wallclock, message)))
|
|
LPD8queue.put(message)
|
|
|
|
#
|
|
# Modes :
|
|
#
|
|
|
|
# Load Matrix only macros (for the moment) in macros.json
|
|
def LoadMacros():
|
|
global macros
|
|
|
|
print()
|
|
print("Loading LPD8 Macros...")
|
|
|
|
if os.path.exists('libs/matrix.json'):
|
|
#print('File libs/matrix.json exits')
|
|
f=open("libs/matrix.json","r")
|
|
|
|
elif os.path.exists(ljpath+'/../../libs/matrix.json'):
|
|
#print('File '+ljpath+'/../../libs/matrix.json exits')
|
|
f=open(ljpath+"/../../libs/matrix.json","r")
|
|
|
|
s = f.read()
|
|
macros = json.loads(s)
|
|
print((len(macros['OS']),"Macros"))
|
|
print("Loaded.")
|
|
|
|
|
|
# return macroname number for given type 'OS', 'Maxwell'
|
|
def findMacros(macroname,macrotype):
|
|
|
|
#print("searching", macroname,'...')
|
|
position = -1
|
|
for counter in range(len(macros[macrotype])):
|
|
#print (counter,macros[macrotype][counter]['name'],macros[macrotype][counter]['code'])
|
|
if macroname == macros[macrotype][counter]['name']:
|
|
#print(macroname, "is ", counter)
|
|
position = counter
|
|
return position
|
|
|
|
|
|
|
|
# Not assigned buttons
|
|
def DefaultMacro(arg):
|
|
|
|
print(("DefaultMacro", arg))
|
|
|
|
|
|
|
|
|
|
#
|
|
# Default macros
|
|
#
|
|
|
|
|
|
LPD8macros = {
|
|
|
|
"n1": {"command": DefaultMacro, "default": 1},
|
|
"n2": {"command": DefaultMacro, "default": 2},
|
|
"n3": {"command": DefaultMacro, "default": 3},
|
|
"n4": {"command": DefaultMacro, "default": 4},
|
|
"n5": {"command": DefaultMacro, "default": 5},
|
|
"n6": {"command": DefaultMacro, "default": 6},
|
|
"n7": {"command": DefaultMacro, "default": 7},
|
|
"n8": {"command": DefaultMacro, "default": 8}
|
|
}
|
|
|
|
|
|
def Run(macroname, macroargs=''):
|
|
|
|
doit = LPD8macros[macroname]["command"]
|
|
if macroargs=='':
|
|
macroargs = LPD8macros[macroname]["default"]
|
|
#print("Running", doit, "with args", macroargs )
|
|
doit(macroargs)
|
|
|
|
LoadMacros()
|