Logic Pro X Scripter Editor and Controls

Update: I have made this a top-level documentation page on my site. Go there for any updates on this content.

I have been noodling around with the Scripter plug-in in Apple’s Logic Pro X. It is very powerful but also very wonky. Apple has good documentation for it, but inconsistent between the ePub versus the website, though the website looks more complete. Much more can be gleaned from the example scripts, but even then there are behaviors that are not documented anywhere, and the code can be challenging to read if you have little to no experience with Javascript. This post aims to clarify how the Scripter Editor works, and what is expected by both the compiler and the user to build controls for a script.

The Editor

I’ll leave to Apple’s documentation an overview of the Scripter Editor and just dive into the undocumented and undesirable behaviors.

The editor itself, as a Javascript editor is barebones and has none of the features a developer would expect. There is no autocomplete, and formatting is wonky where indentation is inconsistently applied between tabs as 2 and 4 character widths.

Also (and probably worst of all), there are times when the editor will stop compiling to the UI. I was able to jumpstart the editor with a major code change, completely shutting off and reloading of the Scripter plug-in and desired script, and even having to escalate restarting Logic Pro X. The escalation seemed to be necessary more often when I doing a lot of Run Script actions to parse the code, but this wasn’t consistent enough to be hard fact.

There are a few keyboard shortcuts that are specific to the editor. The usual Cut, Copy, and Paste are all supported, but you must be careful you have the correct focus or else you will mistakenly make changes in your project. Beyond that, all other keyboard shortcuts are reserved for the Project window, and the Editor has only these left specific to it:

  • Increase text size: Shift+Option+”+”
  • Decrease text size: Control+Option+”-“

To save a script update, you must go back to the Scripter plug-in menu for that script and select “Save” in the main pulldown menu. Pressing Cmd+S will only save the Project, and that save will not include the Script.

I have to rant a little bit here and state that in spite of the power provided by the Scripter plug-in, the editor is by far the single worst editing tool I have ever used, and very surprising to come across something this poor of quality from Apple. I understand Scripter is deep in the recesses of an already niche and complex app (it’s not even listed on their marketing pages as a feature), but I have to imagine if Apple wants more widespread use of Scripter, then they have a lot of work to do with the editor to get more developers to engage with it.

Controls

Controls aren’t necessary to use Scripter, but they make life a whole lot easier than trying to tweak events in code. This section is a detailed examination of their requirements and behaviors. For each control the following information is provided for each property where relevant:

  • Property name.
  • Property Datatype.
  • Is the Property required by Scripter? For the type property, the actual string expected by Scripter is given, as opposed to just a description.
  • Notes detailing expected values, quirks, and limitations.
  • The return value as captured in the ParameterChanged function.

For the purposes of this post, assume in all of the example controls are being pushed to the API’s PluginParameters array upon initialization.

var PluginParameters = [];
PluginParameters.push({name:"Excelsior!", type:"text"});

Also, assume that all controls must have the following properties specified upon initialization:

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String Yes Partially determines the type of control. Values possible are “lin”, “log”, “menu”, “checkbox”, and “text”. This list is not exhaustive to the types of controls possible. If a particular string is expected by the Scripter compiler, it will be noted in the “required” field.

Different types of controls have different requirements, but all must have those two (which will be called out in each of the listings anyway).

Linear Slider

The Linear Slider is the most obvious use case for affecting MIDI events, and is straightforward to use within the typical number ranges of MIDI: 0–12 chromatic notes, 0%–100%, 0–127 pitches, etc. However, some experimentation is required when working with higher ranges like 0–1000 milliseconds or ranges requiring very fine precision.

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “lin”
minValue Integer or Float No The minimum value for the slider. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 0.00 to the property, and an error will be thrown saying a value is missing. The integer or float can be signed.
maxValue Integer or Float No The maximum value for the slider. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 1.00 to the property, and an error will be thrown saying a value is missing. The integer or float can be signed.
defaultValue Integer or Float No The maximum value for the slider. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 0.00 to the property, and an error will be thrown saying a value is missing. The integer or float can be signed.
numberOfSteps Integer No The number of increments between minValue and maxValue. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 100 to the property, and an error will be thrown saying a value is missing.
unit String No A label shown next to the number in the control to give a unit description if desired. The script will not crash if no value is given, no default will be assigned, and no error will be thrown. Nothing in the provided string will affect the slider’s calculations or settings.
Return value Integer or Float

In general, the linear slider is fairly forgiving when it comes to missing values, but the actual values derived can be unexpected. While the UI will show an appropriate level of precision—tenths, hundredths, thousandths at most—the console reveals far finer precision that may not be useful.

Notes on numberOfSteps

No minValue and maxValue

When no values are given for the minValue, maxValue, and defaultValue properties, Scripter will assign values of 0.00, 1.00, and 0.00 respectively, with the slider incrementing between 0.00–1.00 by the hundredths. So, 0.42 can be a setting for the slider.

numberOfSteps exceeds the difference between minValue and maxValue

If the numberOfSteps value exceeds the difference between minValue and maxValue, then Scripter will divide maxValue by numberOfSteps and use the result for the incremental values, rounding up at certain times. How the control divides the steps is not entirely predictable.

For example, if a slider is set to use 0.00 for minValue, 1.00 for maxValue, and 300 for numberOfSteps, then only values divisible by 0.003 are selectable. Starting at 0.00 and incrementing up the selectable values are 0.000, 0.003, 0.006, 0.010, 0.013, 0.016, 0.020, and so on.

Another example, if a slider is set to use 0 for minValue, 100 for maxValue, and 1000 for numberOfSteps, then only values with a tenths precision are selectable. Starting at 0.000 and incrementing up with the up arrow, the selectable values are 0.000, 0.100, 0.200, 0.300, 0.400, 0.500, 0.600, and so on. However, when the actual slider control is moved to the right, then sometimes values jump to 0.399, 0.599, and so on.

In both cases, the console will output values that are typical floating point values:

2
1.899999976158142
1.8200000524520874
1.7400000095367432
1.6600000858306885
1.5800000429153442
1.5199999809265137
1.440000057220459
1.3799999952316284
1.3200000524520874
1.2600001096725464
1.2000000476837158
1.1400001049041748
1.100000023841858
1.040000081062317
1

Notes on minValue and maxValue

maxValue is less than minValue

If the maxValue is less than the minValue, then the control will behave as expected, moving from the left to right decreasing in value. For example, if a slider is set to use 1.00 for minValue, 0.00 for maxValue, then the slider goes down by the expected increment.

Examples

To create a percent slider set to 50%:

{name:"Linear Slider", type:"lin", unit:"%", minValue:0, maxValue:100, numberOfSteps:100, defaultValue:50}

To create a slider that selects between a range of -12–12, set to 0:

{name:"Linear Slider", type:"lin", minValue:-12, maxValue:12, numberOfSteps:24, defaultValue:00}

Logarithmic Slider

The Linear Slider is another use case for affecting MIDI events, but requires special considerations for its uses when working with number ranges involving very fine precision or negative numbers.

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “log”
minValue Unsigned Integer or Float No The minimum value for the slider. This must be a number greater than or equal to 1. If the value is less than 1, then Scripter automatically assigns it to a value of 1.0. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 1.00 to the property, and an error will be thrown saying a value is missing.
maxValue Unsigned Integer or Float No The maximum value for the slider. This must be a number greater than or equal to 1. If the value is less than 1, then Scripter automatically assigns it to a value of 1.0. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 1.00 to the property, and an error will be thrown saying a value is missing. The integer or float can be signed.
defaultValue Unsigned Integer or Float No The maximum value for the slider. The script will not crash if no value is given, but two things will happen. Scripter will assign the value as 1.0, and an error will be thrown saying a value is missing. The integer or float cannot be signed.
numberOfSteps Integer No The number of increments between minValue and maxValue. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 100 to the property, and an error will be thrown saying a value is missing.
unit String No A label shown next to the number in the control to give a unit description if desired. The script will not crash if no value is given, no default will be assigned, and no error will be thrown.
Return value Integer or Float

In general, the logarithmic slider is less forgiving than the linear slider.

Notes on numberOfSteps

No minValue and maxValue

When no values are given for the minValue, maxValue, and defaultValue properties, Scripter will assign values of 1.00, 1.00, and 1.00 respectively, with a value of 1.0 being given regardless of the slider’s position.

numberOfSteps exceeds the difference between minValue and maxValue

If the numberOfSteps value exceeds the difference between minValue and maxValue, then Scripter will maintain only a precision of hundredths in the UI, but the console will show far more precise values (typical floating point values). How the control divides the steps is not entirely predictable.

In all cases, the console will output values that are typical floating point values:

2
1.899999976158142
1.8200000524520874
1.7400000095367432
1.6600000858306885
1.5800000429153442
1.5199999809265137
1.440000057220459
1.3799999952316284
1.3200000524520874
1.2600001096725464
1.2000000476837158
1.1400001049041748
1.100000023841858
1.040000081062317
1

Pulldown Menu

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “menu”
valueStrings Array of Strings Yes An array of strings for the user to select in the pulldown menu. There does not appear to be an unreasonable limit to the number of strings. (I was able to add 1024 strings without any issue.)
defaultValue Unsigned Integer No A 0-based index value referencing one of the strings in the valueStrings array. If no number is given, or the value is out of the array bounds, then the first menu item (item 0) is selected.
Return value Integer that is the 0-based index of the item selected.

Examples

A pulldown menu with 3 items, and the last item set as the default

{name:"Pulldown Menu", type:"menu", valueStrings:["Item 0", "Item 1", "Item 2"], defaultValue:2}

Radio Buttons

Radio Buttons are a type of menu, with only two strings in the valueStrings array. If more than two items are added to the valueStrings array, then the menu automatically converts into a pulldown menu. Because of the two-item limit, radio buttons are really just a variation of the Checkbox control.

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “menu”
valueStrings Array of Strings Yes An array of two (2) strings for the user to select in the pulldown menu.
defaultValue Unsigned Integer No A 0-based index value referencing one of the strings in the valueStrings array, so 0 or 1. If no number is given, or the value is out of the array bounds, then the first menu item (item 0) is selected.
Return value Integer that is the 0-based index of the item selected.

Examples

A pair of radio button with “On” and “Off” labels.

{name:"Radio Buttons", type:"menu", valueStrings:["On", "Off"]}

Checkbox

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “checkbox”
defaultValue Unsigned Integer No Use 0 for unchecked or 1 for checked. If no number is given, or the value is out of the array bounds, then the checkbox is left unchecked.
Return value 0 for unchecked or 1 for checked.

Examples

A checkbox with the box set to be checked.

{name:"Checkbox", type:"checkbox", defaultValue:1}

Text Control

The text control is a simple label that is used to help organize controls in the interface. But the length of the label is very limited, so if you need to include a “Readme” or instructions, best to add those as comments or a separate text file to travel with the script.

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors. The String has a visible limit of approximately 45 characters. This limit not set by the compiler, but instead by the physical layout of the control.
type String “text”
Return value None.

Examples


{name:"My Text Label Control", type:"text"}