Added UDP connector for ORCA Livecoding !!
This commit is contained in:
		
							parent
							
								
									012bef55b1
								
							
						
					
					
						commit
						b79a3487eb
					
				
							
								
								
									
										71
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								README.md
									
									
									
									
									
								
							| @ -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 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										68
									
								
								jamidi.json
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								jamidi.json
									
									
									
									
									
								
							| @ -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
									
								
							
							
						
						
									
										207
									
								
								libs/OSCom.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										175
									
								
								libs/UDPcom.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										169
									
								
								libs/WScom.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										39
									
								
								libs/gstt.py
									
									
									
									
									
										Normal 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" | ||||||
| @ -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
									
									
									
									
									
								
							
							
						
						
									
										353
									
								
								main.py
									
									
									
									
									
								
							| @ -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 |     print(GetTime(),"Jamidi running forever...") | ||||||
|     wserver = WebsocketServer(wsPORT,host=serverIP) |  | ||||||
|     midi3.ws = wserver |  | ||||||
|     midi3.Confs = Confs |  | ||||||
|     #midi3.findJamDevices("ocs2") |  | ||||||
| 
 | 
 | ||||||
|     print("") |     WScom.runforever() | ||||||
|     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: |  | ||||||
|         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 | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user