Extend REAPER extension to read/write automation items, wire desktop app to it over UDP

extension-reaper-macos: split main.cpp into tracking.cpp (polls selected
envelope/automation items, reads/writes D_BASELINE) and socket.cpp (basic
UDP listener, non-blocking, drains all pending packets per tick). Nudging
now applies to every selected automation item across every track in the
project, not just the first one found.

app-desktop-macos: new "Extension" column (mirrors the OSC/Remote columns)
to enable/disable the UDP connection and point it at a host/port, plus a
log window. FocusFaderWidget gets an OSC/Ext output-mode toggle (mirrors
TransportWidget's MIDI/OSC toggle) so a fader can drive the extension
directly instead of/alongside OSC. Also renamed the Remote/Tablet buttons
for clarity and split their status indicator into its own column.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Paul Lipscomb
2026-07-16 19:13:34 -04:00
parent cd5ebd84d6
commit 7d4f8a4cd2
11 changed files with 786 additions and 57 deletions
+47
View File
@@ -0,0 +1,47 @@
import socket
_ext_socket = None
_ext_ip = "127.0.0.1"
_ext_port = 9124
_ext_enabled = False
def get_extension_socket():
global _ext_socket
if _ext_socket is None:
_ext_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return _ext_socket
def set_extension_target(ip=None, port=None):
global _ext_socket, _ext_ip, _ext_port
if ip is not None:
_ext_ip = ip
if port is not None:
_ext_port = port
_ext_socket = None
def set_extension_enabled(enabled):
global _ext_enabled
_ext_enabled = enabled
def is_extension_enabled():
return _ext_enabled
def send_to_extension(value):
"""Sends a plain numeric delta to extension-reaper-macos over UDP.
No-op (kill switch) unless set_extension_enabled(True) has been called."""
if not _ext_enabled:
return
try:
get_extension_socket().sendto(str(value).encode(), (_ext_ip, _ext_port))
except Exception as e:
print(f"[Extension send] Error: {e}")