API guide¶
This guide describes the main reapy
functions and classes you will probably use in your ReaScripts. For more detailed documentation and access to the source code, check out the Module Index.
Contents
reapy¶
The top-level package reapy
includes general purpose functions that act at the level of REAPER itself, and not at the sub-level of a project, a track, etc.
All functions in reapy.core.reaper.reaper are imported at the top-level, which means you can call reapy.function
for any function function
in this module.
>>> import reapy
>>> reapy.print("Hello world!")
>>> reapy.clear_console()
>>> reapy.get_reaper_version()
'5.965/x64'
>>> command_id = reapy.add_reascript(r"C:\path\to\my\reascript.py")
>>> command_id
53007
>>> reapy.get_command_name(command_id)
'_RSbcbf8f64cb92ff8062457098ee1194c7742e6431'
Improve performance with reapy.inside_reaper
¶
When used from inside REAPER, reapy
has almost identical performance than native ReaScript API. Yet when it is used from the outside, the performance is quite worse. More precisely, since external API calls are processed in a defer
loop inside REAPER, there can only be around 30 to 60 of them per second. In a time-critical context, you should make use of the reapy.inside_reaper
context manager.
>>> import reapy
>>> project = reapy.Project() # Current project
>>>
>>> # Unefficient (and useless) call
>>> bpms = [project.bpm for _ in range(1000)] # Takes at least 30 seconds...
>>>
>>> # Efficient call
>>> with reapy.inside_reaper():
... bpms = [project.bpm for _ in range(1000)]
...
>>> # Takes only 0.1 second!
Non-blocking loops inside REAPER with reapy.defer and reapy.at_exit¶
Inside REAPER, ReaScripts are run in the main thread. Thus, the REAPER interface is blocked until script execution is over. For that reason, you can’t have infinite loops running in ReaScripts, which is why most GUI libraries that include a main loop detecting user actions can’t be used in ReaScripts.
Of course, if you run reapy ReaScripts outside REAPER, there is no problem with infinite loops. Yet if you want to have loops running inside REAPER, you can make use of reapy.defer
.
Here is what reapy.defer
does:
reapy: hey REAPER I need you to call that function I wrote
REAPER: man I can’t spend my whole life running your scripts. I have stuff to do like… you know… making music
reapy: all right well it’s not that urgent. I only need you to call it soon, but not like just right now.
REAPER: ok, well give it to me and I’ll put it in my schedule. It should be done within the next 0.03 seconds.
REAPER typically executes around 30 deferred calls per second. The following example creates a loop that indefinitely prints integers to the REAPER console, without blocking REAPER:
import reapy
def stupid_loop(i):
reapy.print(i)
# hey REAPER could you do that again please?...
reapy.defer(stupid_loop, i + 1)
stupid_loop(0) # Start the loop
When such a loop is running, the user might terminate it at some point, maybe by killing the ReaScript. If you need some clean-up code to be executed when it happens, you can make use of reapy.at_exit
. It tells REAPER to run the function whenever the script stops running (either because it reached its end, or because it has been manually terminated).
The following example opens a file and starts a loop that indefinitely writes integers to that file. Since we want the file to be closed when the user terminates script execution, call to its close
method is deferred to reapy.at_exit
:
import reapy
file = open("somefile.txt", "w")
def stupid_loop(i):
file.write(i)
reapy.defer(stupid_loop, i + 1)
reapy.at_exit(file.close) # Make sure REAPER cleans up after loop
stupid_loop(0) # Start the loop
reapy.Project¶
This is probably the class you will use the most. It represents a REAPER Project. To get the current project, just call reapy.Project()
. If you want to get a project that is not necessarily the current one, pass the index
keyword argument to reapy.Project
with the index of the corresponding tab in REAPER (starting at 0).
>>> reapy.Project() # Current project
Project("(ReaProject*)0x0000000006D3AFF0")
>>> reapy.Project(index=1) # Project in REAPER's second tab
Project("(ReaProject*)0x000000000440A2D0")
>>> reapy.Project(index=-1) # Current project
Project("(ReaProject*)0x0000000006D3AFF0")
Projects have simple properties such as bpm
, is_current_project
, length
. You can manually set some of them, but not all.
>>> project = reapy.Project()
>>> project.bpm
120.0
>>> project.bpm = 100 # Set the tempo in REAPER to 100
>>> project.length = 10 # Doesn't make sense to manually set length!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
They also have useful methods:
>>> project.make_current_project()
>>> track = project.add_track()
>>> project.play() # Hit the play button
The detailed class documentation is available here.
reapy.Track¶
The easiest way to access Tracks is to get project.tracks
, which is the list of all tracks in the project. You can also get project.selected_tracks
.
Tracks have properties such as color
, n_items
, but also items
or fxs
which are the list of Items (or FXs) on the track.
>>> project = reapy.Project()
>>> track = project.tracks[2] # Second track
>>> track.name
'KICK'
Detailed class documentation here.
reapy.Send¶
Track.sends
contains the list of Sends of a Track. You can also create new Sends with Track.add_send
. See class documentation.
reapy.Envelope¶
Track.get_envelope
allows you to get a Track’s envelope by index, name or chunk name (i.e. special name for volume, pan, etc.)
>>> envelope = track.get_envelope(index=0)
>>> envelope.name
'Volume'
>>> track.get_envelope(name="Volume") == envelope
True
See class documentation here.
reapy.Item¶
You can access Items via Project.selected_items
or Track.items
. Detailed class documentation here.
reapy.Take¶
From Items, you can access takes via Item.takes
or Item.active_take
. See the class documentation.
reapy.Source¶
The property Take.source
contains the Source of a Take. Sources have properties such as filename
, sample_rate
, or type
(which can be "MIDI"
, "WAV"
, etc.). See the class documentation.
reapy.FX¶
You can get the list of FX on a track with Track.fxs
. You can also get the first virtual instrument on a Track with Track.instrument
.
Access and set the parameters of an FX as follows:
>>> fx = track.fxs[0]
>>> fx.n_params
10
>>> fx.params[0]
0.5
>>> fx.params[0] = 0.3 # Manually set the parameter
>>> fx.params[0].name # Params have names! (if the VST is nice)
"Dry Gain"
>>> fx.params["Dry Gain"] # You can access them by name too
0.3
See the full class documentation here.