8000 Merge pull request #114 from steeltrack/individual_params · steeltrack/AbletonOSC@eb1dccd · GitHub
[go: up one dir, main page]

Skip to content

Commit

Permalink
Merge pull request ideoforms#114 from steeltrack/individual_params
Browse files Browse the repository at this point in the history
Improved device parameter support
  • Loading branch information
ideoforms authored Jan 16, 2024
2 parents 3f45fca + 20c1dd4 commit eb1dccd
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,11 @@ Represents the view (user interface) of live
| /live/view/get/selected_scene | | scene_index | Returns the selected scene index (first scene = 0) |
| /live/view/get/selected_track | | track_index | Returns the selected index track (first track = 0) |
| /live/view/get/selected_clip | | track_index, scene_index | Returns the track and scene index of the selected clip |
| /live/view/get/selected_device | | track_index, device_index| Get the selected device (first device = 0) |
| /live/view/set/selected_scene | scene_index | | Set the selected scene (first scene = 0) |
| /live/view/set/selected_track | track_index | | Set the selected track (first track = 0) |
| /live/view/set/selected_clip | track_index, scene_index | | Set the selected clip |
| /live/view/set/selected_device | track_index, device_index| | Set the selected device (first device = 0) |
| /live/view/start_listen/selected_scene | | selected_scene | Start listening to the selected scene (first scene = 0) |
| /live/view/start_listen/selected_track | | selected_track | Start listening to selected track (first track = 0) |
| /live/view/stop_listen/selected_scene | | | Stop listening to the selected scene (first scene = 0) |
Expand Down Expand Up @@ -390,6 +392,8 @@ Represents an audio or MIDI clip. Can be used to start/stop clips, and query/mod

Represents an instrument or effect.

- Changes for any Parameter property can be listened for by calling `/live/device/start_listen/parameter/value <track_index> <device index> <parameter_index>`

<details>
<summary><b>Documentation</b>: Device API</summary>

Expand All @@ -406,6 +410,7 @@ Represents an instrument or effect.
| /live/device/get/parameters/is_quantized | track_id, device_id | track_id, device_id, [value, ...] | Get the list of is_quantized settings (i.e., whether the parameter must be an int/bool) |
| /live/device/set/parameters/value | track_id, device_id, value, value ... | | Set the device parameter values |
| /live/device/get/parameter/value | track_id, device_id, parameter_id | track_id, device_id, parameter_id, value | Get a device parameter value |
| /live/device/get/parameter/value_string | track_id, device_id, parameter_id | track_id, device_id, parameter_id, value | Get the device parameter value as a readable string ex: 2500 Hz |
| /live/device/set/parameter/value | track_id, device_id, parameter_id, value | | Set a device parameter value |

For devices:
Expand Down
48 changes: 45 additions & 3 deletions abletonosc/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ def __init__(self, manager):
self.class_identifier = "device"

def init_api(self):
def create_device_callback(func, *args):
def create_device_callback(func, *args, include_ids: bool = False):
def device_callback(params: Tuple[Any]):
track_index, device_index = int(params[0]), int(params[1])
device = self.song.tracks[track_index].devices[device_index]
rv = func(device, *args, params[2:])
if (include_ids):
rv = func(device, *args, params[0:])
else:
rv = func(device, *args, params[2:])

if rv is not None:
return (track_index, device_index, *rv)

Expand Down Expand Up @@ -73,7 +77,6 @@ def device_set_parameters_value(device, params: Tuple[Any] = ()):
self.osc_server.add_handler("/live/device/get/parameters/min", create_device_callback(device_get_parameters_min))
self.osc_server.add_handler("/live/device/get/parameters/max", create_device_callback(device_get_parameters_max))
self.osc_server.add_handler("/live/device/get/parameters/is_quantized", create_device_callback(device_get_parameters_is_quantized))

self.osc_server.add_handler("/live/device/set/parameters/value", create_device_callback(device_set_parameters_value))

#--------------------------------------------------------------------------------
Expand All @@ -85,6 +88,42 @@ def device_get_parameter_value(device, params: Tuple[Any] = ()):
# https://github.com/ideoforms/AbletonOSC/issues/33
param_index = int(params[0])
return param_index, device.parameters[param_index].value

# Uses str_for_value method to return the UI-friendly version of a parameter value (ex: "2500 Hz")
def device_get_parameter_value_string(device, params: Tuple[Any] = ()):
param_index = int(params[0])
return param_index, device.parameters[param_index].str_for_value(device.parameters[param_index].value)

def device_get_parameter_value_listener(device, params: Tuple[Any] = ()):

def property_changed_callback():
value = device.parameters[params[2]].value
self.logger.info("Property %s changed of %s %s: %s" % ('value', 'device parameter', str(params), value))
self.osc_server.send("/live/device/get/parameter/value", (*params, value,))

value_string = device.parameters[params[2]].str_for_value(device.parameters[params[2]].value)
self.logger.info("Property %s changed of %s %s: %s" % ('value_string', 'device parameter', str(params), value_string))
self.osc_server.send("/live/device/get/parameter/value_string", (*params, value_string,))

listener_key = ('device_parameter_value', tuple(params))
if listener_key in self.listener_functions:
device_get_parameter_remove_value_listener(device, params)

self.logger.info("Adding listener for %s %s, property: %s" % ('device parameter', str(params), 'value'))
device.parameters[params[2]].add_value_listener(property_changed_callback)
self.listener_functions[listener_key] = property_changed_callback

property_changed_callback()

def device_get_parameter_remove_value_listener(device, params: Tuple[Any] = ()):
listener_key = ('device_parameter_value', tuple(params))
if listener_key in self.listener_functions:
self.logger.info("Removing listener for %s %s, property %s" % (self.class_identifier, str(params), 'value'))
listener_function = self.listener_functions[listener_key]
device.parameters[params[2]].remove_value_listener(listener_function)
del self.listener_functions[listener_key]
else:
self.logger.warning("No listener function found for property: %s (%s)" % (prop, str(params)))

def device_set_parameter_value(device, params: Tuple[Any] = ()):
param_index, param_value = params[:2]
Expand All @@ -96,5 +135,8 @@ def device_get_parameter_name(device, params: Tuple[Any] = ()):
return param_index, device.parameters[param_index].name

self.osc_server.add_handler("/live/device/get/parameter/value", create_device_callback(device_get_parameter_value))
self.osc_server.add_handler("/live/device/get/parameter/value_string", create_device_callback(device_get_parameter_value_string))
self.osc_server.add_handler("/live/device/set/parameter/value", create_device_callback(device_set_parameter_value))
self.osc_server.add_handler("/live/device/get/parameter/name", create_device_callback(device_get_parameter_name))
self.osc_server.add_handler("/live/device/start_listen/parameter/value", create_device_callback(device_get_parameter_value_listener, include_ids = True))
self.osc_server.add_handler("/live/device/stop_listen/parameter/value", create_device_callback(device_get_parameter_remove_value_listener, include_ids = True))
12 changes: 11 additions & 1 deletion abletonosc/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def get_selected_track(params: Optional[Tuple] = ()):

def get_selected_clip(params: Optional[Tuple] = ()):
return (get_selected_track()[0], get_selected_scene()[0])

def get_selected_device(params: Optional[Tuple] = ()):
return (get_selected_track()[0], list(self.song.view.selected_track.devices).index(self.song.view.selected_track.view.selected_device))

def set_selected_scene(params: Optional[Tuple] = ()):
self.song.view.selected_scene = self.song.scenes[params[0]]
Expand All @@ -27,14 +30,21 @@ def set_selected_clip(params: Optional[Tuple] = ()):
set_selected_track((params[0],))
set_selected_scene((params[1],))

def set_selected_device(params: Optional[Tuple] = ()):
device = self.song.tracks[params[0]].devices[params[1]]
self.song.view.select_device(device)
return params[0], params[1]

self.osc_server.add_handler("/live/view/get/selected_scene", get_selected_scene)
self.osc_server.add_handler("/live/view/get/selected_track", get_selected_track)
self.osc_server.add_handler("/live/view/get/selected_clip", get_selected_clip)
self.osc_server.add_handler("/live/view/get/selected_device", get_selected_device)
self.osc_server.add_handler("/live/view/set/selected_scene", set_selected_scene)
self.osc_server.add_handler("/live/view/set/selected_track", set_selected_track)
self.osc_server.add_handler("/live/view/set/selected_clip", set_selected_clip)
self.osc_server.add_handler("/live/view/set/selected_device", set_selected_device)

self.osc_server.add_handler('/live/view/start_listen/selected_scene', partial(self._start_listen, self.song.view, "selected_scene", getter=get_selected_scene))
self.osc_server.add_handler('/live/view/start_listen/selected_track', partial(self._start_listen, self.song.view, "selected_track", getter=get_selected_track))
self.osc_server.add_handler('/live/view/stop_listen/selected_scene', partial(self._stop_listen, self.song.view, "selected_scene"))
self.osc_server.add_handler('/live/view/stop_listen/selected_track', partial(self._stop_listen, self.song.view, "selected_track"))
self.osc_server.add_handler('/live/view/stop_listen/selected_track', partial(self._stop_listen, self.song.view, "selected_track"))

0 comments on commit eb1dccd

Please sign in to comment.
0