112 lines
3.9 KiB
Python
112 lines
3.9 KiB
Python
|
|
"""Handles /live/scene/* OSC addresses."""
|
||
|
|
import logging
|
||
|
|
from typing import Any, Optional
|
||
|
|
from .handler import AbletonOSCHandler
|
||
|
|
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
|
||
|
|
SCENE_PROPS_RW = [
|
||
|
|
"name", "color", "color_index",
|
||
|
|
"tempo", "tempo_enabled",
|
||
|
|
"time_signature_numerator", "time_signature_denominator",
|
||
|
|
"time_signature_enabled",
|
||
|
|
]
|
||
|
|
|
||
|
|
SCENE_PROPS_RO = ["is_empty", "is_triggered"]
|
||
|
|
|
||
|
|
|
||
|
|
class SceneHandler(AbletonOSCHandler):
|
||
|
|
def init_api(self) -> None:
|
||
|
|
self.clear_listeners()
|
||
|
|
|
||
|
|
for prop in SCENE_PROPS_RW:
|
||
|
|
self._add(f"/live/scene/get/{prop}", self._make_getter(prop))
|
||
|
|
self._add(f"/live/scene/set/{prop}", self._make_setter(prop))
|
||
|
|
self._add(f"/live/scene/start_listen/{prop}", self._make_start_listen(prop))
|
||
|
|
self._add(f"/live/scene/stop_listen/{prop}", self._make_stop_listen(prop))
|
||
|
|
|
||
|
|
for prop in SCENE_PROPS_RO:
|
||
|
|
self._add(f"/live/scene/get/{prop}", self._make_getter(prop))
|
||
|
|
self._add(f"/live/scene/start_listen/{prop}", self._make_start_listen(prop))
|
||
|
|
self._add(f"/live/scene/stop_listen/{prop}", self._make_stop_listen(prop))
|
||
|
|
|
||
|
|
self._add("/live/scene/fire", self._fire)
|
||
|
|
self._add("/live/scene/fire_as_selected", self._fire_as_selected)
|
||
|
|
self._add("/live/scene/get/num_clips", self._get_num_clips)
|
||
|
|
self._add("/live/scene/get/clip_slots/has_clip", self._get_has_clips)
|
||
|
|
|
||
|
|
# ------------------------------------------------------------------
|
||
|
|
|
||
|
|
def _get_scene(self, params: tuple) -> Optional[Any]:
|
||
|
|
if not params:
|
||
|
|
return None
|
||
|
|
idx = int(params[0])
|
||
|
|
scenes = list(self.song.scenes)
|
||
|
|
return scenes[idx] if 0 <= idx < len(scenes) else None
|
||
|
|
|
||
|
|
def _make_getter(self, prop: str):
|
||
|
|
def handler(params: tuple) -> Optional[tuple]:
|
||
|
|
scene = self._get_scene(params)
|
||
|
|
if scene is None:
|
||
|
|
return None
|
||
|
|
val = self._get_prop(scene, prop)
|
||
|
|
return (int(params[0]), val) if val is not None else None
|
||
|
|
return handler
|
||
|
|
|
||
|
|
def _make_setter(self, prop: str):
|
||
|
|
def handler(params: tuple) -> None:
|
||
|
|
if len(params) < 2:
|
||
|
|
return None
|
||
|
|
scene = self._get_scene(params)
|
||
|
|
if scene:
|
||
|
|
self._set_prop(scene, prop, params[1])
|
||
|
|
return None
|
||
|
|
return handler
|
||
|
|
|
||
|
|
def _make_start_listen(self, prop: str):
|
||
|
|
def handler(params: tuple) -> None:
|
||
|
|
scene = self._get_scene(params)
|
||
|
|
if scene:
|
||
|
|
self._register_listener(
|
||
|
|
f"scene.{params[0]}.{prop}", scene, prop,
|
||
|
|
f"/live/scene/get/{prop}", (int(params[0]),)
|
||
|
|
)
|
||
|
|
return handler
|
||
|
|
|
||
|
|
def _make_stop_listen(self, prop: str):
|
||
|
|
def handler(params: tuple) -> None:
|
||
|
|
if params:
|
||
|
|
self._remove_listener(f"scene.{params[0]}.{prop}")
|
||
|
|
return handler
|
||
|
|
|
||
|
|
def _fire(self, params: tuple) -> None:
|
||
|
|
scene = self._get_scene(params)
|
||
|
|
if scene:
|
||
|
|
try:
|
||
|
|
scene.fire()
|
||
|
|
except Exception as e:
|
||
|
|
logger.warning("scene.fire: %s", e)
|
||
|
|
return None
|
||
|
|
|
||
|
|
def _fire_as_selected(self, params: tuple) -> None:
|
||
|
|
scene = self._get_scene(params)
|
||
|
|
if scene:
|
||
|
|
try:
|
||
|
|
scene.fire_as_selected()
|
||
|
|
except Exception as e:
|
||
|
|
logger.warning("scene.fire_as_selected: %s", e)
|
||
|
|
return None
|
||
|
|
|
||
|
|
def _get_num_clips(self, params: tuple) -> Optional[tuple]:
|
||
|
|
scene = self._get_scene(params)
|
||
|
|
if scene is None:
|
||
|
|
return None
|
||
|
|
count = sum(1 for slot in scene.clip_slots if slot.has_clip)
|
||
|
|
return (int(params[0]), count)
|
||
|
|
|
||
|
|
def _get_has_clips(self, params: tuple) -> Optional[tuple]:
|
||
|
|
scene = self._get_scene(params)
|
||
|
|
if scene is None:
|
||
|
|
return None
|
||
|
|
return (int(params[0]),) + tuple(bool(slot.has_clip) for slot in scene.clip_slots)
|