Added UDP connector for ORCA Livecoding !!

This commit is contained in:
sam 2020-05-05 22:42:22 +02:00
parent 012bef55b1
commit b79a3487eb
8 changed files with 850 additions and 319 deletions

View File

@ -4,7 +4,7 @@ By llstr, Sam Neurohack
LICENCE : CC NC LICENCE : CC NC
Midi and more exchanges over LAN/Internet Midi and more exchanges over LAN/Internet. Now with ORCA live coding support !!
Imagine Bob own a TR 808 at home and Alice a nozoid OCS-2. They can control each other devices in a webpage or a midi controller. Imagine Bob own a TR 808 at home and Alice a nozoid OCS-2. They can control each other devices in a webpage or a midi controller.
If John has a mutliple encoders midi controller at home and want to control Alice and Bob devices, all changes made by John will be displayed to everyone and played by devices. If John has a mutliple encoders midi controller at home and want to control Alice and Bob devices, all changes made by John will be displayed to everyone and played by devices.
@ -25,6 +25,38 @@ More you can use also a vcvrack complex patch to drive light fixtures, laser abs
- Jamidi is experimental and nowhere safe. Network managment and security is not in jamidi scope. Some ideas : All computers can be on the same encrypted vpn (tinc, zerotier,..). The server can run on a VPS and all client connect to it. The server is at home, closer to midi devices,... - Jamidi is experimental and nowhere safe. Network managment and security is not in jamidi scope. Some ideas : All computers can be on the same encrypted vpn (tinc, zerotier,..). The server can run on a VPS and all client connect to it. The server is at home, closer to midi devices,...
- Look at jamidi.json for set your configuration. 2 element types : midi device and IP servers
# ORCA livecoding support.
Livecode some instrument somewhere else. https://github.com/hundredrabbits/Orca
On computer linked with desired midi instrument :
python3 main.py
Livecoder should configure ORCA and use it :
CTRL K ip:ipaddress
CTRL K udp:udport (default is 8083)
MIDI CCs base 36 use ;cmnd
m : midi channel 0-F (0-15)
n : number 0-Z (0-35)
d : data 0-Z will output (d/36)*127
MIDI NOTES use ;nmonv
m : midi channel 0-F (0-15)
o : octave 0-8
n : Note A-G. For note with # : a-g
v : velocity 0-Z will output (v/36)*127
@ -39,9 +71,9 @@ or
/tr808/note/1 /tr808/note/1
cc : is a "command". Currently cc, reset (highly specific to nozoid synthetiser). You can add any tyoe of "command". 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 : 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. /ocs2 and /tr808 changes made by John will be displayed to everyone and played by devices.
@ -55,46 +87,55 @@ Websocket default port is 8081 but one can change.
Will receive all "commands" from all clients, forward them to local devices and broadcast them too. Will receive all "commands" from all clients, forward them to local devices and broadcast them too.
servername : 'local', 'llstrvpn'. Servers (IP, port,...) must be described in jamidi.json
How to Run python server :
python3 main.py
Options : Options :
servername : 'local', 'llstrvpn'. Servers (IP, port,...) must be described in jamidi.json -h Show this help message and exit
--broadcast : Broadcast all incomings commands to all client. Default option. -s SERVERNAME Servername: 'local', 'llstrvpn' (local by default)
--no-broadcast : Do not broadcast all incomings commands to all client. -d DEVICENAME Mididevice for incoming ORCA via OSC (mmo3 by default)
-nocurrent Do not send all current CC values to all new client (enabled by default)
--reset : Send reset values to local device at startup. Default option. -nobroadcast Do not broadcast all incomings commands to all client (enabled by default)
--no-reset : Do not send reset values to local device at startup. -noreset Do not broadcast all incomings commands to all client (enabled by default)
-nothrough Disable the builtin midithrough from any midi IN to --device enabled by default
--current : Send all current CC values to all new client. Default option. -verbose Enable debug mode (disabled by default)
--no-current : Do not send all current CC values to all new client.
# How it work : Clients # How it work : Clients
Can be webpages or midi instrument/software. Multiple clients types is supported. Send midi over network to Jamidi. Can be webpages or midi instrument/software. Multiple clients types is supported.
How to Run python client :
python3 client.py
Options : Options :
servername : Remote server 'local', 'xrkia' ('local' by default). Servers must be described in jamidi.json servername : Remote server 'local', 'xrkia' ('local' by default). Servers must be described in jamidi.json
default : Network <-> default midi device (True or False) -s servername servername: 'local', 'xrkia' ('local' by default)
-nodefault Do not send reset values to local device a startup.
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 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". Each rule may happen at all time or only during a "song".
How to Run python client :
python3 client.py

View File

@ -51,6 +51,19 @@
} }
], ],
"sam" :
[
{
"_comment": "Server is laser.teamlaser.fr",
"type": "serverconf",
"name": "tmlsr",
"IP": "192.168.2.43",
"port": 8081,
"oscport": 8082,
"udport": 8083
}
],
"sq-1": [ "sq-1": [
{ {
"_comment": "SQ-1 device parameters", "_comment": "SQ-1 device parameters",
@ -89,59 +102,6 @@
"midichan" : 1, "midichan" : 1,
"xname" : "mmo3" "xname" : "mmo3"
} }
], ]
"ocs2bcr": [
{
"_comment": "OCS-2 control with BCR2000",
"type": "mididevice",
"mididevice": "BCR2000 Port 1",
"midichan" : 2,
"xname" : "ocs2"
}
],
"mmo3bcr": [
{
"_comment": "MMO-3 control with BCR2000",
"type": "mididevice",
"mididevice": "BCR2000 Port 1",
"midichan" : 1,
"xname" : "mmo3"
}
],
"launchpad": [
{
"_comment": "Launchpad mini device parameters",
"type": "mididevice",
"mididevice": "Launchpad Mini",
"midichan" : 0,
"xname" : "launchpad"
}
],
"maxwell": [
{
"_comment": "Mawell device parameters",
"type": "mididevice",
"mididevice": "to Maxwell 1",
"midichan" : 0,
"xname" : "ocs2"
}
],
"default": [
{
"_comment": "Client : default midi device",
"type": "mididevice",
"mididevice": "BCR2000 Port 1",
"midichan" : 3,
"xname" : "default"
}
]
} }

207
libs/OSCom.py Normal file
View File

@ -0,0 +1,207 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
OSCcom for jamidi v0.1b
OSCom.Start(serverIP, OSCPORT)
default handler : handler(path, tags, args, source)
register particular OSC command in Start(): i.e oscserver.addMsgHandler( "/n", Note)
'''
import midi3
#import socket
import types, json
from OSC3 import OSCServer, OSCClient, OSCMessage
import _thread, time
import gstt
import WScom, UDPcom
import midi3
#base36 = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
def GetTime():
return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
# this method of reporting timeouts only works by convention
# that before calling handle_request() field .timed_out is
# set to False
def handle_timeout(self):
self.timed_out = True
def Start(serverIP, OSCPORT):
global oscserver
#print(GetTime(),gstt.oscname, gstt.Confs[gstt.oscname][0]["midichan"])
#print(gstt.Confs)
#print(gstt.Confs[gstt.oscname])
for i in range(len(gstt.Confs[gstt.oscname])):
print(GetTime(),gstt.oscname, gstt.Confs[gstt.oscname][i]["midichan"])
oscserver = OSCServer( (serverIP, OSCPORT) )
oscserver.timeout = 0
# funny python's way to add a method to an instance of a class
import types
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
oscserver.addMsgHandler( "default", handler )
oscserver.addMsgHandler( "/n", Note)
oscserver.addMsgHandler( "/c", CC)
oscserver.addMsgHandler( "/p", PB)
_thread.start_new_thread(osc_thread, ())
# RAW OSC Frame available ?
def OSCframe():
# clear timed_out flag
oscserver.timed_out = False
# handle all pending requests then return
while not oscserver.timed_out:
oscserver.handle_request()
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
def osc_thread():
#print("osc Thread launched")
try:
while True:
time.sleep(0.005)
OSCframe()
except Exception as e:
import sys, traceback
print('\n---------------------')
print('Exception: %s' % e)
print('- - - - - - - - - - -')
traceback.print_tb(sys.exc_info()[2])
print("\n")
# Properly close the system. Todo
def Stop():
oscserver.close()
# default handler
def handler(path, tags, args, source):
oscaddress = ''.join(path.split("/"))
print()
print("Jamidi Default OSC Handler got from " + str(source[0]),"OSC msg", path, "args", args)
#print("OSC address", path)
#print("find.. /bhoreal ?", path.find('/bhoreal'))
if len(args) > 0:
#print("with args", args)
pass
'''
# for example
if path == '/truc':
arg1 = args[0]
arg2 = args[1])
'''
'''
MIDI NOTES
=n in ORCA
/n in OSC
ORCA OSC
=nmonv /n m o n v
m : midi channel (0-15 / ORCA 0-F)
o : octave (0-8 / ORCA 0-7)
n : Note A to G
v : velocity 0-Z will output (v/36)*127
'''
def Note(path, tags, args, source):
#print('Note from ORCA received',args)
midichannel = int(args[0],36)
octave = int(args[1],36)
note = args[2]
velocity = int((int(args[3],36)/36)*127)
if note.istitle() == True:
notename = str(note)+ str(octave)
else:
notename = str(note)+ "#"+ str(octave)
if gstt.debug > 0:
print("incoming note", note, octave, notename, midi3.note2midi(notename) )
for mididevice in midi3.findJamDevices(gstt.oscname):
midi3.NoteOn(midi3.note2midi(notename), velocity, mididevice)
#midi3.NoteOn(int(wspath[1]), int(wspath[2]), gstt.Confs[wscommand[1]][0]["mididevice"])
'''
CC
=c in ORCA
/c in OSC
ORCA OSC
=cmcd /c m n d
m : midi channel
n : number (0-35 / ORCA 0-Z)
d : data 0-Z will output (d/36)*127
'''
def CC(path, tags, args, source):
midichannel = int(args[0],36)
ccvr = int(args[1],36)
ccvl = int((int(args[2],36)/36)*127)
if gstt.debug > 0:
print("ccvr=%d/ccvl=%d"%(ccvr,ccvl))
if gstt.oscname == "ocs2":
gstt.crtvalueOCS2[ccvr]=ccvl
else:
gstt.crtvalueMMO3[ccvr]=ccvl
for mididevice in midi3.findJamDevices(gstt.oscname):
midi3.cc(gstt.Confs[gstt.oscname][0]["midichan"], ccvr, ccvl, mididevice)
def PB(path, tags, args, source):
#print("Pitch number",ccnumber, value)
midichannel = int(args[0])
ccnumber = int(args[1])
ccdata = int(args[3])
'''
# If needed to send some OSC
def SendOSC(ip,port,oscaddress,oscargs=''):
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
osclient = OSCClient()
osclient.connect((ip, port))
if gstt.debug == True :
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
'''

175
libs/UDPcom.py Normal file
View File

@ -0,0 +1,175 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
UDPcom for jamidi v0.1b
UDPcom.Start(serverIP, UDPORT)
Handler : udp_thread()
Read below for :
- MIDI NOTES use ;nmonv
- MIDI CCs use ;cmnd
'''
import midi3
#import socket
import types, json
import socket
import _thread, time
import midi3
import WScom, OSCom
import gstt
import time
#base36 = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
def GetTime():
return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
def udp_thread():
while True:
payload, client_address = sock.recvfrom(1024)
udpath = payload.decode('utf_8')
if gstt.debug > 1:
print(GetTime(),"UDP got", udpath, "from", str(client_address))
#print(udpath[0:1], " ",udpath[1:2], " ",udpath[2:3], " ",udpath[3:4], " " )
if udpath[0:1] == "n":
Note(udpath)
if udpath[0:1] == "c":
CC(udpath)
if udpath[0:1] == "f":
FullCC(udpath)
time.sleep(0.005)
def Start(serverIP, UDPORT):
global sock
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server = ( serverIP,UDPORT)
sock.bind(server)
_thread.start_new_thread(udp_thread, ())
'''
MIDI NOTES use ;nmonv
m : midi channel 0-F (0-15)
o : octave 0-8
n : Note A-G. For note with # : a-g
v : velocity 0-Z will output (v/36)*127
'''
def Note(udpnote):
if gstt.debug>0:
print()
print(GetTime(),'UDPNote from ORCA received', udpnote, udpnote[1:1])
midichannel = int(udpnote[1:2],36)
octave = int(udpnote[2:3],36)
note = udpnote[3:4]
velocity = (int(udpnote[4:5],36)/36)*127
#if gstt.debug>0:
print(GetTime(),'UDPNote from ORCA received:','midichannel:',midichannel,'octave:',octave,'note:',note,'velocity:',velocity)
#if octave < 9 or midichannel < 16 or int(note,36) < 10 or int(note,36) > 16:
if octave < 9 and midichannel < 16 and int(note,36) >= 10 and int(note,36) <= 16:
if note.istitle() == True:
notename = str(note.upper())+ str(octave)
else:
notename = str(note.upper())+ "#"+ str(octave)
if gstt.debug > 0:
print(GetTime(),"Incoming note", notename, "=", midi3.note2midi(notename), "velocity", velocity, "for channel", midichannel)
for mididevice in midi3.findJamDevices(gstt.oscname):
midi3.NoteOn(midi3.note2midi(notename), int(velocity), mididevice, midichannel-1)
# if sending note back to WS users :
#WScom.sendWSall("/"+midi3.findJamName(gstt.oscname, midichannel)+"/noteon "+str(midi3.note2midi(notename)))
else:
print(GetTime(),"Note", midichannel, octave, note, velocity,"had offchart parameters.")
'''
MIDI CCs base 36 use ;cmnd
m : midi channel 0-F (0-15)
n : number 0-Z (0-35)
d : data 0-Z will output (d/36)*127
'''
def CC(udpcc):
print()
midichannel = int(udpcc[1:2],36)
#midichannel = base36.index(udpcc[1:2].upper())
ccvr = int(udpcc[2:3],36)
ccvl = int((int(udpcc[3:4],36)/36)*127)
if midichannel < 16:
if gstt.debug > 0:
print(GetTime(),"ccvr=%d/ccvl=%d"%(ccvr,ccvl))
if gstt.oscname == "ocs2":
gstt.crtvalueOCS2[ccvr]=ccvl
else:
gstt.crtvalueMMO3[ccvr]=ccvl
for mididevice in midi3.findJamDevices(gstt.oscname):
midi3.cc(midichannel, ccvr, ccvl, mididevice)
#midi3.cc(gstt.Confs[gstt.oscname][0]["midichan"], ccvr, ccvl, mididevice)
WScom.sendWSall("/"+midi3.findJamName(mididevice, midichannel)+"/cc/"+str(ccvr)+" "+str(ccvl))
else:
print(GetTime(),"Bad midichannel")
'''
MIDI Full CCs all 128 channels and data use ;fmnndd
m : midi channel 0-F (0-15)
nn : number 0-3J (0-127)
dd : data 0-3J (0-127)
'''
def FullCC(udpcc):
print()
midichannel = int(udpcc[1:2],36)
#midichannel = base36.index(udpcc[1:2].upper())
ccvr = int(udpcc[2:4],36)
ccvl = int(udpcc[4:6],36)
if midichannel < 16:
if gstt.debug > 0:
print(GetTime(),"ccvr=%d/ccvl=%d"%(ccvr,ccvl))
if gstt.oscname == "ocs2":
gstt.crtvalueOCS2[ccvr]=ccvl
else:
gstt.crtvalueMMO3[ccvr]=ccvl
for mididevice in midi3.findJamDevices(gstt.oscname):
midi3.cc(midichannel, ccvr, ccvl, mididevice)
WScom.sendWSall("/"+midi3.findJamName(mididevice, midichannel)+"/cc/"+str(ccvr)+" "+str(ccvl))
else:
print(GetTime(),"Bad midichannel")

169
libs/WScom.py Normal file
View File

@ -0,0 +1,169 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
WScom for jamidi v0.1b
WScom.Start(serverIP, wsPORT)
WScom.runforever()
handler : message_received(client, wserver, message)
'''
import midi3
#import socket
import types, json
import _thread, time
from websocket_server import WebsocketServer
import gstt
import UDPcom, OSCom
def Start(serverIP, wsPORT):
global wserver
wserver = WebsocketServer(wsPORT,host=serverIP)
midi3.ws = wserver
wserver.set_fn_new_client(new_client)
wserver.set_fn_client_left(client_left)
wserver.set_fn_message_received(message_received)
def runforever():
wserver.run_forever()
# Called for every WS client connecting (after handshake)
def new_client(client, wserver):
print(midi3.GetTime(),"New WS client connected and was given id %d" % client['id'])
#sendWSall("/status Hello %d" % client['id'])
if gstt.current == True:
sendallcurrentccvalues("mmo3")
sendallcurrentccvalues("ocs2")
gstt.Players+=1
sendWSall("/status Hello %d" %(client['id']))
if gstt.Players > 1:
#sendWSall("/gstt.Players %d" %(Players))
sendWSall("/players (players:%d)" %(gstt.Players))
else:
sendWSall("/players (player:%d)" %(gstt.Players))
# Called for every WS client disconnecting
def client_left(client, wserver):
try:
print(midi3.GetTime(),"WS Client(%d) disconnected" % client['id'])
gstt.Players-=1
sendWSall("/players %d" %(gstt.Players))
except:
print("Something weird if coming from",client,"on the wire...")
pass
# Called for each WS received message.
def message_received(client, wserver, message):
print("")
if len(message) > 200:
message = message[:200]+'..'
wspath = message.split(" ")
if gstt.debug > 0:
print(midi3.GetTime(),"Main got from WS", client['id'], "said :", message, "splitted in an wspath :", wspath)
else:
print(midi3.GetTime(),"Main got WS Client", client['id'], "said :", message)
wscommand = wspath[0].split("/")
# gstt.debug
if gstt.debug > 0:
print("wscommand :",wscommand)
# noarg
if len(wspath) == 1:
args[0] = "noargs"
#print "noargs command"
# CC : /device/cc/2 127
elif wscommand[2] == "cc":
ccvr=int(wscommand[3]) #cc variable
ccvl=int(wspath[1]) #cc value
if gstt.debug > 0:
print("ccvr=%d/ccvl=%d"%(ccvr,ccvl))
if wscommand[1] == "ocs2":
gstt.crtvalueOCS2[ccvr]=ccvl
else:
gstt.crtvalueMMO3[ccvr]=ccvl
for mididevice in midi3.findJamDevices(wscommand[1]):
midi3.cc(gstt.Confs[wscommand[1]][0]["midichan"], ccvr, ccvl, mididevice)
# RESET : /device/reset 1
elif wscommand[2] == "reset":
if wscommand[1] == "ocs2":
reset("ocs2")
else:
reset("mmo3")
# NOTEON : /device/noteon note velocity
elif wscommand[2] == "noteon":
for mididevice in midi3.findJamDevices(wscommand[1]):
midi3.NoteOn(int(wspath[1]), int(wspath[2]), mididevice)
#midi3.NoteOn(int(wspath[1]), int(wspath[2]), gstt.Confs[wscommand[1]][0]["mididevice"])
# NOTEOFF /device/noteoff note
elif wscommand[2] == "noteoff":
for mididevice in midi3.findJamDevices(wscommand[1]):
midi3.NoteOff(int(wspath[1]), mididevice)
#midi3.NoteOff(int(wspath[1]), gstt.Confs[wscommand[1]][0]["mididevice"])
# Loop back : WS Client -> server -> WS Client
sendWSall(message)
# Send through websocket.
# Different websocket library for client (websocket) or server (websocket_server.
# ws object is added here by main.py or client.py startup : midi3.ws =
def send(message):
if gstt.clientmode == True:
send(message)
else:
wserver.send_message_to_all(msg = message)
def sendWSall(message):
if gstt.broadcast == True:
if gstt.debug >0:
print(midi3.GetTime(),"WS sending to all %s" % (message))
wserver.send_message_to_all(message)
# /send all current cc values
def sendallcurrentccvalues(nozoid):
if gstt.broadcast == True:
#print ""
print(midi3.GetTime(),"sending all current cc values of", nozoid)
if nozoid == "mmo3":
for ccnumber in range(0,32):
sendWSall("/mmo3/cc/"+str(ccnumber)+" "+str(gstt.crtvalueMMO3[ccnumber]))
else:
for ccnumber in range(0,32):
sendWSall("/ocs2/cc/"+str(ccnumber)+" "+str(gstt.crtvalueOCS2[ccnumber]))

39
libs/gstt.py Normal file
View File

@ -0,0 +1,39 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
"""
Jamidi states
v0.2.4b
LICENCE : CC
by Sam Neurohack
from /team/laser
"""
# reset = [64,64,0,32,96] # un truc comme ca pour les valeurs de reset ?
resetMMO3 = [0] * 32
resetOCS2 = [0] * 32
# record current values
crtvalueMMO3 = [0] * 32
crtvalueOCS2 = [0] * 32
# record number of loaded pages (aka client id or players)
Players=0
oscname = ""
Confs = []
debug = 0
BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(s, b):
res = ""
while s:
res+=BS[s%b]
s//= b
return res[::-1] or "0"

View File

@ -36,6 +36,8 @@ import sys
from sys import platform from sys import platform
import os import os
import re import re
import gstt
import WScom
is_py2 = sys.version[0] == '2' is_py2 = sys.version[0] == '2'
@ -61,10 +63,8 @@ midinputsname = ["Name"] * 16
midinputsqueue = [Queue() for i in range(16) ] midinputsqueue = [Queue() for i in range(16) ]
midinputs = [] midinputs = []
debug = 0
# False = server / True = Client # False = server / True = Client
clientmode = False gstt.clientmode = False
#Mser = False #Mser = False
@ -152,6 +152,7 @@ def note2midi(note_name):
pitch = match.group('n').upper() pitch = match.group('n').upper()
offset = acc_map[match.group('off')] offset = acc_map[match.group('off')]
octave = int(match.group('oct')) octave = int(match.group('oct'))
except: except:
raise ValueError('Improper note format: {}'.format(note_name)) raise ValueError('Improper note format: {}'.format(note_name))
# Convert from the extrated ints to a full note number # Convert from the extrated ints to a full note number
@ -189,17 +190,17 @@ def midi2hz(note_number):
# in a 440 Hz tuning # in a 440 Hz tuning
return 440.0*(2.0**((note_number - 69)/12.0)) return 440.0*(2.0**((note_number - 69)/12.0))
# /cc cc number value
def cc(midichannel, ccnumber, value, mididest):
if gstt.debug>0:
print(GetTime(),"Jamidi Sending Midi channel", midichannel, "cc", ccnumber, "value", value, "to", mididest)
MidiMsg([CONTROLLER_CHANGE+midichannel-1, ccnumber, value], mididest)
# Send through websocket.
# Different websocket library for client (websocket) or server (websocket_server.
# ws object is added here by main.py or client.py startup : midi3.ws =
def wssend(message):
if clientmode == True:
ws.send(message)
else:
ws.send_message_to_all(msg = message)
# #
# MIDI Startup and handling # MIDI Startup and handling
@ -231,8 +232,18 @@ def MidinProcess(inqueue, portname):
MidiVel = msg[2] MidiVel = msg[2]
print(GetTime(),"NOTE ON :", MidiNote, 'velocity :', MidiVel, "Channel", MidiChannel) print(GetTime(),"NOTE ON :", MidiNote, 'velocity :', MidiVel, "Channel", MidiChannel)
#NoteOn(msg[1],msg[2],mididest) #NoteOn(msg[1],msg[2],mididest)
#NoteOn(msg[1],msg[2],mididest,MidiChannel-1)
#beware !!
if gstt.nothrough == False:
for mididevice in findJamDevices(gstt.oscname):
#NoteOn(msg[1],msg[2],"XXXX",MidiChannel-1)
if gstt.debug>0:
print(GetTime(),"mididevice/oscname:",mididevice,"/",gstt.oscname)
NoteOn(msg[1],msg[2],mididevice,MidiChannel-1)
print(GetTime(),"Midi in process send /"+findJamName(portname, MidiChannel)+"/noteon "+str(msg[1])+" "+str(msg[2])) print(GetTime(),"Midi in process send /"+findJamName(portname, MidiChannel)+"/noteon "+str(msg[1])+" "+str(msg[2]))
wssend("/"+findJamName(portname, MidiChannel)+"/noteon "+str(msg[1])+" "+str(msg[2])) WScom.send("/"+findJamName(portname, MidiChannel)+"/noteon "+str(msg[1])+" "+str(msg[2]))
''' '''
# Sampler mode : note <63 launch snare.wav / note > 62 kick.wav # Sampler mode : note <63 launch snare.wav / note > 62 kick.wav
@ -264,7 +275,7 @@ def MidinProcess(inqueue, portname):
print(GetTime(),"NOTE OFF :", MidiNote, 'velocity :', MidiVel, "Channel", MidiChannel) print(GetTime(),"NOTE OFF :", MidiNote, 'velocity :', MidiVel, "Channel", MidiChannel)
#NoteOff(msg[1],msg[2], mididest) #NoteOff(msg[1],msg[2], mididest)
print(GetTime(),"Midi in process send /"+findJamName(portname, MidiChannel)+"/noteoff "+str(msg[1])) print(GetTime(),"Midi in process send /"+findJamName(portname, MidiChannel)+"/noteoff "+str(msg[1]))
wssend("/"+findJamName(portname, MidiChannel)+"/noteoff "+str(msg[1])) WScom.send("/"+findJamName(portname, MidiChannel)+"/noteoff "+str(msg[1]))
# # CC on all Midi Channels # # CC on all Midi Channels
@ -274,7 +285,7 @@ def MidinProcess(inqueue, portname):
#findJamName(portname, MidiChannel) #findJamName(portname, MidiChannel)
print(GetTime(),"channel", MidiChannel, " ",findJamName(portname, MidiChannel), " CC :", msg[1], msg[2]) print(GetTime(),"channel", MidiChannel, " ",findJamName(portname, MidiChannel), " CC :", msg[1], msg[2])
print(GetTime(),"Midi in process send /"+findJamName(portname, MidiChannel)+"/cc/"+str(msg[1])+" "+str(msg[2])+" to WS") print(GetTime(),"Midi in process send /"+findJamName(portname, MidiChannel)+"/cc/"+str(msg[1])+" "+str(msg[2])+" to WS")
wssend("/"+findJamName(portname, MidiChannel)+"/cc/"+str(msg[1])+" "+str(msg[2])) WScom.send("/"+findJamName(portname, MidiChannel)+"/cc/"+str(msg[1])+" "+str(msg[2]))
''' '''
@ -282,7 +293,7 @@ def MidinProcess(inqueue, portname):
if CONTROLLER_CHANGE -1 < msg[0] < 192: if CONTROLLER_CHANGE -1 < msg[0] < 192:
print("channel 1 (MMO-3) CC :", msg[1], msg[2]) print("channel 1 (MMO-3) CC :", msg[1], msg[2])
print("Midi in process send /mmo3/cc/"+str(msg[1])+" "+str(msg[2])+" to WS") print("Midi in process send /mmo3/cc/"+str(msg[1])+" "+str(msg[2])+" to WS")
wssend("/mmo3/cc/"+str(msg[1])+" "+str(msg[2])) WScom.send("/mmo3/cc/"+str(msg[1])+" "+str(msg[2]))
# OCS-2 Midi CC message CHANNEL 2 # OCS-2 Midi CC message CHANNEL 2
@ -290,7 +301,7 @@ def MidinProcess(inqueue, portname):
print("channel 2 (OCS-2) CC :", msg[1], msg[2]) print("channel 2 (OCS-2) CC :", msg[1], msg[2])
print("Midi in process send /ocs2/cc/"+str(msg[1])+" "+str(msg[2])+" to WS") print("Midi in process send /ocs2/cc/"+str(msg[1])+" "+str(msg[2])+" to WS")
wssend("/ocs2/cc/"+str(msg[1])+" "+str(msg[2])) WScom.send("/ocs2/cc/"+str(msg[1])+" "+str(msg[2]))
''' '''
@ -303,19 +314,24 @@ def MidinProcess(inqueue, portname):
''' '''
def NoteOn(note,color, mididest): #def NoteOn(note, color, mididest):
#https://pypi.org/project/python-rtmidi/0.3a/
#à NOTE_ON=#90 et NOTE_OFF=#80 on ajoute le channel (0 le premier) pour envoyer effectivement sur le channel
def NoteOn(note, color, mididest, midichannel=0):
global MidInsNumber global MidInsNumber
if gstt.debug >0:
print(GetTime(),"Sending", note, color, "to", mididest, "on channel", midichannel)
for port in range(MidInsNumber): for port in range(MidInsNumber):
# To mididest # To mididest
if midiname[port].find(mididest) == 0: if midiname[port].find(mididest) == 0:
midiport[port].send_message([NOTE_ON, note, color]) midiport[port].send_message([NOTE_ON+midichannel, note, color])
# To All # To All
elif mididest == "all" and midiname[port].find(mididest) != 0: elif mididest == "all" and midiname[port].find(mididest) != 0:
midiport[port].send_message([NOTE_ON, note, color]) midiport[port].send_message([NOTE_ON+midichannel, note, color])
@ -491,8 +507,8 @@ def InConfig():
print(GetTime(),"MIDIin...") print(GetTime(),"MIDIin...")
# client mode # client mode
if debug > 0: if gstt.debug > 0:
if clientmode == True: if gstt.clientmode == True:
print(GetTime(),"midi3 in client mode") print(GetTime(),"midi3 in client mode")
else: else:
print(GetTime(),"midi3 in server mode") print(GetTime(),"midi3 in server mode")
@ -603,8 +619,8 @@ def MidiMsg(midimsg, mididest):
for port in range(len(OutDevice)): for port in range(len(OutDevice)):
# To mididest # To mididest
if midiname[port].find(mididest) != -1: if midiname[port].find(mididest) != -1:
if debug>0: if gstt.debug>0:
print(GetTime(),"jamidi 3 sending to name", midiname[port], "port", port, ":", midimsg) print(GetTime(),"jamidi3 sending to name", midiname[port], "port", port, ":", midimsg)
midiport[port].send_message(midimsg) midiport[port].send_message(midimsg)
desterror = 0 desterror = 0
@ -612,11 +628,11 @@ def MidiMsg(midimsg, mididest):
print(GetTime(),"mididest",mididest, ": ** This midi destination doesn't exists **") print(GetTime(),"mididest",mididest, ": ** This midi destination doesn't exists **")
# send midi msg over ws. # send midi msg over ws.
#if clientmode == True: #if gstt.clientmode == True:
# ws.send("/ocs2/cc/1 2") # ws.send("/ocs2/cc/1 2")
'''
def NoteOn(note, velocity, mididest): def NoteOn(note, velocity, mididest):
global MidInsNumber global MidInsNumber
@ -626,7 +642,7 @@ def NoteOn(note, velocity, mididest):
# To mididest # To mididest
if midiname[port].find(mididest) == 0: if midiname[port].find(mididest) == 0:
midiport[port].send_message([NOTE_ON, note, velocity]) midiport[port].send_message([NOTE_ON, note, velocity])
'''
def listdevice(number): def listdevice(number):
@ -638,17 +654,20 @@ def listdevice(number):
# return device name for given mididevice and midichannel # return device name for given mididevice and midichannel
def findJamName(mididevice, midichan): def findJamName(mididevice, midichan):
#print("searching", mididevice, "channel", midichan,'...')
for (k, v) in Confs.items(): if gstt.debug >0:
print(GetTime(),"Findjamname searching", mididevice, "channel", midichan,'...')
for (k, v) in gstt.Confs.items():
#print("Key: " + k) #print("Key: " + k)
#print("Value: " + str(v)) #print("Value: " + str(v))
if v[0]["type"] == "mididevice": if v[0]["type"] == "mididevice":
#print(v[0]["mididevice"],v[0]["midichan"], type(v[0]["midichan"])) #print(k, v[0]["mididevice"],v[0]["midichan"],type(v[0]["midichan"]),v[0]["xname"], "?")
if (v[0]["mididevice"] == mididevice) and (v[0]["midichan"] == midichan): if (v[0]["mididevice"] == mididevice) and (v[0]["midichan"] == midichan):
print(GetTime(),"Incoming event from", k, "xname", v[0]["xname"]) print(GetTime(),"Incoming event from", k, "xname", v[0]["xname"])
return v[0]["xname"] return v[0]["xname"]
return "None" return "None"
@ -656,15 +675,17 @@ def findJamName(mididevice, midichan):
def findJamDevices(name): def findJamDevices(name):
devices = [] devices = []
print (GetTime(),"searching", name) if gstt.debug >0:
for (k, v) in Confs.items(): print (GetTime(),"Findjamdevice searching", name)
for (k, v) in gstt.Confs.items():
if v[0]["type"] == "mididevice": if v[0]["type"] == "mididevice":
#print(k, name,v[0]["xname"]) #print(k, name,v[0]["xname"])
if v[0]["xname"] == name: if v[0]["xname"] == name:
#print(v[0]["mididevice"]) #print(v[0]["mididevice"])
devices.append(v[0]["mididevice"]) devices.append(v[0]["mididevice"])
# print(devices) if gstt.debug>0:
print(GetTime(),devices)
return devices return devices

353
main.py
View File

@ -14,6 +14,21 @@ wserver.run_forever()
wserver.send_message_to_all(message) wserver.send_message_to_all(message)
ORCA:
CTRL K pour rentrer une commande
CTRL K ip:127.0.0.1
CTRL K osc:8082
CTRL K cc:0
CTRL K udp:udport
/p
Pitch bend
''' '''
@ -33,28 +48,36 @@ from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON,
sys.path.append('libs/') sys.path.append('libs/')
import midi3 import midi3
from websocket_server import WebsocketServer
#import socket #import socket
import types, json import types, json
import argparse import argparse
import _thread, time
debug = 1 from midi3 import note2midi
from midi3 import GetTime
import OSCom
import WScom
import UDPcom
import gstt
print ("") print ("")
print ("Arguments parsing if needed...") print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="Jamidi Server v0.1b commands help mode") argsparser = argparse.ArgumentParser(description="Jamidi Server v0.1b commands help mode")
argsparser.add_argument("-s","--servername",help="Servername: 'local', 'llstrvpn' (local by default)", type=str) argsparser.add_argument("-s","--servername",help="Servername: 'local', 'llstrvpn' (local by default)", type=str)
argsparser.add_argument('--current',help="Send all current CC values to all new client. Default option" , dest='current', action='store_true') argsparser.add_argument("-d","--device",help="midi device for incoming ORCA via UDP (mmo3 by default)", type=str)
argsparser.add_argument('--no-current',help="Do not send all current CC values to all new client. ", dest='current', action='store_false') argsparser.add_argument('-nothrough',help="Disable the builtin midithrough from any midi IN to --device enabled by default", dest='nothrough', action='store_true')
argsparser.add_argument('--broadcast',help="Broadcast all incomings commands to all client. Default option" , dest='broadcast', action='store_true') argsparser.set_defaults(nothrough=False)
argsparser.add_argument('--no-broadcast',help="Do not broadcast all incomings commands to all client", dest='broadcast', action='store_false') argsparser.add_argument('-nocurrent',help="Do not send all current CC values to all new client (enabled by default)", dest='current', action='store_false')
argsparser.add_argument('--reset',help="Send reset values to local device a startup. Default option" , dest='reset', action='store_true')
argsparser.add_argument('--no-reset',help="Do not send reset values to local device a startup.", dest='reset', action='store_false')
argsparser.set_defaults(reset=True)
argsparser.set_defaults(current=True) argsparser.set_defaults(current=True)
argsparser.add_argument('-nobroadcast',help="Do not broadcast all incomings commands to all client (enabled by default)", dest='broadcast', action='store_false')
argsparser.set_defaults(broadcast=True) argsparser.set_defaults(broadcast=True)
argsparser.add_argument('-noreset',help="Do not broadcast all incomings commands to all client (enabled by default)", dest='reset', action='store_false')
argsparser.set_defaults(reset=True)
argsparser.add_argument('-verbose',help="Enable debug mode (disabled by default)", dest='verbose', action='store_true')
argsparser.set_defaults(verbose=False)
args = argsparser.parse_args() args = argsparser.parse_args()
@ -64,41 +87,95 @@ if args.servername:
else: else:
servername = "local" servername = "local"
# ORCA destination device
if args.device:
gstt.oscname = args.device
else:
gstt.oscname = "mmo3"
# Broadcast commands to all clients ? # Broadcast commands to all clients ?
if args.broadcast == False: if args.broadcast == False:
print("Broadcast disabled") print("Broadcast disabled")
broadcast = False gstt.broadcast = False
else: else:
print("Broadcast enabled") print("Broadcast enabled")
broadcast = True gstt.broadcast = True
# Send current values to all new client ? # Send current values to all new client ?
if args.current == False: if args.current == False:
print("Do not send current values at startup disabled") print("Do not send current values at startup disabled")
current = False gstt.current = False
else: else:
print("Current values update at startup disabled") print("Current values update at startup disabled")
current = True gstt.current = True
# Reset at startup ? # Reset at startup ?
if args.reset == False: if args.reset == False:
print("Reset at startup disabled") print("Reset at startup disabled")
startreset = False gstt.startreset = False
else: else:
print("Reset at startup enabled") print("Reset at startup enabled")
startreset = True gstt.startreset = True
# Debug/verbose mode ?
if args.verbose == False:
print("Debug mode disabled")
gstt.debug = 0
else:
print("Debug mode enabled")
gstt.debug = 1
# nomidithrough mode ?
if args.nothrough == False:
print("Midi through mode")
gstt.nothrough = False
else:
print("No midi through mode")
gstt.nothrough = True
# reset = [64,64,0,32,96] # un truc comme ca pour les valeurs de reset ? #base36 = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
resetMMO3 = [0] * 32
resetOCS2 = [0] * 32
# record current values '''
crtvalueMMO3 = [0] * 32 base36 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z}
crtvalueOCS2 = [0] * 32
transpose =
"0": None, "1": None, "2": None, "3":, None, "4":, None, "5":, "6":, "7":, "8":, "9":, "A": "A0", "B": B0,
C ,"C0", D : "D0", "E": "E0" F G H I J K L M N
"C0" "D0" "E0" "F0" "G0" "A0" "B0" "C1" "D1" "E1" "F1" "G1"
O P Q R S T U V W X Y Z
"A1" "B1" "C2" "D2" "E2" "F2" "G2" "A2" "B2" "C3" "D3" "E3"
'''
#
# Settings from jamidi.json
#
# Load midi definitions in jamidi.json
def LoadConfs():
if os.path.exists('jamidi.json'):
f=open("jamidi.json","r")
s = f.read()
gstt.Confs = json.loads(s)
#print(GetTime(),gstt.Confs)
# return midi confname number for given type
def findConfs(confname,conftype):
#print("searching", midiconfname,'...')
position = -1
for counter in range(len(gstt.Confs[conftype])):
if confname == gstt.Confs[conftype][counter]['name']:
#print(confname, "is ", counter)
position = counter
return position
LoadConfs()
# record number of loaded pages (aka client id or players)
Players=0
# #
@ -117,8 +194,8 @@ def GetTime():
# /cc cc number value # /cc cc number value
def cc(midichannel, ccnumber, value, mididest): def cc(midichannel, ccnumber, value, mididest):
if debug>0: if gstt.debug>0:
print("Jamidi Sending Midi channel", midichannel, "cc", ccnumber, "value", value, "to", mididest) print(GetTime(),"Jamidi Sending Midi channel", midichannel, "cc", ccnumber, "value", value, "to", mididest)
midi3.MidiMsg([CONTROLLER_CHANGE+midichannel-1, ccnumber, value], mididest) midi3.MidiMsg([CONTROLLER_CHANGE+midichannel-1, ccnumber, value], mididest)
@ -131,173 +208,17 @@ def reset(nozoid):
if nozoid == "mmo3": if nozoid == "mmo3":
for ccnumber in range(0,32): for ccnumber in range(0,32):
midi3.MidiMsg([CONTROLLER_CHANGE+Confs["mmo3"][0]["midichan"]-1, ccnumber, resetMMO3[ccnumber]], Confs["mmo3"][0]["mididevice"]) midi3.MidiMsg([CONTROLLER_CHANGE+gstt.Confs["mmo3"][0]["midichan"]-1, ccnumber, gstt.resetMMO3[ccnumber]], gstt.Confs["mmo3"][0]["mididevice"])
sendWSall("/mmo3/cc/"+str(ccnumber)+" "+str(resetMMO3[ccnumber])) WScom.sendWSall("/mmo3/cc/"+str(ccnumber)+" "+str(gstt.resetMMO3[ccnumber]))
crtvalueMMO3[ccnumber]=resetMMO3[ccnumber] gstt.crtvalueMMO3[ccnumber]=gstt.resetMMO3[ccnumber]
else: else:
for ccnumber in range(0,32): for ccnumber in range(0,32):
midi3.MidiMsg([CONTROLLER_CHANGE+Confs["ocs2"][0]["midichan"]-1, ccnumber, resetOCS2[ccnumber]], Confs["ocs2"][0]["mididevice"]) midi3.MidiMsg([CONTROLLER_CHANGE+gstt.Confs["ocs2"][0]["midichan"]-1, ccnumber, gstt.resetOCS2[ccnumber]], gstt.Confs["ocs2"][0]["mididevice"])
sendWSall("/ocs2/cc/"+str(ccnumber)+" "+str(resetOCS2[ccnumber])) WScom.sendWSall("/ocs2/cc/"+str(ccnumber)+" "+str(gstt.resetOCS2[ccnumber]))
crtvalueOCS2[ccnumber]=resetOCS2[ccnumber] gstt.crtvalueOCS2[ccnumber]=gstt.resetOCS2[ccnumber]
print("End of reset for", nozoid) print(GetTime(),"End of reset for", nozoid)
print("") print("")
# /send all current cc values
def sendallcurrentccvalues(nozoid):
if broadcast == True:
#print ""
print(GetTime(),"sending all current cc values of", nozoid)
if nozoid == "mmo3":
for ccnumber in range(0,32):
sendWSall("/mmo3/cc/"+str(ccnumber)+" "+str(crtvalueMMO3[ccnumber]))
else:
for ccnumber in range(0,32):
sendWSall("/ocs2/cc/"+str(ccnumber)+" "+str(crtvalueOCS2[ccnumber]))
#
# Settings from jamidi.json
#
# Load midi definitions in jamidi.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
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
#
# Websocket part
#
# Called for every WS client connecting (after handshake)
def new_client(client, wserver):
global Players
print(GetTime(),"New WS client connected and was given id %d" % client['id'])
#sendWSall("/status Hello %d" % client['id'])
if current == True:
sendallcurrentccvalues("mmo3")
sendallcurrentccvalues("ocs2")
Players+=1
sendWSall("/status Hello %d" %(client['id']))
if Players > 1:
#sendWSall("/players %d" %(Players))
sendWSall("/players (players:%d)" %(Players))
else:
sendWSall("/players (player:%d)" %(Players))
# Called for every WS client disconnecting
def client_left(client, wserver):
global Players
try:
print(GetTime(),"WS Client(%d) disconnected" % client['id'])
Players-=1
sendWSall("/players %d" %(Players))
except:
print("Something weird if coming from",client,"on the wire...")
pass
# Called for each WS received message.
def message_received(client, wserver, message):
print("")
if len(message) > 200:
message = message[:200]+'..'
oscpath = message.split(" ")
if debug > 0:
print(GetTime(),"Main got from WS", client['id'], "said :", message, "splitted in an oscpath :", oscpath)
else:
print(GetTime(),"Main got WS Client", client['id'], "said :", message)
wscommand = oscpath[0].split("/")
# debug
if debug > 0:
print("wscommand :",wscommand)
# noarg
if len(oscpath) == 1:
args[0] = "noargs"
#print "noargs command"
# CC : /device/cc/2 127
elif wscommand[2] == "cc":
ccvr=int(wscommand[3]) #cc variable
ccvl=int(oscpath[1]) #cc value
if debug > 0:
print("ccvr=%d/ccvl=%d"%(ccvr,ccvl))
if wscommand[1] == "ocs2":
#cc(Confs[wscommand[1]][0]["midichan"], ccvr, ccvl, Confs[wscommand[1]][0]["mididevice"])
crtvalueOCS2[ccvr]=ccvl
else:
#cc(Confs[wscommand[1]][0]["midichan"], ccvr, ccvl, Confs[wscommand[1]][0]["mididevice"])
crtvalueMMO3[ccvr]=ccvl
for mididevice in midi3.findJamDevices(wscommand[1]):
cc(Confs[wscommand[1]][0]["midichan"], ccvr, ccvl, mididevice)
# RESET : /device/reset 1
elif wscommand[2] == "reset":
if wscommand[1] == "ocs2":
reset("ocs2")
else:
reset("mmo3")
# NOTEON : /device/noteon note velocity
elif wscommand[2] == "noteon":
for mididevice in midi3.findJamDevices(wscommand[1]):
midi3.NoteOn(int(oscpath[1]), int(oscpath[2]), mididevice)
#midi3.NoteOn(int(oscpath[1]), int(oscpath[2]), Confs[wscommand[1]][0]["mididevice"])
# NOTEOFF /device/noteoff note
elif wscommand[2] == "noteoff":
for mididevice in midi3.findJamDevices(wscommand[1]):
midi3.NoteOff(int(oscpath[1]), mididevice)
#midi3.NoteOff(int(oscpath[1]), Confs[wscommand[1]][0]["mididevice"])
# Loop back : WS Client -> server -> WS Client
sendWSall(message)
def sendWSall(message):
if broadcast == True:
if debug >0:
print(GetTime(),"sending to all %s" % (message))
wserver.send_message_to_all(message)
@ -305,45 +226,43 @@ def sendWSall(message):
# Running... # Running...
# #
LoadConfs()
serverIP = Confs[servername][0]["IP"] serverIP = gstt.Confs[servername][0]["IP"]
wsPORT = Confs[servername][0]["port"] wsPORT = gstt.Confs[servername][0]["port"]
print(Confs["ocs2"][0]["mididevice"]) OSCPORT = gstt.Confs[servername][0]["oscport"]
UDPORT = gstt.Confs[servername][0]["udport"]
print("Running....") print()
print(GetTime(),"Launching servers...")
print(GetTime(),"Launching OSC Server", serverIP,':', OSCPORT)
OSCom.Start(serverIP, OSCPORT)
print(GetTime(),"Launching WS Server", serverIP,':', wsPORT)
UDPcom.Start(serverIP, UDPORT)
print(GetTime(),"Launching UDP Server", serverIP,':', UDPORT)
WScom.Start(serverIP, wsPORT)
if gstt.startreset == True:
print(GetTime(),"resetting nozoids...")
reset("mmo3")
reset("ocs2")
# Main
# Main loop do nothing. Maybe do the webui server ?
try: try:
#while True:
# Websocket startup
wserver = WebsocketServer(wsPORT,host=serverIP)
midi3.ws = wserver
midi3.Confs = Confs
#midi3.findJamDevices("ocs2")
print("") print(GetTime(),"Jamidi running forever...")
print(GetTime(),"Launching Jamidi Websocket server...")
print(GetTime(),"at", serverIP, "port",wsPORT)
wserver.set_fn_new_client(new_client)
wserver.set_fn_client_left(client_left)
wserver.set_fn_message_received(message_received)
if startreset == True: WScom.runforever()
print("resetting nozoids...")
reset("mmo3")
reset("ocs2")
#print ""
print(GetTime(),"WS server running forever...")
wserver.run_forever()
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
finally:
OSCom.Stop()
# Gently stop on CTRL C # Gently stop on CTRL C