Ableton Live MIDI Remote Script / Control Surface

Are these returned using?
Live.DeviceParameter.DeviceParameter.value_items

Ok Ignoring the Volume but for most:

If you set in the E.one template the Min and Max VALUE and the “MIN MIDI VALUE” “MAX MIDI VALUE” and add the units label like %, ms etc to the Parameter name wouldn’t that work?

Then use the Min/Max values as “MIN VALUE” “MAX VALUE” ?
Cur could be “DEFAULT” value then you do not need to capture the midi CC’s on the moment you load a template or page.

so

Semitone (Semitone):
Min: -12 st (-12.0)
Cur: 0 st (0.0)
Max: 12 st (12.0)

I know the ‘st’ already mean Semitone, but in case of db, ms etc it makes sense.

{
	"id": 1,
	"type": "fader",
	"visible": true,
	"name": "SEMITONE ST",
	"color": "FFFFFF",
	"bounds": [0, 40, 146, 56],
	"pageId": 1,
	"controlSetId": 1,
	"inputs": [{
		"potId": 1,
		"valueId": "value"
	}],
	"values": [{
		"message": {
			"type": "cc7",
			"deviceId": 1,
			"lsbFirst": false,
			"parameterNumber": 1,
			"min": 0,
			"max": 127
		},
		"min": -12,
		"max": 12,
		"id": "value"
	}]

If p is a Live.DeviceParameter.DeviceParameter then

p.str_for_value(p.value)

p.value_items is only valid for enumerated parameters (and these are already nicely handled using overlays)

I have already added code to send the current value as a MIDI cc: it’s easier (no need to parse and modify JSON) and cleaner.

1 Like

its actually a good idea that you can re-arrange the order of controls in Ableton.
That would make it easier to customize the template further in the e.one app.

I have some troubles to get the preset dumps:

2022-04-20T13:33:52.471093: info: RemoteScriptMessage: (ElectraOne) Constructing preset on the fly...
2022-04-20T13:33:52.472950: info: Python: INFO:_Framework.ControlSurface:472 - LOG: (ElectraOne) dumping device: PluginDevice.
2022-04-20T13:33:52.472969: info: RemoteScriptMessage: (ElectraOne) dumping device: PluginDevice.
2022-04-20T13:33:52.473057: info: Python: INFO:_Framework.ControlSurface:472 - LOG: (ElectraOne) name bx_console SSL 4000 E display name bx_console SSL 4000 E
2022-04-20T13:33:52.473071: info: RemoteScriptMessage: (ElectraOne) name bx_console SSL 4000 E display name bx_console SSL 4000 E
2022-04-20T13:33:52.473693: info: Python: INFO:_Framework.ControlSurface:473 - LOG: (ElectraOne) ElectraOne uploading preset.
2022-04-20T13:33:52.473713: info: RemoteScriptMessage: (ElectraOne) ElectraOne uploading preset.
2022-04-20T13:33:57.769952: info: Python: INFO:_Framework.ControlSurface:769 - LOG: (ElectraOne) ElectraOne loaded.
2022-04-20T13:33:57.769983: info: RemoteScriptMessage: (ElectraOne) ElectraOne loaded.
2022-04-20T13:33:57.800111: info: Python: INFO:_Framework.ControlSurface:799 - LOG: (ElectraOne) ElectraOne building map.
2022-04-20T13:33:57.800144: info: RemoteScriptMessage: (ElectraOne) ElectraOne building map.
# Local directory where dunps are stored (./dumps) and user defined
# presets are loaded from (./user-presets)
LOCALDIR = r'E:\Ableton User Lib\User Library\Remote Scripts\ElectraOneDump'

inside that dir I create dumps and user-presets but no presets found.
I also tried

r'E:/Ableton User Lib/User Library/Remote Scripts/ElectraOneDump'
'E:/Ableton User Lib/User Library/Remote Scripts/ElectraOneDump'

But no presents :frowning:

EDIT:: solved, partially: I found them in C/users/username/ folder. But my config local path is still ignored.

Another issue is that for vst3 a dump is created with a name like PluginDevice.json this will cause that for vst’s the dump will be overridden.

The VST3 in question: name bx_console SSL 4000 E display name bx_console SSL 4000 E

It is not caused by white spaces. See this other example. the behaviour is the same.

2022-04-20T14:06:14.648887: info: RemoteScriptMessage: (ElectraOne) name TX16Wx display name TX16Wx
2022-04-20T14:06:14.649770: info: Python: INFO:_Framework.ControlSurface:648 - LOG: (ElectraOne) ElectraOne uploading preset.``` 
 
I tested bot vst2 and vst3's

Shouldn’t that be
LOCALDIR = r’E:\Ableton User Lib\User Library\Remote Scripts\ElectraOne’
i.e. without the Dump?

Ah yeah, I followed the documentation as I did not get dumps.


## Installation

Copy all Python files to your local Ableton MIDI Live Scripts folder (```~/Music/Ableton/User Library/Remote Scripts/``` on MacOS and
```~\Documents\Ableton\User Library\Remote Scripts``` on Windows) into a directory called ```ElectraOneDump````.

Add ElectraOne as a Control Surface in Live > Preferences > MIDI. Set the input port to ```Electr Controller (Electra Port 1)``` and the output port to ```Electr Controller (Electra CTRL)```. For both, tick the *Remote* boxes in the MIDI Ports table below. See:

so I renamed ElectraOne to ElectraOneDump

I reverted back to ElectraOne, still only dumps in C:\Users\USERNAME

it’s been a year since I worked on my script, so scanning thru it quickly:
Have you tried self.selected_track.view.selected_device or similar. Might also be self.__chosen_plugin but that’s probably relying on something the framework has provided before.
Within my C4 script you can switch and bank thru devices and tracks, so we built an index of tracks and devices (and params), but the old school way, because (especially the v2) framework was too hardcore for an absolute python novice :roll_eyes::grin::innocent:

Also this might be helpful w re to reordering params

    def __reorder_parameters(self):
        result = []
        if liveobj_valid(self.__chosen_plugin):

            # if a default Live device is chosen, iterate the DEVICE_DICT constant
            # to reorder the local list of plugin parameters
            if self.__chosen_plugin.class_name in list(DEVICE_DICT.keys()):
                device_banks = DEVICE_DICT[self.__chosen_plugin.class_name]
                device_bank_index = 0
                for bank in device_banks:
                    param_bank_index = 0
                    for param_name in bank:
                        parameter_name = ''
                        parameter = get_parameter_by_name(self.__chosen_plugin, param_name)
                        if parameter:
                            parameter_name = parameter.name
                        else:  # get parameter by index if possible
                            param_index = param_bank_index + (SETUP_DB_DEVICE_BANK_SIZE * device_bank_index)
                            if len(self.__chosen_plugin.parameters) > param_index:
                                parameter = self.__chosen_plugin.parameters[param_index]
                                parameter_name = parameter.name
                            else:
                                parameter = None

                        result.append((parameter, parameter_name))
                        param_bank_index += 1

                    device_bank_index += 1

            # otherwise reorder the local list to the order provided by the parameter itself
            else:
                result = [(p, p.name) for p in self.__chosen_plugin.parameters]

        self.__ordered_plugin_parameters = result  # these are tuples where index 0 is a DeviceParameter object
        count = 0

        nbr_of_full_pages = int(len(self.__ordered_plugin_parameters) / SETUP_DB_PARAM_BANK_SIZE)  # len() / 24
        nbr_of_remainders = int(len(self.__ordered_plugin_parameters) % SETUP_DB_PARAM_BANK_SIZE)  # len() % 24
        if nbr_of_full_pages >= SETUP_DB_MAX_PARAM_BANKS:
            nbr_of_full_pages = SETUP_DB_MAX_PARAM_BANKS
        elif nbr_of_full_pages < 0:
            nbr_of_full_pages = 0
            self.main_script().log_message("Not possible, right? and yet I am logged")

        if nbr_of_full_pages == 0 and nbr_of_remainders > 0:
            nbr_of_full_pages = 1
        elif nbr_of_remainders > 0:  # 0 < nbr_of_full_pages < SETUP_DB_MAX_PARAM_BANKS
            nbr_of_full_pages += 1

        # Note: see above handle_pressed_vpot(encoder 8 click in device mode)
        self.__eah.set_max_current_track_device_parameter_bank_nbr(nbr_of_full_pages)
        for p in self.__ordered_plugin_parameters:
            # log the param names to the Live log in order
            self.main_script().log_message("Param {0} name <{1}>".format(count, p[1]))
            count += 1

Thanks, will check it out.

Meanwhile if added an option to sort and filter device parameters based on the DEVICE_DICT in the Ableton framework (using list comprehensions for even cleaner code). Large devices can if needed use multiple MIDI channels, but this can be limited with another option in the config file. See

I have been recording a track in Ableton and Ableton is responding quite slow.
Selecting a track and i have to wait about 5 seconds and meanwhile ableton is locked.
I know there is a timeout in the script so the e.one can load a template.
Might be better to scroll through banks of controllers instead.
Perhaps even load pages vs templates.
Although loading pages by sysex isn’t implemented yet.

so on initial device select a template is loaded that includes the lists as well.
Scrolling through pages just loads additional banks of controllers by loading pages over sysex.

Wouldn’t that provide much better performance?

Also if you disconnect the usb Ableton craches. that might be resolved by device detection / handshake.

Did you turn off deugging and dumping? That should speed up things somewhat.

I did notice the upload time for a preset is near instantaneous when using the Electro Editor, while the remote script takes a long time (and sometimes fails). Not sure what causes this (will investigate next week), but that does indicate that even uploading large presets should not really lead to a significant performance penalty and/or latency. I prefer to keep using one preset for the currently selected device instead of the approach you suggest with several device presets stored in different pages of a single E1 preset (as this requires complex JSON processing). What might help is to ‘cache’ presets: upload them once the first time a corresponding device is selected, and later simply switch presets on the E1. I was already contemplating using a seperate “Ableton Remote Script” bank (which would also include future enhancements like a Mixer preset and a Pad preset). However @martin this requires some firmware updates. Specifically: 1) create a named bank, 2) switch to a named preset (and to an empty one if it doesn’t exist)

ok great will check without debugging.

I am not talking of multiple device presets in multiple pages but about a sort of chunk load algorithm.

but I read back @martin his comment and he is only talking about switching pages.
which wouldn’t be usefull as your limited to 480 controls or so.

When loading vst and Ableton device you wil quickly reach a limit.

An updated version of the Ableton Remote script, using Martin’s update of the firmware, has just been uploaded:

It is still in a rough state, but I am publishing it now looking forward to any feedback!

5 Likes

Hi J,

Nice update, It looks more stable.

I also tried the mixer template. But its very hard to read as the Ableton Track Names are not displayed on the E.one.
So not usable atm as I can really not see what track I am controlling.
But really nice progress. I will test and play more with it.

Thanks!

Definitely on top of my todo list, but that requires a firmware change (ping @martin )

Or rather, this seems to be possible using existing LUA functions too, except that groups appear to have been renamed tiles, and now I’m unsure what the LUA function is/will be called :wink:

Luckily, the E1 sends many log messages, which helped me figure it out.

So: the latest version in the repository now supports changing track names!

3 Likes

Just a quick note from the superbooth. @markus.schloesser helped me to get working on my laptop. And it looks really good!

3 Likes

A great, nice to hear that!

One more update: preset uploading made very MUCH faster by NOT sending it through Ableton Live’s MIDI stack but instead sending it directly to the E1 CTRL port using an external program (SendMidi). See GitHub - xot/ElectraOne: Ableton Live MIDI Remote Script for the Electra One

2 Likes

will definitely try this out , as it sounds very promising. I might need a hand with Github though, is a bit unfamiliar terrain for me currently, but your script is about to change that for me :slight_smile:

1 Like