title: DJ2Go to OSC Bridge tags: midi python dj2go h1: 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.) ```py #!/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() ```