Push1+2 vs Push3 control surfaces API - differences and documentation?
Not sure if this should go to Ableton or not (already have a bug report out on a similar topic), but thought it might be helpful to open a discussion here regardless.
Background - I have been using the control surface API since it arrived with m4l way back when. took a while off from musicking, and am returning to some of my previous work after getting a Push3 standalone a few weeks ago. Im going to scope this post to just the touch strip component, but some of this can be applied to (presumably) a lot of the controls that are children of the Push3 control surface object.
I have a m4l device that takes control of the touchstrip on the Push, sets its mode to bi-directional latching (mode 2), and then uses inout to control the position of the crossfader in Live. using the exact same patch that was developed for Push1/2 I am getting wildly different behavior.
1) The (call set_mode X) message to the touchstrip [live.object] is not recognized as a function. The error coming back is "live.object: 'ControlProxy' object has no attribute 'set_mode'" - this seems to indicate that this control on the Push3 lives behind some proxy that is control agnostic. Which leads me to my next point...
2) Why are all controls on the Push3 of the same 'ControlProxy' type instead of their actual type, i.e. TouchStripElement in the case of the touchstrip element - I noticed this when attempting to take over control of the button matrix for another device. All controls seem to sit behind this ControlProxy object. And when calling getinfo on them, they all return the same base functions, with no control specific information. For instance, you'd expect see different info about the touch strip as opposed to an encoder, matrix button, etc. I leveraged this extensively for prototyping and developing LiveAPI calls in JS.
3) The observed output is not useful at all - The output is a series of -128, -64, 0, 64, and 128 values. On Push 2, you get the full pitch bend range of 0 - 16384 (the upper end is clipped a bit, but close enough).
I understand that the Push3 isn't a traditional control surface written in Python, and I'm certainly don't understand the nuances of the technical implementation. That being said, some of these changes to the control surface API, and they way it communicates with Push3 are 100% breaking changes for me, and some of the devices i depend on. I was hoping to port some of my work to standalone mode, to untether from a computer while performing and writing, but now I am questioning not only if it's possible now, but if it will EVER be possible with the way M4L communicates with the Push3.
Will there ever be any documentation released around things that have changed in this regard? Or is something already out there and I just haven't stumbled upon it yet?
I've attached text output of some getinfo calls to the touchstrip control, and the patch used to generate said outputs.
EDIT: Tested on both the current release version of Live (Max 8.5.5), as well as the latest version of the Live Beta (Max 8.5.6).
I've been bashing my head into this as well.
Bumping the thread as a show of solidarity.
You can download and compare Push 1 and 2 scripts in readable form.
We're concerned with the differences in Push 3.
I'm also trying to get my head around the Push3 control surface and accessing this within M4L. I suspect I might be a bit more of a novice, but I'm struggling with something that seems different here to other scripts.
The short Q is, does the Push3 script have "components"? The LOM talks about addressing "buttons", but in my search for how to manipulate the "red box" (view of session view displayed on the button matrix) via M4L it lead me to instead addressing "components". I don't see this components aspect documented in the LOM, nor any Push3 specific documentation to help.
Looking at how this functionality is addressed in other M4L scripts for other controllers, it seems to start with finding the right component (called "SessionComponent") or similar. What I've gathered is a starting point is to send the path of your control surface script to live.path, then "getcount components" for a number of these subcomponents. Doing that on the APC40 script for example tells me there's 74 of them. I can address them by an index number. When I do that to the Push3 script, it says "getcount" is an invalid property name. Trying to address any by an index number also fails. Does this mean the Push3 script is just structured entirely differently?
Trying to address any by an index number also fails. Does this mean the Push3 script is just structured entirely differently?
That is what I am suspecting - its not a python script as all the other control surfaces have been in the past. It would be nice if Ableton/C74 could shed some light on this. As much as I like tinkering under the hood of things, if this is just no longer supported/documented, that would be a pretty big heartbreak for embracing the Push3 as a standalone device. For me and my workflow at least.
Re: Source Audio - Appreciate the reply, but I've been using those for years. As greaterthanzero pointed out, Push3 is nowhere to be found in the Live12 scripts, as it is no longer a python script.
Hi,
Anyone has some findings how to call "components" Belle mentioned or is there replacement for it?
Based on release notes:
"Push 2 will now use the same technology as Push 3, instead of using a remote script. This introduces some UI changes to Push 2. It is possible to force the use of the remote script by adding the option -Push2UseLegacyScript to Live's Options.txt file."
Anyone knows what kind of technology and how to interact with Push 2 and 3 from Max for Live in Ableton 12?
Thanks
Just linking the issue that seems related on Clyphx https://github.com/ldrolez/clyphx-live11/issues/44
I was just playing with Ableton API using Python. So here are findings:
yes, Push 2 and 3 are no longer visible in Control Surfaces in Ableton, but visible via Ableton API using Python
Push 2 or 3 has different object type called Application.ControlSurfaceProxy instead of ClyphX_Pro.ClyphX_Pro.ClyphX_Pro (used Clyphx as an example ... other control surface would have something with its name)
It is possible to collect controller's name eg "Push 2" from Control Surfaces. So Push 2 tells that it is Push 2 controller (please see output below)
Anyone understands what ControlSurfaceProxy is?
Unfortunately, no proxy stuff is not mentioned in https://nsuspray.github.io/Live_API_Doc/11.0.0.xml
ControlSurfaceProxy is only mentioned here: https://github.com/gluon/AbletonLive12_MIDIRemoteScripts/blob/main/_MxDCore/ControlSurfaceWrapper.py
Below is some output from Python (sorry if this is not relevant in M4L, but I thought better to add as we are stuck so anything could be useful):
(.venv) lm@mac live_rpyc-github % python3 client.py
Live.Application.get_application().control_surfaces:
<ClyphX_Pro.ClyphX_Pro.ClyphX_Pro object at 0x2b6b8d390>
<rpyc_control_surface.RpycControlSurface object at 0x2b6b8d518>
None
None
None
None
<Application.ControlSurfaceProxy object at 0x10a0af340>
dir clyphx:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__subject_events__', '__weakref__', '_accumulate_midi_messages', '_c_instance', '_component_guard', '_components', '_control_surface_injector', '_control_surfaces', '_device_component', '_disconnect_and_unregister_all_components', '_displays', '_do_receive_midi', '_do_send_midi', '_enabled', '_flush_midi_messages', '_forwarding_long_identifier_registry', '_forwarding_registry', '_get_tasks', '_highlighting_session_component', '_in_build_midi_map', '_in_component_guard', '_install_forwarding', '_install_mapping', '_is_sending_scheduled_messages', '_midi_message_count', '_midi_message_dict', '_midi_message_list', '_on_scene_list_changed', '_on_selected_scene_changed', '_on_selected_track_changed', '_on_track_list_changed', '_pad_translations', '_process_remaining_scheduled_messages', '_rebuild_requests_during_suppression', '_refresh_displays', '_register_component', '_register_control', '_registered_disconnectables', '_remaining_scheduled_messages', '_send_midi', '_set_session_highlight', '_set_suppress_rebuild_requests', '_suggested_input_port', '_suggested_output_port', '_suppress_requests_counter', '_task_group', '_tasks', '_toggle_lock', '_translate_message', 'accumulating_midi_messages', 'add_disconnect_listener', 'add_received_midi_listener', 'application', 'build_midi_map', 'call_listeners', 'can_lock_to_devices', 'canonical_parent', 'clear_disconnect_listeners', 'clear_received_midi_listeners', 'clyphx_pro_component', 'component_guard', 'components', 'connect_script_instances', 'controls', 'disconnect', 'disconnect_disconnectable', 'disconnect_has_listener', 'disconnect_listener_count', 'find_disconnectable', 'get_control_by_name', 'get_recipient_for_nonsysex_midi_message', 'handle_nonsysex', 'handle_sysex', 'has_disconnectable', 'highlighting_session_component', 'in_component_guard', 'instance_identifier', 'is_sysex_message', 'lock_to_device', 'log_message', 'mxd_midi_scheduler', 'notify_disconnect', 'notify_received_midi', 'port_settings_changed', 'receive_midi', 'received_midi', 'received_midi_has_listener', 'received_midi_listener_count', 'refresh_state', 'register_disconnectable', 'register_slot', 'register_slot_manager', 'release_controlled_track', 'remove_disconnect_listener', 'remove_received_midi_listener', 'request_rebuild_midi_map', 'restore_bank', 'root_components', 'schedule_message', 'set_controlled_track', 'set_device_component', 'set_enabled', 'set_feedback_channels', 'set_highlighting_session_component', 'set_pad_translations', 'show_message', 'song', 'suggest_input_port', 'suggest_map_mode', 'suggest_needs_takeover', 'suggest_output_port', 'supports_pad_translation', 'suppressing_rebuild_requests', 'toggle_lock', 'unlock_from_device', 'unregister_disconnectable', 'update', 'update_display']
dir push:
['__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'add_control_values_arrived_listener', 'add_midi_received_listener', 'control_descriptions', 'control_values_arrived_has_listener', 'enable_receive_midi', 'fetch_received_midi_messages', 'fetch_received_values', 'grab_control', 'midi_received_has_listener', 'release_control', 'remove_control_values_arrived_listener', 'remove_midi_received_listener', 'send_midi', 'send_value', 'subscribe_to_control', 'type_name', 'unsubscribe_from_control']
Live.Application.get_application().control_surfaces[6].type_name:
Push2