diff --git a/README.md b/README.md index d6ee78b..c6ab1c3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ -# rivage-reaper +# Rivage-Reaper +A script for dropping markers into [Reaper][reaper], and naming them according to the current console scene number and name on a Yamaha Rivage PM10. + +To run this, you need to have Reaper running on the same machine as this script, with OSC set to Local Port (Receive Only) with the default port of 8000, and update the `CONSOLE_IP` variable at the top of the script to match your console's DSP Engine IP. + +## Thanks +The following people and their projects helped make this possible to pull together quickly: +* [Justin Stasiw's Digico-Reaper-Link][digico-reaper-link], the inspiration for this project +* [Brenek Harrison's Yamaha RCP Docs][rcp-docs] + +[reaper]: https://www.reaper.fm/ +[digico-reaper-link]: https://github.com/jms5194/Digico-Reaper-Link +[rcp-docs]: https://github.com/BrenekH/yamaha-rcp-docs/ \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4d8192e --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +python-osc==1.9.3 diff --git a/rivage-reaper.py b/rivage-reaper.py new file mode 100644 index 0000000..91858ff --- /dev/null +++ b/rivage-reaper.py @@ -0,0 +1,73 @@ +from pythonosc.udp_client import SimpleUDPClient +import socket + +REAPER_IP = "127.0.0.1" +REAPER_PORT = 8000 + +CONSOLE_IP = "198.51.100.1" +PORT = 49280 +DELIMITER = b"\n" +BUFFER_SIZE = 4096 + + +class Buffer(object): + def __init__(self, sock): + self.sock = sock + self.buffer = b"" + + def get_line(self): + while DELIMITER not in self.buffer: + data = self.sock.recv(BUFFER_SIZE) + if not data: # socket is closed + return None + self.buffer += data + line, sep, self.buffer = self.buffer.partition(DELIMITER) + return line.decode() + + +def reaper_insert_marker(reaper_client: SimpleUDPClient): + reaper_client.send_message("/action", 40157) + + +def reaper_rename_last_marker(reaper_client: SimpleUDPClient, name): + reaper_client.send_message("/lastmarker/name", name) + + +print(""" ____ _ ____ + | _ \(_)_ ____ _ __ _ ___ | _ \ ___ __ _ _ __ ___ _ __ + | |_) | \ \ / / _` |/ _` |/ _ \_____| |_) / _ \/ _` | '_ \ / _ \ '__| + | _ <| |\ V / (_| | (_| | __/_____| _ < __/ (_| | |_) | __/ | + |_| \_\_| \_/ \__,_|\__, |\___| |_| \_\___|\__,_| .__/ \___|_| + |___/ |_| """) + +reaper_client = SimpleUDPClient(REAPER_IP, REAPER_PORT) +with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.connect((CONSOLE_IP, PORT)) + print("Connected to {}".format(CONSOLE_IP)) + buff = Buffer(sock) + while True: + line = buff.get_line() + if line is None: + break + if line.startswith("NOTIFY sscurrent_ex MIXER:Lib/Scene"): + scene_internal_id = line.rsplit(maxsplit=1)[1] + print( + "Internal scene {} loaded, dropping marker and requesting info".format( + scene_internal_id + ) + ) + reaper_insert_marker(reaper_client) + + request_scene_info_command = "ssinfo_ex MIXER:Lib/Scene {}\n".format( + scene_internal_id + ) + sock.sendall(str.encode(request_scene_info_command)) + elif line.startswith("OK ssinfo_ex MIXER:Lib/Scene"): + quote_split_line = line.split('"') + scene_number = quote_split_line[1] + scene_name = quote_split_line[3] + + print("Renaming marker for scene {} to {}".format(scene_number, scene_name)) + + reaper_cue_name = " ".join((scene_number, scene_name)) + reaper_rename_last_marker(reaper_client, reaper_cue_name)