diff --git a/client.py b/client.py index 7e485e8..9ac7dfe 100644 --- a/client.py +++ b/client.py @@ -26,10 +26,7 @@ import json from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON, NOTE_OFF, PITCH_BEND, POLY_PRESSURE, PROGRAM_CHANGE) import midi3 - -# from websocket_server import WebsocketServer -#import socket -import types, time +import types import websocket @@ -68,6 +65,8 @@ else: print("Default device enabled") defaultdevice = True + + # # Midi part # @@ -75,10 +74,6 @@ else: # default local MIDI device nozmidi = "BCR2000 Port 1" -# nozmidi = "Arturia BeatStep" -# nozmidi = "Virtual Midi A" -# nozmidi = "Virtual Sequencer" -# nowmidi = "IAC Driver Sequencer Bus 1" # nozmidi = "UM-ONE:UM-ONE MIDI 1 20:0" midichanOCS2 = 2 @@ -97,7 +92,7 @@ def GetTime(): # -# Settings from clientruler.json +# Settings from rules.json # # Load midi routing definitions in clientruler.json @@ -111,8 +106,6 @@ def LoadMidiRules(): MidiRules = json.loads(s) - - # return midi rulename number for given type 'Specials', 'cc2cc' def findMidiRules(rulename,ruletype): @@ -124,6 +117,8 @@ def findMidiRules(rulename,ruletype): position = counter return position + + # # Settings from jamidi.json # @@ -139,7 +134,6 @@ def LoadConfs(): Confs = json.loads(s) - # return midi confname number for given type 'Specials', 'cc2cc' def findConfs(confname,conftype): @@ -233,6 +227,9 @@ def reset(nozoid): crtvalueOCS2[ccnumber]=resetOCS2[ccnumber] print("End of reset for", nozoid) print("") + + + # # Websocket part # @@ -264,8 +261,10 @@ def on_open(ws): _thread.start_new_thread(run, ()) + def on_message(ws, message): - # + + print("") print(message) if len(message) > 200: @@ -274,15 +273,20 @@ 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("clientruler got from WS :", message, "splitted in an oscpath :", oscpath) + print("client got from WS :", message, "splitted in an oscpath :", oscpath) wscommand = oscpath[0].split("/") - print("WS command was :",wscommand) + # 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[1] == "ocs2": if wscommand[2] == "cc": print("Incoming OCS-2 WS CC", wscommand[3], ":", int(oscpath[1])) @@ -301,17 +305,33 @@ def on_message(ws, message): print("Incoming MMO-3 WS OSC1", wscommand[3], ":", int(oscpath[1])) + # 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": + midi3.NoteOn(int(oscpath[1]), int(oscpath[2]), Confs[wscommand[1]][0]["mididevice"]) + + + # NOTEOFF /device/noteoff note + elif wscommand[2] == "noteoff": + midi3.NoteOff(int(oscpath[1]), Confs[wscommand[1]][0]["mididevice"]) + + # if needed a loop back : WS Client -> server -> WS Client # sendWSall(message) + +# +# Running... +# + LoadMidiRules() LoadConfs() @@ -335,10 +355,9 @@ try: on_close = on_close) midi3.ws = ws - midi3.wsmode = True + midi3.clientmode = True print("Midi Configuration...") - midi3.check() ws.on_open = on_open diff --git a/main.py b/main.py index 25150ab..223f83e 100644 --- a/main.py +++ b/main.py @@ -11,8 +11,6 @@ print("") print("Jamidi Server") print("v0.1b") -#from multiprocessing import Process, Queue, TimeoutError -#import subprocess import sys import traceback import os @@ -24,7 +22,7 @@ import midi3 from websocket_server import WebsocketServer #import socket -import types, time, json +import types, json import argparse debug = 1 @@ -85,7 +83,6 @@ Players=0 # Midi part # - print("Midi Configuration...") # print("Midi Destination", nozmidi) @@ -95,7 +92,6 @@ def GetTime(): return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime()) - # /cc cc number value def cc(midichannel, ccnumber, value, mididest): @@ -137,6 +133,7 @@ def sendallcurrentccvalues(nozoid): else: for ccnumber in range(0,32): sendWSall("/ocs2/cc/"+str(ccnumber)+" "+str(crtvalueOCS2[ccnumber])) + # # Settings from jamidi.json # @@ -212,16 +209,22 @@ def message_received(client, wserver, message): else: print(GetTime(),"Main got WS Client", client['id'], "said :", message) + # wscommand will be like ['', 'ocs2', 'cc', '9'] wscommand = oscpath[0].split("/") + + + # debug if debug > 0: print("wscommand :",wscommand) + # noarg if len(oscpath) == 1: args[0] = "noargs" #print "noargs command" - # like /ocs2/cc/2 127 + + # CC : /device/cc/2 127 elif wscommand[2] == "cc": ccvr=int(wscommand[3]) #cc variable ccvl=int(oscpath[1]) #cc value @@ -236,22 +239,31 @@ def message_received(client, wserver, message): cc(Confs[wscommand[1]][0]["midichan"], ccvr, ccvl, Confs[wscommand[1]][0]["mididevice"]) - # like /ocs2/reset 1 + + # RESET : /device/reset 1 elif wscommand[2] == "reset": if wscommand[1] == "ocs2": reset("ocs2") else: reset("mmo3") - #print "" + + # NOTEON : /device/noteon note velocity + elif wscommand[2] == "noteon": + midi3.NoteOn(int(oscpath[1]), int(oscpath[2]), Confs[wscommand[1]][0]["mididevice"]) + + + # NOTEOFF /device/noteoff note + elif wscommand[2] == "noteoff": + midi3.NoteOff(int(oscpath[1]), Confs[wscommand[1]][0]["mididevice"]) + + + + ws.send("/noteon "+str(msg[1])+" "+str(msg[2])) - # if needed a loop back : WS Client -> server -> WS Client + # Loop back : WS Client -> server -> WS Client sendWSall(message) -''' -def handle_timeout(self): - self.timed_out = True -''' def sendWSall(message): @@ -262,6 +274,11 @@ def sendWSall(message): wserver.send_message_to_all(message) + +# +# Running... +# + LoadConfs() serverIP = Confs[servername][0]["IP"] @@ -275,6 +292,7 @@ try: # Websocket startup wserver = WebsocketServer(wsPORT,host=serverIP) + midi3.ws = wserver #print wserver print("") diff --git a/midi3.py b/midi3.py index 7fc77f0..008c428 100644 --- a/midi3.py +++ b/midi3.py @@ -60,7 +60,7 @@ midinputs = [] debug = 0 # False = server / True = Client -wsmode = False +clientmode = False #Mser = False @@ -110,6 +110,15 @@ def midi2note(midinote): print("midinote",midinote, "note", notes[midinote%12]+str(round(midinote/12))) return notes[midinote%12]+str(round(midinote/12)) +# 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 @@ -139,8 +148,11 @@ def MidinProcess(inqueue, portname): MidiNote = msg[1] MidiVel = msg[2] print("NOTE ON :", MidiNote, 'velocity :', MidiVel, "Channel", MidiChannel) - - + #NoteOn(msg[1],msg[2],mididest) + wssend("/noteon "+str(msg[1])+" "+str(msg[2])) + + ''' + # Sampler mode : note <63 launch snare.wav / note > 62 kick.wav if MidiNote < 63 and MidiVel >0: if platform == 'darwin': @@ -155,36 +167,93 @@ def MidinProcess(inqueue, portname): os.system("afplay kick.wav") else: os.system("aplay kick.wav") - - + ''' # Note Off if msg[0]==NOTE_OFF: print("NOTE OFF :", MidiNote, 'velocity :', MidiVel, "Channel", MidiChannel) + #NoteOff(msg[1],msg[2], mididest) + wssend("/noteoff "+str(msg[1])) # MMO-3 Midi CC message CHANNEL 1 if msg[0] == CONTROLLER_CHANGE: 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") - if wsmode == True: - ws.send("/mmo3/cc/"+str(msg[1])+" "+str(msg[2])) + wssend("/mmo3/cc/"+str(msg[1])+" "+str(msg[2])) + # OCS-2 Midi CC message CHANNEL 2 if msg[0] == CONTROLLER_CHANGE+1: 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") - if wsmode == True: - ws.send("/ocs2/cc/"+str(msg[1])+" "+str(msg[2])) + wssend("/ocs2/cc/"+str(msg[1])+" "+str(msg[2])) + # other midi message if msg[0] != NOTE_OFF and msg[0] != NOTE_ON and msg[0] != CONTROLLER_CHANGE: pass + ''' + print("from", portname,"other midi message") + MidiMsg(msg[0],msg[1],msg[2],mididest) + ''' +def NoteOn(note,color, mididest): + global MidInsNumber + + + for port in range(MidInsNumber): + + # To mididest + if midiname[port].find(mididest) == 0: + midiport[port].send_message([NOTE_ON, note, color]) + + # To All + elif mididest == "all" and midiname[port].find(mididest) != 0 and midiname[port].find(BhorealMidiName) != 0 and midiname[port].find(LaunchMidiName) != 0: + midiport[port].send_message([NOTE_ON, note, color]) + + ''' + # To Launchpad, if present. + elif mididest == "launchpad" and midiname[port].find(LaunchMidiName) == 0: + launchpad.PadNoteOn(note%64,color) + + # To Bhoreal, if present. + elif mididest == "bhoreal" and midiname[port].find(BhorealMidiName) == 0: + gstt.BhorLeds[note%64]=color + midiport[port].send_message([NOTE_ON, note%64, color]) + #bhorosc.sendosc("/bhoreal", [note%64 , 0]) + ''' + + +def NoteOff(note, mididest): + global MidInsNumber + + + for port in range(MidInsNumber): + + # To mididest + if midiname[port].find(mididest) != -1: + midiport[port].send_message([NOTE_OFF, note, 0]) + + # To All + elif mididest == "all" and midiname[port].find(mididest) == -1 and midiname[port].find(BhorealMidiName) == -1 and midiname[port].find(LaunchMidiName) == -1: + midiport[port].send_message([NOTE_OFF, note, 0]) + + ''' + # To Launchpad, if present. + elif mididest == "launchpad" and midiname[port].find(LaunchMidiName) == 0: + launchpad.PadNoteOff(note%64) + + # To Bhoreal, if present. + elif mididest == "bhoreal" and midiname[port].find(BhorealMidiName) == 0: + midiport[port].send_message([NOTE_OFF, note%64, 0]) + gstt.BhorLeds[note%64] = 0 + #bhorosc.sendosc("/bhoreal", [note%64 , 0]) + ''' + # Generic call back : new msg forwarded to queue @@ -340,9 +409,14 @@ def InConfig(): print("") print("MIDIin...") + # client mode - if wsmode == True: - print("ws object", ws) + if debug > 0: + if clientmode == True: + print("midi3 in client mode") + else: + print("midi3 in server mode") + print("List and attach to available devices on host with OUT port :") if platform == 'darwin': @@ -458,7 +532,7 @@ def MidiMsg(midimsg, mididest): print("mididest",mididest, ": ** This midi destination doesn't exists **") # send midi msg over ws. - #if wsmode == True: + #if clientmode == True: # ws.send("/ocs2/cc/1 2") diff --git a/nozWS.py b/nozWS.py index 132cac2..05f0b10 100755 --- a/nozWS.py +++ b/nozWS.py @@ -151,7 +151,7 @@ def on_open(ws): _thread.start_new_thread(run, ()) def on_message(ws, message): - # + print("") print(message) if len(message) > 200: @@ -167,8 +167,8 @@ def on_message(ws, message): if len(oscpath) == 1: args[0] = "noargs" - #print "noargs command" + # CC : /device/cc/2 127 elif wscommand[2] == "cc": if wscommand[1] == "ocs2": print("Incoming OCS-2 WS") @@ -177,7 +177,7 @@ def on_message(ws, message): print("Incoming MMO-3 WS") cc(midichanMMO3, int(wscommand[3]), int(oscpath[1]), nozmidi) - + # RESET : /device/reset 1 elif wscommand[2] == "reset": if wscommand[1] == "ocs2": reset("ocs2")