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 | diff --git a/abletonosc/track.py b/abletonosc/track.py index 5e21353..ea63aa0 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,23 @@ 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.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)) 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