From 178f0c2d006e3f5c65a68b462d11730885914a9c Mon Sep 17 00:00:00 2001 From: Dave Bailey Date: Sun, 14 Jan 2024 14:14:36 -0700 Subject: [PATCH 1/4] Added more complete send support. --- abletonosc/track.py | 65 ++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/abletonosc/track.py b/abletonosc/track.py index 5e21353..99bd19e 100644 --- a/abletonosc/track.py +++ b/abletonosc/track.py @@ -78,7 +78,7 @@ def track_callback(params: Tuple[Any]): # Volume, panning and send are properties of the track's mixer_device so # can't be formulated as normal callbacks that reference properties of track. #-------------------------------------------------------------------------------- - mixer_properties_rw = ["volume", "panning"] + mixer_properties_rw = ["volume", "panning", "sends"] for prop in mixer_properties_rw: self.osc_server.add_handler("/live/track/get/%s" % prop, create_track_callback(self._get_mixer_property, prop)) @@ -89,19 +89,6 @@ def track_callback(params: Tuple[Any]): self.osc_server.add_handler("/live/track/stop_listen/%s" % prop, create_track_callback(self._stop_mixer_listen, prop, include_track_id=True)) - # Still need to fix these - # Might want to find a better approach that unifies volume and sends - def track_get_send(track, params: Tuple[Any] = ()): - send_id, = params - return send_id, track.mixer_device.sends[send_id].value - - def track_set_send(track, params: Tuple[Any] = ()): - send_id, value = params - track.mixer_device.sends[send_id].value = value - - self.osc_server.add_handler("/live/track/get/send", create_track_callback(track_get_send)) - self.osc_server.add_handler("/live/track/set/send", create_track_callback(track_set_send)) - def track_delete_clip(track, params: Tuple[Any]): clip_index, = params track.clip_slots[clip_index].delete_clip() @@ -232,17 +219,34 @@ def track_set_input_routing_channel(track, params): self.osc_server.add_handler("/live/track/set/input_routing_channel", create_track_callback(track_set_input_routing_channel)) def _set_mixer_property(self, target, prop, params: Tuple) -> None: - parameter_object = getattr(target.mixer_device, prop) - self.logger.info("Setting property for %s: %s (new value %s)" % (self.class_identifier, prop, params[0])) - parameter_object.value = params[0] + if (prop == 'sends'): + send_id, value = params + parameter_object = getattr(target.mixer_device, prop)[send_id] + self.logger.info("Setting property for %s: %s (new value %s)" % (self.class_identifier, prop, params[0])) + parameter_object.value = value + else: + parameter_object = getattr(target.mixer_device, prop) + self.logger.info("Setting property for %s: %s (new value %s)" % (self.class_identifier, prop, params[0])) + parameter_object.value = params[0] def _get_mixer_property(self, target, prop, params: Optional[Tuple] = ()) -> Tuple[Any]: - parameter_object = getattr(target.mixer_device, prop) - self.logger.info("Getting property for %s: %s = %s" % (self.class_identifier, prop, parameter_object.value)) - return parameter_object.value, + if (prop == 'sends'): + send_id, = params + parameter_object = getattr(target.mixer_device, prop)[send_id] + self.logger.info("Getting property for %s: %s = %s" % (self.class_identifier, prop, parameter_object.value)) + return send_id, parameter_object.value, + else: + parameter_object = getattr(target.mixer_device, prop) + self.logger.info("Getting property for %s: %s = %s" % (self.class_identifier, prop, parameter_object.value)) + return parameter_object.value, def _start_mixer_listen(self, target, prop, params: Optional[Tuple] = ()) -> None: - parameter_object = getattr(target.mixer_device, prop) + if (prop == 'sends'): + track_id, send_id, = params + parameter_object = getattr(target.mixer_device, prop)[send_id] + else: + parameter_object = getattr(target.mixer_device, prop) + def property_changed_callback(): value = parameter_object.value self.logger.info("Property %s changed of %s %s: %s" % (prop, self.class_identifier, str(params), value)) @@ -251,19 +255,24 @@ def property_changed_callback(): listener_key = (prop, tuple(params)) if listener_key in self.listener_functions: - self._stop_mixer_listen(target, prop, params) - - self.logger.info("Adding listener for %s %s, property: %s" % (self.class_identifier, str(params), prop)) - - parameter_object.add_value_listener(property_changed_callback) - self.listener_functions[listener_key] = property_changed_callback + # self._stop_mixer_listen(target, prop, params) + self.logger.info("Already assigned listener for %s %s, property: %s" % (self.class_identifier, str(params), prop)) + else: + self.logger.info("Adding listener for %s %s, property: %s" % (self.class_identifier, str(params), prop)) + parameter_object.add_value_listener(property_changed_callback) + self.listener_functions[listener_key] = property_changed_callback #-------------------------------------------------------------------------------- # Immediately send the current value #-------------------------------------------------------------------------------- property_changed_callback() def _stop_mixer_listen(self, target, prop, params: Optional[Tuple[Any]] = ()) -> None: - parameter_object = getattr(target.mixer_device, prop) + if (prop == 'sends'): + track_id, send_id, = params + parameter_object = getattr(target.mixer_device, prop)[send_id] + else: + parameter_object = getattr(target.mixer_device, prop) + listener_key = (prop, tuple(params)) if listener_key in self.listener_functions: self.logger.info("Removing listener for %s %s, property %s" % (self.class_identifier, str(params), prop)) From b0d4b9d99c129a66c619ecb421f5bfb8b1a43815 Mon Sep 17 00:00:00 2001 From: Dave Bailey Date: Sun, 14 Jan 2024 16:50:48 -0700 Subject: [PATCH 2/4] Cleaned up code --- abletonosc/track.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/abletonosc/track.py b/abletonosc/track.py index 99bd19e..ea63aa0 100644 --- a/abletonosc/track.py +++ b/abletonosc/track.py @@ -219,7 +219,7 @@ def track_set_input_routing_channel(track, params): self.osc_server.add_handler("/live/track/set/input_routing_channel", create_track_callback(track_set_input_routing_channel)) def _set_mixer_property(self, target, prop, params: Tuple) -> None: - if (prop == 'sends'): + if prop == 'sends': send_id, value = params parameter_object = getattr(target.mixer_device, prop)[send_id] self.logger.info("Setting property for %s: %s (new value %s)" % (self.class_identifier, prop, params[0])) @@ -230,7 +230,7 @@ def _set_mixer_property(self, target, prop, params: Tuple) -> None: parameter_object.value = params[0] def _get_mixer_property(self, target, prop, params: Optional[Tuple] = ()) -> Tuple[Any]: - if (prop == 'sends'): + if prop == 'sends': send_id, = params parameter_object = getattr(target.mixer_device, prop)[send_id] self.logger.info("Getting property for %s: %s = %s" % (self.class_identifier, prop, parameter_object.value)) @@ -241,7 +241,7 @@ def _get_mixer_property(self, target, prop, params: Optional[Tuple] = ()) -> Tup return parameter_object.value, def _start_mixer_listen(self, target, prop, params: Optional[Tuple] = ()) -> None: - if (prop == 'sends'): + if prop == 'sends': track_id, send_id, = params parameter_object = getattr(target.mixer_device, prop)[send_id] else: @@ -255,7 +255,6 @@ def property_changed_callback(): listener_key = (prop, tuple(params)) if listener_key in self.listener_functions: - # self._stop_mixer_listen(target, prop, params) self.logger.info("Already assigned listener for %s %s, property: %s" % (self.class_identifier, str(params), prop)) else: self.logger.info("Adding listener for %s %s, property: %s" % (self.class_identifier, str(params), prop)) @@ -267,7 +266,7 @@ def property_changed_callback(): property_changed_callback() def _stop_mixer_listen(self, target, prop, params: Optional[Tuple[Any]] = ()) -> None: - if (prop == 'sends'): + if prop == 'sends': track_id, send_id, = params parameter_object = getattr(target.mixer_device, prop)[send_id] else: From 9069e48c713863cbe2ca8b16a35ee1ce11407f08 Mon Sep 17 00:00:00 2001 From: Dave Bailey Date: Sun, 14 Jan 2024 17:16:12 -0700 Subject: [PATCH 3/4] Updated README --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7148281..ee59502 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ Represents the view (user interface) of live ## Track API -Represents an audio, MIDI, return or master track. Can be used to set track audio parameters (volume, panning, send, mute, solo), listen for the playing clip slot, query devices, etc. Can also be used to query clips in arrangement view. +Represents an audio, MIDI, return or master track. Can be used to set track audio parameters (volume, panning, sends, mute, solo), listen for the playing clip slot, query devices, etc. Can also be used to query clips in arrangement view. To query the properties of multiple tracks, see [Song: Properties of cue points, scenes and tracks](https://github.com/ideoforms/AbletonOSC#song-properties-of-cue-points-scenes-and-tracks). @@ -234,6 +234,7 @@ To query the properties of multiple tracks, see [Song: Properties of cue points, - Changes for any Track property can be listened for by calling `/live/track/start_listen/ ` - Responses will be sent to `/live/track/get/`, with parameters ` ` + - Sends will take the same format, but with an added send index after the track index: `/live/track/start_listen/sends ` #### Getters @@ -268,7 +269,7 @@ To query the properties of multiple tracks, see [Song: Properties of cue points, | /live/track/get/name | track_id | track_id, name | Query track name | | /live/track/get/panning | track_id | track_id, panning | Query track panning | | /live/track/get/playing_slot_index | track_id | track_id, index | Query currently-playing slot | -| /live/track/get/send | track_id, send_id | track_id, send_id, value | Query track send | +| /live/track/get/sends | track_id, send_id | track_id, send_id, value | Query track send | | /live/track/get/solo | track_id | track_id, solo | Query track solo on/off | | /live/track/get/volume | track_id | track_id, volume | Query track volume | @@ -288,7 +289,7 @@ To query the properties of multiple tracks, see [Song: Properties of cue points, | /live/track/set/output_routing_channel | track_id, channel | | Set output routing channel | | /live/track/set/output_routing_type | track_id, type | | Set output routing type | | /live/track/set/panning | track_id, panning | | Set track panning | -| /live/track/set/send | track_id, send_id, value | | Set track send | +| /live/track/set/sends | track_id, send_id, value | | Set track send | | /live/track/set/solo | track_id, solo | | Set track solo (1=on, 0=off) | | /live/track/set/volume | track_id, volume | | Set track volume | From 66a39e9e4421ff37295adf7ec22e8151f1ccf18a Mon Sep 17 00:00:00 2001 From: Dave Bailey Date: Mon, 15 Jan 2024 16:33:40 -0700 Subject: [PATCH 4/4] Updated send test --- tests/test_track.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_track.py b/tests/test_track.py index c1e90cd..2220e4b 100644 --- a/tests/test_track.py +++ b/tests/test_track.py @@ -41,9 +41,9 @@ def test_track_get_send(client): send_id = 1 for value in [0.5, 0.0]: - client.send_message("/live/track/set/send", [track_id, send_id, value]) + client.send_message("/live/track/set/sends", [track_id, send_id, value]) wait_one_tick() - assert client.query("/live/track/get/send", (track_id, send_id)) == (track_id, send_id, value,) + assert client.query("/live/track/get/sends", (track_id, send_id)) == (track_id, send_id, value,) #-------------------------------------------------------------------------------- # Test track properties - clips