Files
ableton-osc/AbletonOSC/manager.py
T

128 lines
3.9 KiB
Python
Raw Normal View History

"""
Main ControlSurface entry point for Ableton Live.
Manages OSC server lifecycle and all handler registrations.
"""
import logging
import os
import sys
try:
from ableton.v2.control_surface import ControlSurface
except ImportError:
# Allow importing outside of Ableton for tooling
class ControlSurface: # type: ignore
def __init__(self, c_instance=None):
self._c_instance = c_instance
def song(self):
return None
def application(self):
return None
def disconnect(self):
pass
def update_display(self):
pass
def log_message(self, msg):
print(msg)
from .osc_server import OSCServer
from .song import SongHandler
from .track import TrackHandler
from .return_track import ReturnTrackHandler
from .clip import ClipHandler
from .clip_slot import ClipSlotHandler
from .device import DeviceHandler
from .scene import SceneHandler
from .view import ViewHandler
from .application import ApplicationHandler
from .browser import BrowserHandler
from .groove import GrooveHandler
logger = logging.getLogger(__name__)
LISTEN_PORT = int(os.environ.get("ABLETON_OSC_LISTEN_PORT", 11000))
SEND_PORT = int(os.environ.get("ABLETON_OSC_SEND_PORT", 11001))
class Manager(ControlSurface):
def __init__(self, c_instance=None):
super().__init__(c_instance)
self._setup_logging()
self.osc_server = OSCServer(listen_port=LISTEN_PORT, send_port=SEND_PORT)
self._handlers = []
self._setup_handlers()
self.osc_server.start()
logger.info("AbletonOSC started (listen=%d, send=%d)", LISTEN_PORT, SEND_PORT)
self.osc_server.send("/live/startup", ())
# ------------------------------------------------------------------
def _setup_logging(self) -> None:
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
def _setup_handlers(self) -> None:
handler_classes = [
ApplicationHandler,
SongHandler,
TrackHandler,
ReturnTrackHandler,
ClipHandler,
ClipSlotHandler,
DeviceHandler,
SceneHandler,
ViewHandler,
BrowserHandler,
GrooveHandler,
]
for cls in handler_classes:
h = cls(self)
h.init_api()
self._handlers.append(h)
# Control endpoints
self.osc_server.add_handler("/live/test", self._handle_test)
self.osc_server.add_handler("/live/api/reload", self._handle_reload)
self.osc_server.add_handler("/live/api/show_message", self._handle_show_message)
# ------------------------------------------------------------------
# ControlSurface interface
# ------------------------------------------------------------------
def update_display(self) -> None:
"""Called by Live ~100ms; drives the OSC poll loop."""
self.osc_server.process()
def disconnect(self) -> None:
for h in self._handlers:
h.clear_listeners()
self.osc_server.send("/live/shutdown", ())
self.osc_server.stop()
super().disconnect()
logger.info("AbletonOSC disconnected")
# ------------------------------------------------------------------
# Built-in handlers
# ------------------------------------------------------------------
def _handle_test(self, params: tuple):
return ("AbletonOSC active",)
def _handle_reload(self, params: tuple):
# Re-init all handlers (clears listeners and re-registers)
for h in self._handlers:
h.clear_listeners()
h.init_api()
return ("reloaded",)
def _handle_show_message(self, params: tuple):
if params:
self.log_message(str(params[0]))
return None