Files
ableton-osc/AbletonOSC/view.py
T

217 lines
7.9 KiB
Python
Raw Normal View History

"""Handles /live/view/* OSC addresses (UI navigation)."""
import logging
from typing import Optional
from .handler import AbletonOSCHandler
logger = logging.getLogger(__name__)
class ViewHandler(AbletonOSCHandler):
def init_api(self) -> None:
self.clear_listeners()
view = self._song_view()
# selected scene
self._add("/live/view/get/selected_scene", self._get_selected_scene)
self._add("/live/view/set/selected_scene", self._set_selected_scene)
self._add("/live/view/start_listen/selected_scene", self._start_listen_selected_scene)
self._add("/live/view/stop_listen/selected_scene", self._stop_listen_selected_scene)
# selected track
self._add("/live/view/get/selected_track", self._get_selected_track)
self._add("/live/view/set/selected_track", self._set_selected_track)
self._add("/live/view/start_listen/selected_track", self._start_listen_selected_track)
self._add("/live/view/stop_listen/selected_track", self._stop_listen_selected_track)
# selected clip
self._add("/live/view/get/selected_clip", self._get_selected_clip)
self._add("/live/view/set/selected_clip", self._set_selected_clip)
# selected device
self._add("/live/view/get/selected_device", self._get_selected_device)
# focus
self._add("/live/view/show_clip_detail_view", self._show_clip_detail_view)
self._add("/live/view/show_device_detail_view", self._show_device_detail_view)
self._add("/live/view/focus_browser", self._focus_browser)
# arrangement / session toggle
self._add("/live/view/get/focused_document_view", self._get_focused_document_view)
# ------------------------------------------------------------------
def _song_view(self):
try:
return self.song.view
except Exception:
return None
def _get_selected_scene(self, params: tuple) -> Optional[tuple]:
try:
view = self._song_view()
scenes = list(self.song.scenes)
scene = view.selected_scene
idx = scenes.index(scene)
return (idx,)
except Exception as e:
logger.warning("get selected_scene: %s", e)
return None
def _set_selected_scene(self, params: tuple) -> None:
if not params:
return None
try:
idx = int(params[0])
scenes = list(self.song.scenes)
if 0 <= idx < len(scenes):
self._song_view().selected_scene = scenes[idx]
except Exception as e:
logger.warning("set selected_scene: %s", e)
return None
def _start_listen_selected_scene(self, params: tuple) -> None:
view = self._song_view()
if view is None:
return
key = "view.selected_scene"
self._remove_listener(key)
def cb():
result = self._get_selected_scene(())
if result:
self._send("/live/view/get/selected_scene", result)
try:
view.add_selected_scene_listener(cb)
self._listener_store[key] = (view.remove_selected_scene_listener, cb)
cb()
except Exception as e:
logger.warning("selected_scene listener: %s", e)
def _stop_listen_selected_scene(self, params: tuple) -> None:
self._remove_listener("view.selected_scene")
def _get_selected_track(self, params: tuple) -> Optional[tuple]:
try:
view = self._song_view()
all_tracks = list(self.song.tracks) + list(self.song.return_tracks)
track = view.selected_track
idx = all_tracks.index(track)
return (idx,)
except Exception as e:
logger.warning("get selected_track: %s", e)
return None
def _set_selected_track(self, params: tuple) -> None:
if not params:
return None
try:
idx = int(params[0])
all_tracks = list(self.song.tracks) + list(self.song.return_tracks)
if 0 <= idx < len(all_tracks):
self._song_view().selected_track = all_tracks[idx]
except Exception as e:
logger.warning("set selected_track: %s", e)
return None
def _start_listen_selected_track(self, params: tuple) -> None:
view = self._song_view()
if view is None:
return
key = "view.selected_track"
self._remove_listener(key)
def cb():
result = self._get_selected_track(())
if result:
self._send("/live/view/get/selected_track", result)
try:
view.add_selected_track_listener(cb)
self._listener_store[key] = (view.remove_selected_track_listener, cb)
cb()
except Exception as e:
logger.warning("selected_track listener: %s", e)
def _stop_listen_selected_track(self, params: tuple) -> None:
self._remove_listener("view.selected_track")
def _get_selected_clip(self, params: tuple) -> Optional[tuple]:
try:
view = self._song_view()
clip_view = view.detail_clip
if clip_view is None:
return None
tracks = list(self.song.tracks)
for ti, track in enumerate(tracks):
for ci, slot in enumerate(track.clip_slots):
if slot.has_clip and slot.clip == clip_view:
return (ti, ci)
except Exception as e:
logger.warning("get selected_clip: %s", e)
return None
def _set_selected_clip(self, params: tuple) -> None:
if len(params) < 2:
return None
try:
track_idx = int(params[0])
clip_idx = int(params[1])
tracks = list(self.song.tracks)
if 0 <= track_idx < len(tracks):
slots = list(tracks[track_idx].clip_slots)
if 0 <= clip_idx < len(slots) and slots[clip_idx].has_clip:
self._song_view().detail_clip = slots[clip_idx].clip
except Exception as e:
logger.warning("set selected_clip: %s", e)
return None
def _get_selected_device(self, params: tuple) -> Optional[tuple]:
try:
view = self._song_view()
track = view.selected_track
tracks = list(self.song.tracks) + list(self.song.return_tracks)
track_idx = tracks.index(track)
selected = track.view.selected_device
if selected is None:
return None
devices = list(track.devices)
device_idx = devices.index(selected)
return (track_idx, device_idx)
except Exception as e:
logger.warning("get selected_device: %s", e)
return None
def _show_clip_detail_view(self, params: tuple) -> None:
try:
app = self.manager.application()
app.view.show_view("Detail/Clip")
except Exception as e:
logger.warning("show_clip_detail_view: %s", e)
return None
def _show_device_detail_view(self, params: tuple) -> None:
try:
app = self.manager.application()
app.view.show_view("Detail/DeviceChain")
except Exception as e:
logger.warning("show_device_detail_view: %s", e)
return None
def _focus_browser(self, params: tuple) -> None:
try:
app = self.manager.application()
app.view.show_view("Browser")
except Exception as e:
logger.warning("focus_browser: %s", e)
return None
def _get_focused_document_view(self, params: tuple) -> Optional[tuple]:
try:
app = self.manager.application()
view = app.view.focused_document_view
return (view,)
except Exception as e:
logger.warning("get focused_document_view: %s", e)
return None