Skip to content

Commit

Permalink
Added websocket server note output for visualizer
Browse files Browse the repository at this point in the history
  • Loading branch information
euwbah committed Aug 8, 2021
1 parent cfe2411 commit bc28067
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 5 deletions.
17 changes: 13 additions & 4 deletions handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rtmidi import MidiIn, MidiOut

import convert
import ws_server
from keytracker import KeyTracker, ChannelWrapper
from configs import SlideMode, CONFIGS

Expand All @@ -28,6 +29,9 @@ def __call__(self, event, data=None):
msg_type, channel = EVENT_MASK & message[0], CHANNEL_MASK & message[0]

def tune_and_send_note(note, vel, cc74):

edosteps_from_a4 = mapping.calc_notes_from_a4(note, cc74)

if CONFIGS.MPE_MODE:
pitchbend = mapping.calc_pitchbend(note, cc74)
# pitch bend has to go before the note on event
Expand All @@ -37,14 +41,14 @@ def tune_and_send_note(note, vel, cc74):

if CONFIGS.SLIDE_MODE == SlideMode.FIXED:
self.send_cc(channel, 74, CONFIGS.SLIDE_FIXED_N)
tracker.register_on(note, vel, channel, note, channel, pitchbend)
tracker.register_on(note, vel, channel, note, channel, edosteps_from_a4, pitchbend)

# pitch bend has to go after note on event
# otherwise strobe 2 complete disregards it
self.send_pitch_bend(channel, pitchbend)
else:
send_ch, send_note_offset = CONFIGS.SPLITS.get_split_range(note)
send_note = mapping.calc_notes_from_a4(note, cc74) + MIDI_NOTE_A4 + send_note_offset
send_note = edosteps_from_a4 + MIDI_NOTE_A4 + send_note_offset

if 0 > send_note > 127:
send_note = max(0, min(127, send_note))
Expand All @@ -56,14 +60,17 @@ def tune_and_send_note(note, vel, cc74):
# stop that note. Prevents ghosts that hang around.
if existing := tracker.check_existing(channel):
self.send_note_off(existing.channel_sent, existing.midi_note_sent, 0)
ws_server.send_note_off(existing.edosteps_from_a4, 0)

def do_later():
time.sleep(0.001)
if CONFIGS.SLIDE_MODE == SlideMode.FIXED:
self.send_cc(channel, 74, CONFIGS.SLIDE_FIXED_N)

threading.Thread(target=do_later).start()
tracker.register_on(note, vel, channel, send_note, send_ch)
tracker.register_on(note, vel, channel, send_note, send_ch, edosteps_from_a4)

ws_server.send_note_on(edosteps_from_a4, vel)

if msg_type == midi.NOTE_ON:
note, vel = message[1:3]
Expand Down Expand Up @@ -130,7 +137,9 @@ def send_preempt_defaults():
send_preempt_defaults()

elif cc == midi.SUSTAIN: # CC 64
self.send_cc(c, cc, value if not CONFIGS.TOGGLE_SUSTAIN else 127 - value)
sustain_value = value if not CONFIGS.TOGGLE_SUSTAIN else 127 - value
self.send_cc(c, cc, sustain_value)
ws_server.send_cc(cc, sustain_value)
else:
self.send_cc(c, cc, value)

Expand Down
8 changes: 7 additions & 1 deletion keytracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ def __init__(self):
updated after note on event.
"""

self.edosteps_from_a4 = 0
"""
Raw number of edosteps from a4 that was sent to the websocket server
"""


class KeyTracker:
"""
Expand All @@ -84,7 +89,7 @@ def __init__(self):
for ch in range(0, 16):
self.__notes[ch] = ChannelWrapper()

def register_on(self, midi_received, vel, in_channel, midi_sent, send_channel, pitch_offset=8192):
def register_on(self, midi_received, vel, in_channel, midi_sent, send_channel, edosteps_from_a4, pitch_offset=8192):
"""
Called only after a NOTE ON event has been forwarded.
If note on received, but still awaiting cc74 message, use
Expand All @@ -104,6 +109,7 @@ def register_on(self, midi_received, vel, in_channel, midi_sent, send_channel, p
n._note_on = True
n.base_pitch = pitch_offset
n.channel_sent = send_channel
n.edosteps_from_a4 = edosteps_from_a4

def register_received(self, midi_received, vel, in_channel):
"""
Expand Down
3 changes: 3 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import configs
import convert
import ws_server
from configs import SlideMode, CONFIGS
from handler import MidiInputHandler
from mapping import Mapping, MapParsingError
Expand Down Expand Up @@ -163,6 +164,8 @@ def intable(s):
print(f'Starting microtonal message forwarding in '
f'{"MPE" if CONFIGS.MPE_MODE else "MIDI"} mode...')

ws_server.start_ws_server()

seaboard.set_callback(MidiInputHandler(virtual_port))

print("""
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ pyinstaller-hooks-contrib==2021.2
python-rtmidi==1.4.9
pywin32-ctypes==0.2.0
dill==0.3.4
websockets==9.1
janus==0.6.1
73 changes: 73 additions & 0 deletions ws_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
Websocket server for the purpose of sending out microtonal note info
"""
import asyncio
from asyncio import get_event_loop, new_event_loop, set_event_loop
from threading import Thread
from time import sleep

import janus
import websockets


message_queue = {}


async def handler(websocket, path):
global message_queue
await websocket.send('hello')

print('new connection')
q = janus.Queue()
message_queue['sync'] = q.sync_q
message_queue['async'] = q.async_q

while True:
message = await message_queue['async'].get()
print(f'queue got {message}')
await websocket.send(message)


def start_ws_server():
print('starting websocket server at 127.0.0.1:8765')

def ws_thread():
loop = new_event_loop()
set_event_loop(loop)
server = websockets.serve(handler, '127.0.0.1', 8765)
loop.run_until_complete(server)
loop.run_forever()

Thread(target=ws_thread).start()


def send_note_on(edosteps_from_a4, velocity):
if 'sync' in message_queue:
message_queue['sync'].put(f'on:{edosteps_from_a4}:{velocity}')


def send_note_off(edosteps_from_a4, velocity):
if 'sync' in message_queue:
message_queue['sync'].put(f'off:{edosteps_from_a4}:{velocity}')


def send_cc(cc, value):
# assumes single channel mode so channel doesn't matter-
if 'sync' in message_queue:
message_queue['sync'].put(f'cc:{cc}:{value}')


if __name__ == '__main__':
# run this file to test web socket without seaboard
start_ws_server()

sleep(1)

count = 0
while True:
print('ping sent')
send_note_on(0, count)
send_note_off(0, count)
send_cc(64, count)
count += 1
sleep(1)

0 comments on commit bc28067

Please sign in to comment.