Last updated:

Scripting for REAPER: General Guidelines

Introduction

REAPER Scripting is nice, because we are free to do what we want we the tools that are provided to us. We code alone in most cases, maintain and share scripts like we want, as long as it works, and that is beautiful : because there is no hard coding rules, just like when we join an already existing project, we can take time to experiment and we can learn in a progressive way.

So, if there is no “bad ways ” to script, as long as your script do what it is intended in an efficient way, but how to write better script ?

In this article, I will explain you some general guidelines for scripting. Note that this doesn’t end up to a script code standardization. It is only good practices to follow, good for the users and the future scripts moders that may use your scripts for building new REAPER tools.

Background Research

So you have a script idea. Nice !
The first think you will have to is to check if the action doesn’t already exist. It can be a native function, an SWS function, or another user script posted on stash, and sometimes, just on the forum.
Check for synonyms. Maybe the action use “Go” instead of “Move”, or “Set Cursor”, or “Remove” instead of “Delete”…

It take a bit of time but still less than scripting a full actions so it worth it. Looking in the Actions List and in a Search Engine may help you spare some time. It happen to me some times.

This lead us directly to the next point.

Naming

Your action name is crucial, if you want users to be able to find it after a request on a search engine, or in REAPER Actions List.

It is very important to have a name that explicitly tell the user what your script is all about. Things like “Nice Duplicator”, “Creative Pan” or “Tracks Cleaner” doesn’t tell anything. Does it works on items ? takes ? tracks ? How ?

Starting the action name with a verb and putting as much keywords as possible is a good way to start. It is better to have a very long name action than a three words one that tell nothing. That is exactly how I end up coding actions that already exist.

If you script has a deep concept and it’s not just a regular action but a real toolbox, then you can consider naming with the concept. Loudness Graph, Notes Reader etc… are good example.

Use Header

What a shame when a script come with no embedded infos. Who made it ? Where can I search for assistance ? When was it released ? Is there any special thing I need to know (such as the instructions, the REAPER version needed ?)  Is there any link to a screenshot to see the script in action ? What have change between this version of the script and the older ?

That’s why I propose a script header in my scripts templates, and I use it in all my scripts.

With the integrated IDE in REAPER v5, seeing a script source code is just one click, making this header easily accessible even for the newbies.

Use Comments

Using comments is not only a way make you code more easily, it is also a nice way to refresh your memory when you come back to an old script.

They are also very important to let other users build something from/around your script.

With the new Lua integration in REAPER v5, it become more and more asked to recode old Python script into Lua. What a pain if we don’t know well that language and that there is no comment… I had to reverse engineering several scripts like that. Hard.

Think of your helpers, debuggers, beta-testers, moders and think about the future you ! 😛

Using Code Conventions

There is certain coding rules, that may depend of the language, or on the project…

In REAPER, functions name are written in CamelCase, so why not use this syntax for all your functions ?

You could use lowcase_underscore for variable for example.

You are free to do what you want (beauty of scripting, remember ? 😛 ), but keep in mind that a consistent code is far easier to elaborate, and is easier to understand. I like to consider that I don’t code for myself (even for my scripts that are not open source). Consider scripting as writing for someone.

Conventions can be found at other level (indentation, certain variable name, etc…). I will not detail it too much, as it is quite unlikely that people will follow each of my rules, as all REAPER scripters have a background in other coding languages, and so, their own conventions and habits.

Code Hierarchy of Need

What is the most important ? Efficiency ? Performance ? Feature ?

The Maslow’s hierarchy of need declined for coding is nice way to apprehend your scripting process :

A Hierarchy of Needs for Code

Optimization

There is a lot of ways to optimize a script in term of performance. Storing value in variable (or not), using local variables, avoid redundancy (using functions is a good way to to that).

Some small things related to that can go a long way.

One of the most easy/efficient way to optimize a REAPER script is to use the PreventUIRefresh function. It will freeze the UI of REAPER, and so, save a bit of performance. Note: don’t use it if your script is not finished.

Think Modular

Rather than scripting something that make one and one only thing, it is better to consider your script in a modular way.

What if you script where just a part of a custom action, and that the actions executed before or after the script could change ?

For example, a user ask me a script that would delete MIDI note randomly. Nice ! But instead, I made a script that randomly keep and exclude MIDI notes in a notes selection. The huge advantage of this is that you can run the action several time until you find the right seed. You can even only mute instead of deleting the notes.

One key principle would be to consider your selection output. Your script copy paste an item 5 times ? Consider making the selection output to be only the last items so that you can run the action again if needed. You could also consider making the output selection be all the new items created, depending one what you are supposed to do with these items. There is no one and unique solution, but if the script wouldn’t output any item selection, it will  be without a doubt no very good.

Another way to be modular is too have some global variable below the header of the script, that could be modified for having another behavior. I call this the “USER AREA”, and it often contains infos about how to modify this. It is far easier for the user that want to modify the default value of a script. This way, no need to dig to much in the code to customize the script.

Here is an example using X-Raym_Rename and recolor tracks created by Vordio from a Premiere Pro XML export.lua, a script to use with Vordio :

A nice customizable User Area, containing values of default user input fields.

Use Functions

Thinking modular is a good philosophy inside the script itself. That’s why I advice you to use functions inside it, rather than code it from top to bottom.

I have a lot of scripts that share the same core, and only one of the action differ, making them behave in another way. Sometimes, only a global variable at the top of the script change.

It is also easier to find code snippet that could be useful for you (if you want to use them elsewhere), and for the others who may want to decode your script, and use one of this function.

And as I already said, using functions is a nice way to reduce redundancy.

Consider Bad Usage

So your script run on selected items. What if no item selected ? Your script want a number as user input. What if if write a word ? or nothing ?

Having debugging error message can be confusing for the user who could consider that your script is broken. Depending on the script, you may consider display a dialog box such as “Please select items”, or just do nothing, as it is the case for most REAPER actions.

Use Conventions

Despite it’s pretty deep customization capabilities, we can say that there is certain REAPER usage conventions. For example, pressing the space bar make “play”, and pressing the esc key closed a window. I don’t know every one who changed these keyboard shortcuts.

The only type of conventions that came in mind for me is about GFX. When a GFX is on focused, all keyboard input pass through it. In order to satisfy the user experience expectancies, it is up to you to code these interactions.

An other type of conventions is to use a syntax the /instructions for command in a user input window.

Restore Original State

Does your script change the view, the cursor position etc… ? Was this the purpose of the script ?

A good practice is to store some initial project state (cursor position, item/track selection, time selection and view…” and to restore some of these at the end of the script. Once again, you can see my templates for code snippets about this.

Avoid Using Native/SWS Action

You can use native REAPER action into your script, which is very handy. But these can add undesired undo points, or change a user settings.

You may also consider SWS action to store an actual project state (item selection for example), but this would override the actual save of the user. The good solution is to code the behavior you want. It may be not as handy as using native functions, but you want your script to do something in particular, not “do the thing, and erase the previous user saved states”.

One another reason to avoid using functions you didn’t write is that these actions may change, and so, it will influence the behavior of your script.

Sure, some native/SWS actions would be hardcore to recode, and the idea is to write new actions, not to reverse engineer all that already exist, so there is no shame to use them when required !

Undo Points

Always check Undos after running your script. Does it behave like expected ? If not, try to use Undos functions in the REAPER API.

Actions with bad undo points is a bad for your script users.

User Preferences

Some behaviors may be influenced by the user options preferences. You have to be aware of that then you make your script, and if possible, take all possibilities into account.

Dependencies

You may use external scripts when programming, to help you debug things for example.

When possible, you may consider comment out every functions that used this dependencies, and comment out the call to the external files.

It will be then easier to share and use your script.

Sharing

Well you made a great script and you shared it to the world. What the point if people can’t find it easily ?

That’s why you should always avoid pasting your code deep in a forum thread. Using stash or a coding platform (GitHub or BitBucket), or even your website, is good.

Sure, sharing this way take time. But really, for the user, it definitely worth it.

Also, try to avoid having several versions of a same script online. It is very confusing.

Providing a KeyMap

A keymap is a simple text file when you can define a action name and a custom ID for your script.

Having a constant custom ID is very helpful, as all your users will have the same ID (if they loaded the script this way), and so, then can build custom actions and share toolbars that can call your scripts.

For more infos about this subject, you can see this article : Advanced ReaScripts Management.

Conclusion

A bit of rigor can help you make more efficient scripts, and help future user to customize, mod, and develop scripts based on yours, and contribute to the REAPER user resource development, one of the greatest thing in REAPER.

Don’t be to hard on yourself if you don’t follow all this rules, scripting have to stay something fun !

What do you think ? Have you any other guidelines to share ?