Files
ableton-osc/ableton_osc/scene.py
T

112 lines
3.9 KiB
Python
Raw Normal View History

"""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)