Bug fixs
This commit is contained in:
parent
0528576418
commit
0fe991e0f2
21
README.md
21
README.md
@ -40,6 +40,7 @@ or
|
||||
/tr808/note/1
|
||||
|
||||
cc : is a "command". Currently cc, reset (highly specific to nozoid synthetiser). You can add any tyoe of "command".
|
||||
|
||||
ocs2 : is a "device", that must be described, follow examples in jamidi.json. Here the Alice OCS2 will reveive broadcasted midi informations.
|
||||
|
||||
/ocs2 and /tr808 changes made by John will be displayed to everyone and played by devices.
|
||||
@ -60,12 +61,17 @@ Options :
|
||||
servername : 'local', 'llstrvpn'. Servers (IP, port,...) must be described in jamidi.json
|
||||
|
||||
--broadcast : Broadcast all incomings commands to all client. Default option.
|
||||
|
||||
--no-broadcast : Do not broadcast all incomings commands to all client.
|
||||
|
||||
|
||||
--reset : Send reset values to local device a startup. Default option.
|
||||
|
||||
--no-reset : Do not send reset values to local device a startup.
|
||||
|
||||
|
||||
--current : Send all current CC values to all new client. Default option.
|
||||
|
||||
--no-current : Do not send all current CC values to all new client.
|
||||
|
||||
|
||||
@ -78,11 +84,17 @@ Can be webpages or midi instrument/software. Multiple clients types is supported
|
||||
Options :
|
||||
|
||||
servername : Remote server 'local', 'xrkia' ('local' by default). Servers must be described in jamidi.json
|
||||
|
||||
default : Network <-> default midi device (True or False)
|
||||
|
||||
|
||||
Some "rules" are available. Say you want all network incoming midi CC 1 channel 0 goes to a specific device on channel 3 CC 48. Rules must be described in rules.json
|
||||
|
||||
Each rule may happen at all time or only during a "song".
|
||||
|
||||
How to Run python client :
|
||||
|
||||
python3 client.py
|
||||
|
||||
|
||||
|
||||
@ -90,13 +102,18 @@ Each rule may happen at all time or only during a "song".
|
||||
|
||||
1/ Run :
|
||||
|
||||
python3 mainwip.py
|
||||
|
||||
python3 main.py
|
||||
|
||||
|
||||
2/ In a browser open 2 instances of each of these :
|
||||
|
||||
|
||||
indexaurora.html is a three rotating encoders example.
|
||||
|
||||
mmo3.html and ocs2.html demo to control 2 real life nozoids.
|
||||
|
||||
|
||||
3/ Each aurora pages talk to each other. Each mmo3 to each other and so on..
|
||||
|
||||
|
||||
@ -114,7 +131,7 @@ var LJ = 'ws://127.0.0.1:8081/'
|
||||
|
||||
3/ Run :
|
||||
|
||||
python3 mainwip.py
|
||||
python3 main.py
|
||||
|
||||
4/
|
||||
|
||||
|
266
client.py
266
client.py
@ -1,37 +1,27 @@
|
||||
#!/usr/bin/python2.7
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
|
||||
'''
|
||||
NozoidUI Client v0.0.1
|
||||
|
||||
Input : local midi instruments
|
||||
Output : nozoidtUI server
|
||||
|
||||
|
||||
|
||||
Websocket INSTALLER
|
||||
|
||||
|
||||
https://files.pythonhosted.org/packages/8b/0f/52de51b9b450ed52694208ab952d5af6ebbcbce7f166a48784095d930d8c/websocket_client-0.57.0.tar.gz
|
||||
|
||||
Jamidi Client v0.1b
|
||||
|
||||
Input : local midi (hardware/software) instruments
|
||||
Output : Jamidi server
|
||||
|
||||
'''
|
||||
|
||||
print("")
|
||||
print("")
|
||||
print("Jamidi Client")
|
||||
print("v0.1b")
|
||||
|
||||
print ""
|
||||
print ""
|
||||
print "NozoidUI Client"
|
||||
print "v0.0.1"
|
||||
|
||||
from multiprocessing import Process, Queue, TimeoutError
|
||||
|
||||
|
||||
import subprocess
|
||||
#from multiprocessing import Process, Queue, TimeoutError
|
||||
#import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
|
||||
from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON, NOTE_OFF,
|
||||
PITCH_BEND, POLY_PRESSURE, PROGRAM_CHANGE)
|
||||
@ -44,27 +34,46 @@ import websocket
|
||||
|
||||
|
||||
try:
|
||||
import thread
|
||||
import _thread
|
||||
except ImportError:
|
||||
import _thread as thread
|
||||
import time
|
||||
|
||||
import argparse
|
||||
|
||||
debug = 1
|
||||
|
||||
#
|
||||
# webUI server
|
||||
#
|
||||
|
||||
serverIP = "xrkia.org"
|
||||
# serverIP = "127.0.0.1"
|
||||
# serverIP = "10.8.0.46"
|
||||
wsPORT = 8081
|
||||
print ("")
|
||||
print ("Arguments parsing if needed...")
|
||||
argsparser = argparse.ArgumentParser(description="Jamidi Client v0.1b commands help mode")
|
||||
argsparser.add_argument("-s","--servername",help="servername: 'local', 'xrkia' ('local' by default)", type=str)
|
||||
|
||||
argsparser.add_argument('--default',help="All incoming midi <-> default midi device. Default option." , dest='default', action='store_true')
|
||||
argsparser.add_argument('--no-default',help="Do not send reset values to local device a startup.", dest='default', action='store_false')
|
||||
argsparser.set_defaults(default=True)
|
||||
|
||||
args = argsparser.parse_args()
|
||||
|
||||
# Server
|
||||
if args.servername:
|
||||
servername = args.servername
|
||||
else:
|
||||
servername = "local"
|
||||
|
||||
# Default midi device like controller
|
||||
if args.default == False:
|
||||
print("Default device disabled")
|
||||
defaultdevice = False
|
||||
else:
|
||||
print("Default device enabled")
|
||||
defaultdevice = True
|
||||
|
||||
#
|
||||
# Midi part
|
||||
#
|
||||
|
||||
# default local MIDI device
|
||||
|
||||
nozmidi = "BCR2000 Port 1"
|
||||
# nozmidi = "Arturia BeatStep"
|
||||
# nozmidi = "Virtual Midi A"
|
||||
@ -79,30 +88,151 @@ midichanMMO3 = 1
|
||||
resetMMO3 = [0] * 32
|
||||
resetOCS2 = [0] * 32
|
||||
|
||||
# /cc cc number value
|
||||
def cc(midichannel, ccnumber, value, mididest):
|
||||
songs = ["song1", "song2"]
|
||||
song = 0
|
||||
|
||||
print "NozoidUI Sending Midi channel", midichannel, "cc", ccnumber, "value", value, "to", mididest
|
||||
|
||||
def GetTime():
|
||||
return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
|
||||
|
||||
|
||||
#
|
||||
# Settings from clientruler.json
|
||||
#
|
||||
|
||||
# Load midi routing definitions in clientruler.json
|
||||
def LoadMidiRules():
|
||||
global MidiRules, nbmidirule
|
||||
|
||||
if os.path.exists('rules.json'):
|
||||
f=open("rules.json","r")
|
||||
|
||||
s = f.read()
|
||||
MidiRules = json.loads(s)
|
||||
|
||||
|
||||
|
||||
|
||||
# return midi rulename number for given type 'Specials', 'cc2cc'
|
||||
def findMidiRules(rulename,ruletype):
|
||||
|
||||
#print("searching", midirulename,'...')
|
||||
position = -1
|
||||
for counter in range(len(MidiRules[ruletype])):
|
||||
if rulename == MidiRules[ruletype][counter]['name']:
|
||||
#print(rulename, "is ", counter)
|
||||
position = counter
|
||||
return position
|
||||
|
||||
#
|
||||
# Settings from jamidi.json
|
||||
#
|
||||
|
||||
# Load midi routing definitions in clientconfr.json
|
||||
def LoadConfs():
|
||||
global Confs, nbmidiconf
|
||||
|
||||
if os.path.exists('jamidi.json'):
|
||||
f=open("jamidi.json","r")
|
||||
|
||||
s = f.read()
|
||||
Confs = json.loads(s)
|
||||
|
||||
|
||||
|
||||
# return midi confname number for given type 'Specials', 'cc2cc'
|
||||
def findConfs(confname,conftype):
|
||||
|
||||
#print("searching", midiconfname,'...')
|
||||
position = -1
|
||||
for counter in range(len(Confs[conftype])):
|
||||
if confname == Confs[conftype][counter]['name']:
|
||||
#print(confname, "is ", counter)
|
||||
position = counter
|
||||
return position
|
||||
|
||||
|
||||
|
||||
def curved(value):
|
||||
return round(np.sqrt(value)*11.27)
|
||||
|
||||
|
||||
# /cc cc number value
|
||||
def cc(midichannel, ccnumber, value, mididest):
|
||||
|
||||
#print "cc()"
|
||||
print("Jamidi Sending locally Midi channel", midichannel, "cc", ccnumber, "value", value, "to", mididest)
|
||||
|
||||
# Apply CC routing ?
|
||||
if len(MidiRules["cc2cc"]) > 0 :
|
||||
#print "cc2cc test for channel", midichannel, "CC", ccnumber, "val", value, "song", songs[song]
|
||||
for counter in range(len(MidiRules["cc2cc"])):
|
||||
if (MidiRules["cc2cc"][counter]["songname"] == songs[song] or MidiRules["cc2cc"][counter]["songname"] == "all") and (MidiRules["cc2cc"][counter]["chanIN"] == midichannel or MidiRules["cc2cc"][counter]["chanIN"] == "all") and (MidiRules["cc2cc"][counter]["ccs"] == ccnumber or MidiRules["cc2cc"][counter]["ccs"] == "all"):
|
||||
print("cc2cc routing for song",MidiRules["cc2cc"][counter]["songname"], ":", MidiRules["cc2cc"][counter]["name"])
|
||||
#print("cc2cc got song :", MidiRules["cc2cc"][counter]["songname"]," IN Channel :", MidiRules["cc2cc"][counter]["chanIN"]," Code :", MidiRules["cc2cc"][counter]["code"], " value :",MidiRules["ZnotesLcc"][counter]["valuetype"], )
|
||||
if MidiRules["cc2cc"][counter]["valuetype"] == "linear":
|
||||
print("Linear", MidiVal)
|
||||
midi3.MidiMsg((176 + MidiRules["cc2cc"][counter]["chanOUT"], MidiRules["cc2cc"][counter]["ccOUT"], MidiVal), MidiRules["cc2cc"][counter]["mididest"])
|
||||
|
||||
if MidiRules["cc2cc"][counter]["valuetype"] == "curved":
|
||||
print(MidiVal,"got curved", curved(MidiVal))
|
||||
midi3.MidiMsg((176 + MidiRules["cc2cc"][counter]["chanOUT"], MidiRules["cc2cc"][counter]["ccOUT"], curved(MidiVal)), MidiRules["cc2cc"][counter]["mididest"])
|
||||
|
||||
|
||||
#else:
|
||||
print("Jamidi Sending locally Midi channel", midichannel, "cc", ccnumber, "value", value, "to", mididest)
|
||||
#if mididest == "BCR2000 Port 1":
|
||||
|
||||
midi3.MidiMsg([CONTROLLER_CHANGE+midichannel-1, ccnumber, value], mididest)
|
||||
|
||||
|
||||
'''
|
||||
# Specials features ?
|
||||
if len(MidiRules['Specials']) > 0:
|
||||
|
||||
for counter in range(len(MidiRules["Specials"])):
|
||||
|
||||
# print()
|
||||
# print("Name", MidiRules["Specials"][counter]["name"])
|
||||
# print("Song", MidiRules["Specials"][counter]["songname"], songs[song]) # name, "all"
|
||||
# print("Channel", MidiRules["Specials"][ counter]["chanIN"], MidiChannel) # number, "all"
|
||||
# print("Note", MidiRules["Specials"][counter]["notes"], MidiNote) # number, "all"
|
||||
# print("Notetype", MidiRules["Specials"][counter]["notetype"], "on") # "on", "off", "all"
|
||||
|
||||
if (MidiRules["Specials"][counter]["songname"] == songs[song] or MidiRules["Specials"][counter]["songname"] == "all") and (MidiRules["Specials"][counter]["chanIN"] == MidiChannel or MidiRules["Specials"][counter]["chanIN"] == "all") and (MidiRules["Specials"][counter]["notes"] == MidiNote or MidiRules["Specials"][counter]["notes"] == "all") and (MidiRules["Specials"][counter]["notetype"] == "off" or MidiRules["Specials"][counter]["notetype"] == "all") :
|
||||
midirulecode = MidiRules["Specials"][counter]["code"]
|
||||
print("Specials function :",MidiRules["Specials"][counter]["songname"], ":", MidiRules["Specials"][counter]["name"], midirulecode)
|
||||
|
||||
# python function
|
||||
if midirulecode.count('.') > 0:
|
||||
#print(midirulecode+"("+str(MidiNote)+')')
|
||||
eval(midirulecode+"("+str(MidiNote)+')')
|
||||
|
||||
# Maxwell function
|
||||
elif midirulecode.count('/') > 0:
|
||||
#print("Specials NoteON got :", MidiRules["Specials"][counter]["songname"]," IN Channel :", MidiRules["Specials"][counter]["chanIN"]," Code :", midirulecode, " CC", maxwellccs.FindCC(MidiRules["Specials"][counter]["code"]), " value :",MidiRules["Specials"][counter]["valuetype"], " laser :", MidiRules["ZccLcc"][counter]["laser"] )
|
||||
midi3.MidiMsg((CONTROLLER_CHANGE, maxwellccs.FindCC(MidiRules["Specials"][counter]["code"]), MidiRules["Specials"][counter]["valuetype"]), mididest, laser = MidiRules["Specials"][counter]["laser"])
|
||||
|
||||
'''
|
||||
|
||||
# /reset nozoids with "default" values
|
||||
def reset(nozoid):
|
||||
|
||||
print ""
|
||||
print "reseting", nozoid
|
||||
print("")
|
||||
print(GetTime(),"reseting", nozoid)
|
||||
|
||||
if nozoid == "mmo3":
|
||||
for ccnumber in xrange(0,32):
|
||||
midi3.MidiMsg([CONTROLLER_CHANGE+midichanMMO3-1, ccnumber, resetMMO3[ccnumber]], nozmidi)
|
||||
for ccnumber in range(0,32):
|
||||
midi3.MidiMsg([CONTROLLER_CHANGE+Confs["mmo3"][0]["midichan"]-1, ccnumber, resetMMO3[ccnumber]], Confs["mmo3"][0]["mididevice"])
|
||||
sendWSall("/mmo3/cc/"+str(ccnumber)+" "+str(resetMMO3[ccnumber]))
|
||||
crtvalueMMO3[ccnumber]=resetMMO3[ccnumber]
|
||||
else:
|
||||
for ccnumber in xrange(0,32):
|
||||
midi3.MidiMsg([CONTROLLER_CHANGE+midichanOCS2-1, ccnumber, resetOCS2[ccnumber]], nozmidi)
|
||||
sendWSall("/ocs2/cc/"+str(ccnumber)+" "+str(resetMMO3[ccnumber]))
|
||||
|
||||
for ccnumber in range(0,32):
|
||||
midi3.MidiMsg([CONTROLLER_CHANGE+Confs["ocs2"][0]["midichan"]-1, ccnumber, resetOCS2[ccnumber]], Confs["ocs2"][0]["mididevice"])
|
||||
sendWSall("/ocs2/cc/"+str(ccnumber)+" "+str(resetOCS2[ccnumber]))
|
||||
crtvalueOCS2[ccnumber]=resetOCS2[ccnumber]
|
||||
print("End of reset for", nozoid)
|
||||
print("")
|
||||
#
|
||||
# Websocket part
|
||||
#
|
||||
@ -132,11 +262,11 @@ def on_open(ws):
|
||||
print("thread terminating...")
|
||||
|
||||
|
||||
thread.start_new_thread(run, ())
|
||||
_thread.start_new_thread(run, ())
|
||||
|
||||
def on_message(ws, message):
|
||||
#
|
||||
print ""
|
||||
print("")
|
||||
print(message)
|
||||
if len(message) > 200:
|
||||
message = message[:200]+'..'
|
||||
@ -144,22 +274,31 @@ def on_message(ws, message):
|
||||
oscpath = message.split(" ")
|
||||
if debug > 0:
|
||||
#print "Client got from WS", client['id'], "said :", message, "splitted in an oscpath :", oscpath
|
||||
print "Client got from WS said :", message, "splitted in an oscpath :", oscpath
|
||||
print("clientruler got from WS :", message, "splitted in an oscpath :", oscpath)
|
||||
|
||||
wscommand = oscpath[0].split("/")
|
||||
print "WS command was :",wscommand
|
||||
print("WS command was :",wscommand)
|
||||
|
||||
if len(oscpath) == 1:
|
||||
args[0] = "noargs"
|
||||
#print "noargs command"
|
||||
|
||||
elif wscommand[2] == "cc":
|
||||
if wscommand[1] == "ocs2":
|
||||
print "Incoming OCS-2 WS"
|
||||
cc(midichanOCS2, int(wscommand[3]), int(oscpath[1]), nozmidi)
|
||||
else:
|
||||
print "Incoming MMO-3 WS"
|
||||
cc(midichanMMO3, int(wscommand[3]), int(oscpath[1]), nozmidi)
|
||||
elif wscommand[1] == "ocs2":
|
||||
if wscommand[2] == "cc":
|
||||
print("Incoming OCS-2 WS CC", wscommand[3], ":", int(oscpath[1]))
|
||||
cc(Confs["ocs2"][0]["midichan"], int(wscommand[3]), int(oscpath[1]), Confs["default"][0]["mididevice"])
|
||||
|
||||
if wscommand[2] == "OSC1":
|
||||
print("Incoming OCS-2 WS OSC1", wscommand[3], ":", int(oscpath[1]))
|
||||
|
||||
|
||||
elif wscommand[1] == "mmo3":
|
||||
if wscommand[2] == "cc":
|
||||
print("Incoming MMO-3 WS CC", wscommand[3], ":", int(oscpath[1]))
|
||||
cc(Confs["mmo3"][0]["midichan"], int(wscommand[3]), int(oscpath[1]), Confs["default"][0]["mididevice"])
|
||||
|
||||
if wscommand[2] == "OSC1":
|
||||
print("Incoming MMO-3 WS OSC1", wscommand[3], ":", int(oscpath[1]))
|
||||
|
||||
|
||||
elif wscommand[2] == "reset":
|
||||
@ -173,15 +312,21 @@ def on_message(ws, message):
|
||||
# sendWSall(message)
|
||||
|
||||
|
||||
LoadMidiRules()
|
||||
LoadConfs()
|
||||
|
||||
print "Running...."
|
||||
serverIP = Confs[servername][0]["IP"]
|
||||
#serverIP = "10.8.0.46"
|
||||
wsPORT = Confs[servername][0]["port"]
|
||||
|
||||
print("Running....")
|
||||
|
||||
# Main loop do nothing. Maybe do the webui server ?
|
||||
try:
|
||||
|
||||
print ""
|
||||
print "Connecting to NozoidUI server..."
|
||||
print "at", serverIP, "port",wsPORT
|
||||
print("")
|
||||
print("Connecting to Jamidi server...")
|
||||
print("at", serverIP, "port",wsPORT)
|
||||
|
||||
#websocket.enableTrace(True)
|
||||
ws = websocket.WebSocketApp("ws://"+str(serverIP)+":"+str(wsPORT),
|
||||
@ -192,21 +337,22 @@ try:
|
||||
midi3.ws = ws
|
||||
midi3.wsmode = True
|
||||
|
||||
print "Midi Configuration..."
|
||||
print "Midi Destination", nozmidi
|
||||
print("Midi Configuration...")
|
||||
|
||||
midi3.check()
|
||||
|
||||
ws.on_open = on_open
|
||||
ws.run_forever()
|
||||
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
# Gently stop on CTRL C
|
||||
|
||||
print "Fin de NozoidUI."
|
||||
print("Fin de Jamidi.")
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user