Dup Ver Goto 📝

DJ2Go to OSC Bridge

To
222 lines, 609 words, 6278 chars Page 'Dj2go_to_Midi_001' does not exist.

DJ2Go to OSC Bridge

This is script that was mostly written by GPT, then with minor adaptions. The main uses is to use the DJ2Go as an array of buttons and controls to use with Reaper. (Reaper can bind OSC messages to actions.)

#!/usr/bin/env python
import argparse
import rtmidi
import time
from rtmidi.midiutil import open_midiinput
from pythonosc import udp_client


class DJ2Go:
    def __init__(self, midi_port_name=None):
        # Initialize MIDI input
        self.midiin = rtmidi.MidiIn()
        ports = self.midiin.get_ports()

        if not ports:
            raise RuntimeError("No MIDI input ports found!")

        # If no specific port, open the first
        if midi_port_name is None:
            port = 0
        else:
            port = next((i for i, p in enumerate(ports) if midi_port_name in p), 0)

        self.midiin.open_port(port)
        print(f"Opened MIDI port: {ports[port]}")

        self.midiin.set_callback(self._midi_callback)

    def _midi_callback(self, message_data, _time):
        msg, delta_time = message_data

        # Typical messages are [status, data1, data2]
        if len(msg) < 3:
            return
        status, data1, data2 = msg

        # Note On/Off: buttons
        if 0x90 <= status <= 0x9F:  # Note On (with velocity)
            button = data1
            value = 1 if data2 > 0 else 0
            self.button(button_number=button, value=value)
        elif 0x80 <= status <= 0x8F:  # Note Off
            button = data1
            self.button(button_number=button, value=0)

        # Control Change (CC): knobs, faders, jogs, etc.
        elif 0xB0 <= status <= 0xBF:
            cc = data1
            val = data2
            self.control_change(cc, val)

    # Default handler methods (to override)
    def button(self, button_number, value):
        print(f"Button {button_number}: {value}")

    def jogwheel(self, jogwheel, amount):
        print(f"Jogwheel {jogwheel}: {amount}")

    def rotary(self, rotary, amount):
        print(f"Rotary {rotary}: {amount}")

    def pot(self, pot, amount):
        print(f"Pot {pot}: {amount}")

    def fader(self, fader, amount):
        print(f"Fader {fader}: {amount}")

    def control_change(self, cc, val):
        # Example mapping: suppose jogwheels are CC 0x10 and 0x11
        print("cc",cc,val)
        if cc == 25:
            if val >= 64:
              amount = -1
            elif val == 0:
              amount = 0
            else:
              amount = 1
            print(1,amount)
            self.jogwheel(jogwheel=0, amount=amount)
        elif cc == 24:
            if val >= 64:
              amount = -1
            elif val == 0:
              amount = 0
            else:
              amount = 1
            print(2,amount)
            self.jogwheel(jogwheel=1, amount=amount)
        elif cc == 26:
            if val >= 64:
              amount = -1
            elif val == 0:
              amount = 0
            else:
              amount = 1
            print(3,amount)
            self.rotary(rotary=0, amount=amount)
        elif cc in [ 13, 14 ]:
            self.fader(fader=cc-13, amount=val)
        elif cc == 10:
            self.fader(fader="x", amount=val)
        elif cc in [ 8, 23, 11, 9 ]:
            idx = [ 8, 23, 11, 9 ].index(cc)
            self.pot(pot=idx, amount=val)
        else:
            print(f"CC {cc} -> {val}")


button_lookup = {
  68: "left_pitch_minus",
  67: "left_pitch_plus",
  64: "left_sync",
  101: "left_mon",
  51: "left_cue",
  59: "left_play",
  75: "centre_a",
  89: "centre_back",
  90: "centre_enter",
  52: "centre_b",
  70: "right_pitch_minus",
  69: "right_pitch_plus",
  71: "right_sync",
  102: "right_mon",
  60: "right_cue",
  66: "right_play",
}

class DJ2GoOSC(DJ2Go):
    def __init__(self, midi_port_name=None, osc_host="127.0.0.1", osc_port=8000):
        super().__init__(midi_port_name)
        self.client = udp_client.SimpleUDPClient(osc_host, osc_port)
        print(f"Sending OSC to {osc_host}:{osc_port}")

    def jogwheel(self, jogwheel, amount):
        if amount > 0:
          amount = "plus"
        elif amount < 0:
          amount = "minus"
        else:
          return

        path = f"/dj2go/jog/{jogwheel}/{amount}"
        self.client.send_message(path, [])
        print(f"OSC: {path}")

    def rotary(self, rotary, amount):
        if amount > 0:
          amount = "plus"
        elif amount < 0:
          amount = "minus"
        else:
          return

        path = f"/dj2go/rotary/{rotary}/{amount}"
        self.client.send_message(path, [])
        print(f"OSC: {path}")

    def pot(self, pot, amount):
        path = f"/dj2go/pot/{pot}"
        self.client.send_message(path, amount/127.0)
        print(f"OSC: {path} {amount}")

    def fader(self, fader, amount):
        path = f"/dj2go/fader/{fader}"
        self.client.send_message(path, amount/127.0)
        print(f"OSC: {path} {amount}")

    def button(self, button_number, value):
        if button_number in button_lookup:
          button_number = button_lookup[button_number]
        path = f"/dj2go/button/{button_number}"
        self.client.send_message(path, value)
        print(f"OSC: {path} {value}")

def main():
    parser = argparse.ArgumentParser(
        description="Bridge DJ2Go MIDI messages to OSC."
    )
    parser.add_argument(
        "-c", "--controller",
        default="DJ2Go",
        help="MIDI controller name or partial match (default: DJ2Go)"
    )
    parser.add_argument(
        "-i", "--ip",
        default="127.0.0.1",
        help="Target OSC IP address (default: 127.0.0.1)"
    )
    parser.add_argument(
        "-p", "--port",
        type=int,
        default=8000,
        help="Target OSC port (default: 8000)"
    )

    args = parser.parse_args()

    print(f"Starting DJ2Go -> OSC bridge...")
    print(f"MIDI controller: {args.controller}")
    print(f"OSC target: {args.ip}:{args.port}")

    bridge = DJ2GoOSC(midi_port_name=args.controller,
                      osc_host=args.ip,
                      osc_port=args.port)

    try:
        while True:
            time.sleep(0.1)
    except KeyboardInterrupt:
        print("\nExiting gracefully...")


if __name__ == "__main__":
    main()