dev/osc/ TourBoxToOsc


This needs reorganising, and adding things like osc-listening for configuration and preset-changing. Essentially, for each tourbox message, a preset will associate it to a sequence of Osc messages to designated hosts and ports (with a default set). Then there will be e.g. a receiver that takes in osc messages and generates keypresses.

#!/usr/bin/env python
import serial # python -m pip install pyserial
import time
from pythonosc import udp_client # python -m pip install python-osc
import random
import time
import sys
import os
import platform
import socket


def get_ip():
  # workaround since reaper doesn't receive packets if sent to localhost rather than 192.168.0.x
  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  s.settimeout(0)
  try:
      # doesn't even have to be reachable
      s.connect(('10.254.254.254', 1))
      IP = s.getsockname()[0]
  except Exception:
      IP = '127.0.0.1'
  finally:
      s.close()
  return IP

port = os.getenv("port",os.getenv("PORT",9000))
try:
  port = int(port)
except ValueError:
  print(f"Port '{port}' must be an integer")
  exit(1)
host = os.getenv("host",os.getenv("HOST",get_ip()))

print(f"{host=} {port=}")

# xxd /dev/ttyACM3
def main():
  global client
  client = udp_client.SimpleUDPClient(host,port)
  com_port = os.getenv("com_port",None)
  if com_port is None:
    if platform.system() == "Linux":
      com_port = "/dev/ttyACM0"
    elif platform.system() == "Darwin":
      com_port = "weird"
    elif "cygwin" in platform.system().lower():
      com_port = "/dev/ttyS4"
    elif platform.system() == "Windows":
      com_port = "COM5:"
    else:
      print(f"Don't support {platform.system()}")
      exit(2)
  with serial.Serial(com_port,19200) as ser:
    try:
      while True:
        x = ser.read()
        y = ord(x)
        print(f"{y:02x}")
        handle(y)
    except KeyboardInterrupt:
      print(f"Ctrl-c")
      exit()

def button(n,dirn):
  if dirn == 0:
    action(f"button_{n:02x}")

def rotary(n,dirn):
  if dirn > 0:
    return
  action('rotary_{n:02x}_{dirn}')

def action(x,args=[]):
  print(x,args)
  client.send_message(f"tour/{x}",args)

knobs = {
  0x04: "knob",
  0x0f: "dial", 
  0x09: "vdial"
}
dpad = {
  0x10: "up",
  0x11: "down",
  0x12: "left",
  0x13: "right"
}
def handle(x):
  print(f"{x=}")
  dirn = x >> 7
  x &= 0x7F
  kdirn = x >> 4
  x &= 0x3f
  if x in knobs:
    if dirn > 0:
      return
    action(f"{knobs[x]}/"+("cw" if kdirn > 0 else "ccw"))
  elif x in dpad:
    if dirn > 0:
      return
    action(f"dpad/{dpad[x]}")
  else:
    if dirn > 0:
      return
    action(f"button/{x:02x}")

if __name__ == "__main__":
  main()