dev/osc/ OscToMidiExample1


Osc to Midi

This takes in osc messages on a specified port, and for those matching the signals my TourBoxToOsc script generates, outputs a midi cc with value 127 and the cc number based on which knob or button the event came from. The commented out code in the middle is there to facilitate creating the ableton.txt file by pressing each button in order.

#!/usr/bin/env python3
import sys, os
from rtmidi import MidiIn, MidiOut
from pythonosc.osc_message import OscMessage
from datetime import datetime

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

def dump(*xs):
  print(f"dump {xs}")

def main():
  port = int(os.getenv("port",7001))
  host = os.getenv("host","localhost")
  if host == "localhost":
    host = get_ip()

  midiout = MidiOut()
  ports = midiout.get_ports()
  for i,x in enumerate(ports):
    if "ableton_control_1" in x:
      midiout.open_port(i)
      print(f"Opened {i}: {x}")
      break
  else:
    print(f"Didn't find Ableton port")
    exit(1)
  ableton = Ableton(midiout)

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

  #i = 0 
  #d = set()
  #m = []
  with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as s:
    s.bind((host,port))
    while True:
      #i += 1
      #if i > 60:
      #  break
      data = s.recv(256*1024)
      now = datetime.now().strftime("%c")
      l = len(data)
      print(f"{now} : {l} bytes received")
      message = OscMessage(data)
      address = message.address
      params = message.params
      #if not address in d:
      #  d.add(address)
      #  m.append(address)
      print(f"{address=} {params=}")
      ableton(address,params)
      print()
    #with open("ableton.txt","wt") as f:
    #  f.write("\n".join(m))

def fmt(x):
  'turn numbers into strings, and add "quotes" to strings'
  if type(x) in (int,float):
    return str(x)
  elif type(x) is str:
    if '"' in x and not "'" in x:
      return f"'{x}'"
    else:
      x = x.replace('"',r'\"')
      return f'"{x}"'
def dump(*xs):
  print(xs)
  return
  n,*ys = xs
  print(f"{n}: {', '.join(map(fmt,ys))}")

class Ableton:
  def __init__(self,midiout):
    self.midiout = midiout
    with open("ableton.txt") as f:
      a = f.read().rstrip().splitlines()
      self.d = {}
      for i,line in enumerate(a):
        self.d[line] = i
  def __call__(self,address,params):
    print(f"{address}: {', '.join(map(fmt,params))}")
    if address in self.d:
      i = self.d[address]
      a = [ 0xB0, i, 0x7F ]
      print(f"Sending {i=} {a=}")
      a = bytes(a)
      self.midiout.send_message(a)

if __name__ == "__main__":
  main()

ableton.txt

tour/knob/cw
tour/knob/ccw
tour/dial/cw
tour/dial/ccw
tour/vdial/cw
tour/vdial/ccw
tour/dpad/up
tour/dpad/down
tour/dpad/right
tour/dpad/left
tour/button/2a
tour/button/00
tour/button/03
tour/button/23
tour/button/22
tour/button/02
tour/button/01