diff --git a/pdlua/tutorial/pd-lua-intro.pdf b/pdlua/tutorial/pd-lua-intro.pdf index a456dd0..69005a5 100644 Binary files a/pdlua/tutorial/pd-lua-intro.pdf and b/pdlua/tutorial/pd-lua-intro.pdf differ diff --git a/tutorial/pd-lua-intro.html b/tutorial/pd-lua-intro.html index c0d013e..5890d86 100644 --- a/tutorial/pd-lua-intro.html +++ b/tutorial/pd-lua-intro.html @@ -704,11 +704,11 @@
Albert Gräf <aggraef@gmail.com>
Computer Music Dept., Institute of Art History and Musicology
Johannes Gutenberg University (JGU) Mainz, Germany
September 2024
This document is licensed under CC BY-SA 4.0. Other formats: Markdown source, PDF
Permanent link: https://agraef.github.io/pd-lua/tutorial/pd-lua-intro.html
Pd's facilities for data structures, iteration, and recursion are somewhat limited, thus sooner or later you'll probably run into a problem that can't be easily solved by a Pd abstraction any more. At this point you'll have to consider writing an external object (or just external, for short) in a "real" programming language instead. Pd externals are usually programmed using C, the same programming language that Pd itself is written in. But novices may find C difficult to learn, and the arcana of Pd's C interface may also be hard to master.
Enter Pd-Lua, the Pd programmer's secret weapon, which lets you develop your externals in the Lua scripting language. Pd-Lua was originally written by Claude Heiland-Allen and has since been maintained by a number of other people in the Pd community. Lua, from PUC Rio, is open-source (under the MIT license), mature, very popular, and supported by a large developer community. It is a small programming language, but very capable, and is generally considered to be relatively easy to learn. For programming Pd externals, you'll also need to learn a few bits and pieces which let you interface your Lua functions to Pd, as explained in this tutorial, but programming externals in Lua is still quite easy and a lot of fun. Using Pd-Lua, you can program your own externals ranging from little helper objects to full-blown synthesizers, sequencers, and algorithmic composition tools. It gives you access to Pd arrays and tables, as well as a number of other useful facilities such as clocks and receivers, which we'll explain in some detail. Pd-Lua also ships with a large collection of instructive examples which you'll find helpful when exploring its possibilities.
Pd-Lua was originally designed for control processing, so we used to recommend Faust for doing dsp instead. We still do, but Faust isn't for everyone; being a purely functional language, Faust follows a paradigm which most programmers aren't very familiar with. Fortunately, thanks to the work of Timothy Schoen, the most recent Pd-Lua versions now also provide support for signal processing and even graphics. So it is now possible to create pretty much any kind of Pd object in Lua, including dsp objects. (However, Faust will almost certainly execute dsp code much more efficiently than Pd-Lua, as it generates highly optimized native code for just this purpose.)
Note that we can't possibly cover Pd or the Lua language themselves here, so you'll have to refer to other online resources to learn about those. In particular, check out the Lua website, which has extensive documentation available, and maybe have a look at Derek Banas' video tutorial for a quick overview of Lua. For Pd, we recommend the Pd FLOSS Manual at https://flossmanuals.net/ to get started.
Pd-Lua works inside any reasonably modern Pd flavor. This encompasses vanilla Pd, of course, but also Purr Data which includes an up-to-date version of Pd-Lua for Lua 5.4 and has it enabled by default, so you should be ready to go immediately; no need to install anything else. The same is true for plugdata (version 0.6.3 or later), a Pd flavor which can also run as a plug-in inside a DAW.
With vanilla Pd, you can install the pdlua package from Deken. There's also an official Debian package, maintained by IOhannes Zmölnig. You can also compile Pd-Lua from source, using the author's Github repository. Compilation instructions are in the README, and you'll also find some Mac and Windows binaries there. In either case, after installing Pd-Lua you also have to add pdlua
to Pd's startup libraries.
If all is well, you should see a message like the following in the Pd console (note that for vanilla Pd you'll have to switch the log level to 2 or more to see that message):
xxxxxxxxxx
pdlua 0.12.4 (GPL) 2008 Claude Heiland-Allen, 2014 Martin Peach et al.
pdlua: compiled for pd-0.55 on Aug 24 2024 00:51:01
Using lua version 5.4
This will also tell you the Lua version that Pd-Lua is using, so that you can install a matching version of the stand-alone Lua interpreter if needed. Lua should be readily available from your package repositories on Linux, and for Mac and Windows you can find binaries on the Lua website. In the following we generally assume that you're using Lua 5.3 or later (using Lua versions older than 5.3 is not recommended).
If all is not well and you do not see that message, then most likely Pd-Lua refused to load because the Lua library is missing. This shouldn't happen if you installed Pd-Lua from a binary package, but if it does then you may have to manually install the right version of the Lua library to make Pd-Lua work. Make sure that you install the package with the Lua library in it; on Debian, Ubuntu and their derivatives this will be something like liblua5.4-0.
With that out of the way, let's have a look at the most essential parts of a Lua external. To make an external, say foo
, loadable by Pd-Lua, you need to put it into a Lua script, which is simply a text file with the right name (which must be the same as the object name, foo
in this case) and extension (which needs to be .pd_lua
), so the file name will be foo.pd_lua
in this example.
Any implementation of an object must always include:
a call to the pd.Class:new():register
method which registers the object class with Pd (this should always be the first line of the script, other than comments)
a definition of the initialize
method for your object class
Here is a prototypical example (this is the contents of the foo.pd_lua file):
xxxxxxxxxx
local foo = pd.Class:new():register("foo")
-
function foo:initialize(sel, atoms)
return true
end
Note that in the first line we called pd.Class:new():register
with the name of the object class as a string, which must be the same as the basename of the script, otherwise Pd's loader will get very confused, create the wrong object class, print a (rather cryptic) error message, and won't be able to create the object.
We also assigned the created class (which is represented as a Lua table) to a variable foo
(which we made local to the script file here, as explained below). We need that variable as a qualifier for the methods of the object class, including initialize
. You can actually name that variable whatever you want, as long as you use that name consistently throughout the script. This can be useful at times, if the actual class name you chose, as it is known to Pd and set with pd.Class:new():register
(as well as being the basename of your .pd_lua script), is a jumble of special characters such as fo:o#?!
, which isn't a valid Lua identifier.
Next comes the initialize
method, which is implemented as a Lua function, prefixing the method name with the name of the class variable we created above and a colon, i.e., foo:initialize
. (This colon syntax is used for all functions that represent methods, which receive the called object as an implicit self
parameter; please check the section on function definitions in the Lua manual for details.) As a bare minimum, as is shown here, this method must return true
, otherwise the loader will assume that the object creation has failed, and will complain that it couldn't create the object with an error message.
We mention in passing here that Pd-Lua also provides a parameter-less postinitialize
method which can be used to execute code after the object has been created, but before the object starts processing messages. We'll see an example of this method later.
NOTE: Pd-Lua runs all Lua objects in the same instance of the Lua interpreter. Therefore, as a general guideline, we want to keep the global name space tidy and clean. That's why we made foo
a local variable, which means that its scope is confined to this single script. Note that this isn't needed for the member variables and methods, as these are securely stowed away inside the object and not accessible from the outside anyway, if the class variable is local
. But the same caveat applies to all variables and functions in the script file that might be needed to implement the object, so normally you want to mark these as local
, too (or turn them into member variables and methods, if that seems more appropriate).
We mention in passing that global variables and functions may also have their uses if you need to share a certain amount of global state between different Lua objects. But even then it's usually safer to have the objects communicate with each other behind the scenes using receivers, which we'll explain later.
To actually use the object class we just created, Pd needs be able to find our foo.pd_lua file. We'll discuss different approaches in the following section, but the easiest way to achieve this is to just drop foo.pd_lua into the directory that your patch is in (say, pd-lua
in your home directory). Now we can just create our first foo
object (hit Ctrl+1, then type the object name foo
), and we should see something like this:
Hooray, it works! :)) Well, this object doesn't do anything right now, so let's equip it with a single inlet/outlet pair. This is what the initialize
method is for, so we have to edit that method accordingly.
NB: If you closed the editor already and don't remember where the file is, you can just right-click the object and choose Open
, which will open the .pd_lua file in your favorite text editor, as configured in your desktop and/or shell environment.
xxxxxxxxxx
local foo = pd.Class:new():register("foo")
-
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
return true
end
Note that, as we already mentioned, the self
variable here is an implicit parameter of any Lua method, which refers to the object itself. Every Pd-Lua object has two member variables inlets
and outlets
which let us specify the number of inlets and outlets our object should have. This needs to be done when the object is initialized; afterwards, the number of inlets and outlets is set in stone and can't be changed any more.
Next, we have to make sure that Pd picks up our edited class definition. Since the Pd-Lua loader will never reload the .pd_lua file for any given object class during a Pd session, we will have to save the patch, quit Pd, relaunch it and reopen the patch:
So there, we got our single inlet/outlet pair now. To do anything with these, we finally have to add some message handlers to our object. Say, for instance, we want to handle a bang message by incrementing a counter and outputting its current value to the outlet. We first have to initialize the counter value in the initialize
method. As we want each foo
object to have its own local counter value, we create the counter as a member variable:
xxxxxxxxxx
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
self.counter = 0
return true
end
It's not necessary to declare the self.counter
variable in any way, just give it an initial value and be done with it. Finally, we have to add a method for the bang message, which looks as follows:
xxxxxxxxxx
function foo:in_1_bang()
self.counter = self.counter + 1
self:outlet(1, "float", {self.counter})
end
We'll dive into the naming conventions for message handlers later, but note that in_1
specifies the first (and only) inlet and bang
the kind of message we expect. In the body of the method we increment the self.counter
value and output its new value on the first (and only) outlet. This is done by the predefined self:outlet
method which takes three arguments: the outlet number, the (Pd) data type to output, and the output value itself. (In general, it's possible to have multiple values there, e.g., when outputting a list value. Therefore the output value is always specified as a Lua table, hence the curly braces around the float output value.)
Throwing everything together, our Lua external now looks as follows:
xxxxxxxxxx
local foo = pd.Class:new():register("foo")
+A Quick Introduction to Pd-Lua
Albert Gräf <aggraef@gmail.com>
Computer Music Dept., Institute of Art History and Musicology
Johannes Gutenberg University (JGU) Mainz, Germany
September 2024
This document is licensed under CC BY-SA 4.0. Other formats: Markdown source, PDF
Permanent link: https://agraef.github.io/pd-lua/tutorial/pd-lua-intro.html
Why Pd-Lua?
Pd's facilities for data structures, iteration, and recursion are somewhat limited, thus sooner or later you'll probably run into a problem that can't be easily solved by a Pd abstraction any more. At this point you'll have to consider writing an external object (or just external, for short) in a "real" programming language instead. Pd externals are usually programmed using C, the same programming language that Pd itself is written in. But novices may find C difficult to learn, and the arcana of Pd's C interface may also be hard to master.
Enter Pd-Lua, the Pd programmer's secret weapon, which lets you develop your externals in the Lua scripting language. Pd-Lua was originally written by Claude Heiland-Allen and has since been maintained by a number of other people in the Pd community. Lua, from PUC Rio, is open-source (under the MIT license), mature, very popular, and supported by a large developer community. It is a small programming language, but very capable, and is generally considered to be relatively easy to learn. For programming Pd externals, you'll also need to learn a few bits and pieces which let you interface your Lua functions to Pd, as explained in this tutorial, but programming externals in Lua is still quite easy and a lot of fun. Using Pd-Lua, you can program your own externals ranging from little helper objects to full-blown synthesizers, sequencers, and algorithmic composition tools. It gives you access to Pd arrays and tables, as well as a number of other useful facilities such as clocks and receivers, which we'll explain in some detail. Pd-Lua also ships with a large collection of instructive examples which you'll find helpful when exploring its possibilities.
Pd-Lua was originally designed for control processing, so we used to recommend Faust for doing dsp instead. We still do, but Faust isn't for everyone; being a purely functional language, Faust follows a paradigm which most programmers aren't very familiar with. Fortunately, thanks to the work of Timothy Schoen, the most recent Pd-Lua versions now also provide support for signal processing and even graphics. So it is now possible to create pretty much any kind of Pd object in Lua, including dsp objects. (However, Faust will almost certainly execute dsp code much more efficiently than Pd-Lua, as it generates highly optimized native code for just this purpose.)
Note that we can't possibly cover Pd or the Lua language themselves here, so you'll have to refer to other online resources to learn about those. In particular, check out the Lua website, which has extensive documentation available, and maybe have a look at Derek Banas' video tutorial for a quick overview of Lua. For Pd, we recommend the Pd FLOSS Manual at https://flossmanuals.net/ to get started.
Installation
Pd-Lua works inside any reasonably modern Pd flavor. This encompasses vanilla Pd, of course, but also Purr Data which includes an up-to-date version of Pd-Lua for Lua 5.4 and has it enabled by default, so you should be ready to go immediately; no need to install anything else. The same is true for plugdata (version 0.6.3 or later), a Pd flavor which can also run as a plug-in inside a DAW.
With vanilla Pd, you can install the pdlua package from Deken. There's also an official Debian package, maintained by IOhannes Zmölnig. You can also compile Pd-Lua from source, using the author's Github repository. Compilation instructions are in the README, and you'll also find some Mac and Windows binaries there. In either case, after installing Pd-Lua you also have to add pdlua
to Pd's startup libraries.
If all is well, you should see a message like the following in the Pd console (note that for vanilla Pd you'll have to switch the log level to 2 or more to see that message):
xxxxxxxxxx
pdlua 0.12.4 (GPL) 2008 Claude Heiland-Allen, 2014 Martin Peach et al.
pdlua: compiled for pd-0.55 on Aug 24 2024 00:51:01
Using lua version 5.4
This will also tell you the Lua version that Pd-Lua is using, so that you can install a matching version of the stand-alone Lua interpreter if needed. Lua should be readily available from your package repositories on Linux, and for Mac and Windows you can find binaries on the Lua website. In the following we generally assume that you're using Lua 5.3 or later (using Lua versions older than 5.3 is not recommended).
If all is not well and you do not see that message, then most likely Pd-Lua refused to load because the Lua library is missing. This shouldn't happen if you installed Pd-Lua from a binary package, but if it does then you may have to manually install the right version of the Lua library to make Pd-Lua work. Make sure that you install the package with the Lua library in it; on Debian, Ubuntu and their derivatives this will be something like liblua5.4-0.
A basic example
With that out of the way, let's have a look at the most essential parts of a Lua external. To make an external, say foo
, loadable by Pd-Lua, you need to put it into a Lua script, which is simply a text file with the right name (which must be the same as the object name, foo
in this case) and extension (which needs to be .pd_lua
), so the file name will be foo.pd_lua
in this example.
Any implementation of an object must always include:
a call to the pd.Class:new():register
method which registers the object class with Pd (this should always be the first line of the script, other than comments)
a definition of the initialize
method for your object class
Here is a prototypical example (this is the contents of the foo.pd_lua file):
xxxxxxxxxx
local foo = pd.Class:new():register("foo")
+
function foo:initialize(sel, atoms)
return true
end
Note that in the first line we called pd.Class:new():register
with the name of the object class as a string, which must be the same as the basename of the script, otherwise Pd's loader will get very confused, create the wrong object class, print a (rather cryptic) error message, and won't be able to create the object.
We also assigned the created class (which is represented as a Lua table) to a variable foo
(which we made local to the script file here, as explained below). We need that variable as a qualifier for the methods of the object class, including initialize
. You can actually name that variable whatever you want, as long as you use that name consistently throughout the script. This can be useful at times, if the actual class name you chose, as it is known to Pd and set with pd.Class:new():register
(as well as being the basename of your .pd_lua script), is a jumble of special characters such as fo:o#?!
, which isn't a valid Lua identifier.
Next comes the initialize
method, which is implemented as a Lua function, prefixing the method name with the name of the class variable we created above and a colon, i.e., foo:initialize
. (This colon syntax is used for all functions that represent methods, which receive the called object as an implicit self
parameter; please check the section on function definitions in the Lua manual for details.) As a bare minimum, as is shown here, this method must return true
, otherwise the loader will assume that the object creation has failed, and will complain that it couldn't create the object with an error message.
We mention in passing here that Pd-Lua also provides a parameter-less postinitialize
method which can be used to execute code after the object has been created, but before the object starts processing messages. We'll see an example of this method later.
NOTE: Pd-Lua runs all Lua objects in the same instance of the Lua interpreter. Therefore, as a general guideline, we want to keep the global name space tidy and clean. That's why we made foo
a local variable, which means that its scope is confined to this single script. Note that this isn't needed for the member variables and methods, as these are securely stowed away inside the object and not accessible from the outside anyway, if the class variable is local
. But the same caveat applies to all variables and functions in the script file that might be needed to implement the object, so normally you want to mark these as local
, too (or turn them into member variables and methods, if that seems more appropriate).
We mention in passing that global variables and functions may also have their uses if you need to share a certain amount of global state between different Lua objects. But even then it's usually safer to have the objects communicate with each other behind the scenes using receivers, which we'll explain later.
To actually use the object class we just created, Pd needs be able to find our foo.pd_lua file. We'll discuss different approaches in the following section, but the easiest way to achieve this is to just drop foo.pd_lua into the directory that your patch is in (say, pd-lua
in your home directory). Now we can just create our first foo
object (hit Ctrl+1, then type the object name foo
), and we should see something like this:
Hooray, it works! :)) Well, this object doesn't do anything right now, so let's equip it with a single inlet/outlet pair. This is what the initialize
method is for, so we have to edit that method accordingly.
NB: If you closed the editor already and don't remember where the file is, you can just right-click the object and choose Open
, which will open the .pd_lua file in your favorite text editor, as configured in your desktop and/or shell environment.
x
local foo = pd.Class:new():register("foo")
+
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
return true
end
Note that, as we already mentioned, the self
variable here is an implicit parameter of any Lua method, which refers to the object itself. Every Pd-Lua object has two member variables inlets
and outlets
which let us specify the number of inlets and outlets our object should have. This needs to be done when the object is initialized; afterwards, the number of inlets and outlets is set in stone and can't be changed any more.
Next, we have to make sure that Pd picks up our edited class definition. Since the Pd-Lua loader will never reload the .pd_lua file for any given object class during a Pd session, we will have to save the patch, quit Pd, relaunch it and reopen the patch:
So there, we got our single inlet/outlet pair now. To do anything with these, we finally have to add some message handlers to our object. Say, for instance, we want to handle a bang message by incrementing a counter and outputting its current value to the outlet. We first have to initialize the counter value in the initialize
method. As we want each foo
object to have its own local counter value, we create the counter as a member variable:
xxxxxxxxxx
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
self.counter = 0
return true
end
It's not necessary to declare the self.counter
variable in any way, just give it an initial value and be done with it. Finally, we have to add a method for the bang message, which looks as follows:
xxxxxxxxxx
function foo:in_1_bang()
self.counter = self.counter + 1
self:outlet(1, "float", {self.counter})
end
We'll dive into the naming conventions for message handlers later, but note that in_1
specifies the first (and only) inlet and bang
the kind of message we expect. In the body of the method we increment the self.counter
value and output its new value on the first (and only) outlet. This is done by the predefined self:outlet
method which takes three arguments: the outlet number, the (Pd) data type to output, and the output value itself. (In general, it's possible to have multiple values there, e.g., when outputting a list value. Therefore the output value is always specified as a Lua table, hence the curly braces around the float output value.)
Throwing everything together, our Lua external now looks as follows:
x
local foo = pd.Class:new():register("foo")
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
self.counter = 0
return true
end
-
function foo:in_1_bang()
self.counter = self.counter + 1
self:outlet(1, "float", {self.counter})
end
So let's relaunch Pd, reload the patch again, and add some GUI elements to test it out:
Note that this is still a very basic example. While the example is complete and fully functional, we have barely scratched the surface here. Pd-Lua also allows you to process an object's creation arguments (employing the atoms
parameter of the initialize
method, which we didn't use above), log messages and errors in the Pd console, create handlers for different types of input messages and signals, output data and signals to different outlets, work with Pd arrays, clocks, and receivers, and even do some graphics and live coding. We will dive into each of these topics in the rest of this tutorial.
Where your Lua files go
As already mentioned, the externals (.pd_lua files) themselves can go either into the directory of the patch using the external, or into any other directory on Pd's search path (on Linux, this generally includes, ~/.pd-externals, or ~/.pd-l2ork-externals when running pd-l2ork or purr-data).
The Lua loader temporarily sets up Lua's package.path
so that it includes the directory with the external, so you can put any Lua modules (.lua files) required by the external into that directory.
NOTE: As of Pd-Lua 0.12.5, the same is true for the pdlua external directory, where you can put any Lua modules that should be readily available to all your Pd-Lua objects. One example of this is Pd-Lua's own pdx.lua live-coding module which we'll discuss later, but it can also be used for general Lua utility modules that you want to use. There are a lot of incredibly useful Lua libraries out there, such as kikito 's inspect or lunarmodules' penlight, although you might prefer to install these using LuaRocks, Lua's most popular package manager.
If you need/want to use Lua libraries from other locations which aren't on the standard Lua package.path
, then you'll have to set up the LUA_PATH
environment variable accordingly. LuaRocks usually takes care of this for you when set up properly. Otherwise you can set LUA_PATH
manually in your system startup files, such as ~/.bashrc or ~/.xprofile on Linux. E.g.:
xxxxxxxxxx
export LUA_PATH=~/lua/'?.lua;;'
Note that ?
is a placeholder for the module name, the semicolon ;
can be used to separate different locations, and a double semicolon ;;
adds Lua's standard search path (make sure that you quote those special characters so that the shell doesn't try to interpret them). You should always include the double semicolon somewhere, otherwise the Lua interpreter won't be able to find its standard library modules any more. Also note that you may want to place the ;;
in front of the path instead, if the standard locations are to be searched before your custom ones.
Creation arguments
Besides the implicit self
argument, the initialize
method has two additional parameters:
sel
, the selector argument, is a string which contains the Pd name of the object class. You probably won't need this, unless you want to use it for error reporting, or if you have a generic setup function for several related object classes. We won't go into this here.
atoms
is a Lua table which contains all the arguments (Pd "atoms", i.e., numbers or strings) an object was created with. #atoms
gives you the number of creation arguments (which may be zero if none were specified), atoms[1]
is the first argument, atoms[2]
the second, and so on. As usual in Lua, if the index i
runs past the last argument, atoms[i]
returns nil
.
For instance, let's say that we want to equip our foo
object with an optional creation argument, a number, to set the initial counter value. This can be done as follows:
xxxxxxxxxx
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
if type(atoms[1]) == "number" then
self.counter = atoms[1]
else
self.counter = 0
end
return true
end
Here we check that the first creation argument is a number. In that case we use it to initialize the counter
member variable, otherwise a default value of 0 is set. Note that if there is no creation argument, atoms[1]
will be nil
which is of type "nil"
, in which case the zero default value will be used.
Note that currently our bang
handler outputs the value after incrementing it, which seems a bit awkward now that we can actually specify the counter's start value. Let's rework that method so that it spits out the current value before incrementing it:
xxxxxxxxxx
function foo:in_1_bang()
self:outlet(1, "float", {self.counter})
self.counter = self.counter + 1
end
Note that it's perfectly fine to invoke self:outlet
at any point in the method.
While we're at it, we might as well add an optional second creation argument to specify the step value of the counter. Try doing that on your own, before peeking at the solution below!
Got it? Good. Here is our final script:
xxxxxxxxxx
local foo = pd.Class:new():register("foo")
+
function foo:in_1_bang()
self.counter = self.counter + 1
self:outlet(1, "float", {self.counter})
end
So let's relaunch Pd, reload the patch again, and add some GUI elements to test it out:
Note that this is still a very basic example. While the example is complete and fully functional, we have barely scratched the surface here. Pd-Lua also allows you to process an object's creation arguments (employing the atoms
parameter of the initialize
method, which we didn't use above), log messages and errors in the Pd console, create handlers for different types of input messages and signals, output data and signals to different outlets, work with Pd arrays, clocks, and receivers, and even do some graphics and live coding. We will dive into each of these topics in the rest of this tutorial.
Objects and Shortcuts
You may have wondered about the whole pd.Class:new():register("foo")
thing, why is that so complicated? The answer is that Lua uses prototypes (class-less objects) to define object-oriented data structures and their methods. Consequently, Pd-Lua defines a few of these to represent various kinds of Pd objects on the Lua side. There's pd.Class
which represents Pd object classes, pd.Table
which is used to access Pd arrays and tables, and pd.Clock
, pd.Receive
for Pd's clock and receiver objects. Most of the time, you'll be dealing with pd.Class
objects and their methods, but the other kinds of objects often come in handy, too.
Each kind of object needs a way to create an instance of the object, that's what the new()
method is for, and a second method (usually called register
, but Pd arrays use sync
instead) which associates the Lua object with its counterpart in Pd. The register()
method also creates the corresponding data structure in Pd in most cases.
So that's why we first invoke new()
and then register()
on the prototype (pd.Class
, etc.) to create a representation of the Pd data structure in Lua land; it's always this two-step process. However, it goes without saying that no-one wants to be that verbose when coding, so Pd-Lua 0.12.14 and later also provide some shortcuts. In the case of pd.Class:new():register()
, the shortcut is simply pd.class()
. (Note that class
is written in all lower-case, while the prototype pd.Class
has Class
capitalized -- this may be hard to see in the font we've chosen for this document.)
Thus, we might have abbreviated the definition of the foo
object class in our first example as:
x
local foo = pd.class("foo")
Much shorter, and easy to remember. Shortcuts for the other kinds of objects will be introduced along with the long forms in the corresponding sections below. Feel free to use them. But note that in the tutorial and the accompanying examples we generally keep to the long forms, so that our examples will work unchanged with older Pd-Lua versions.
Where your Lua files go
As already mentioned, the externals (.pd_lua files) themselves can go either into the directory of the patch using the external, or into any other directory on Pd's search path (on Linux, this generally includes, ~/.pd-externals, or ~/.pd-l2ork-externals when running pd-l2ork or purr-data).
The Lua loader temporarily sets up Lua's package.path
so that it includes the directory with the external, so you can put any Lua modules (.lua files) required by the external into that directory.
NOTE: As of Pd-Lua 0.12.5, the same is true for the pdlua external directory, where you can put any Lua modules that should be readily available to all your Pd-Lua objects. One example of this is Pd-Lua's own pdx.lua live-coding module which we'll discuss later, but it can also be used for general Lua utility modules that you want to use. There are a lot of incredibly useful Lua libraries out there, such as kikito 's inspect or lunarmodules' penlight, although you might prefer to install these using LuaRocks, Lua's most popular package manager.
If you need/want to use Lua libraries from other locations which aren't on the standard Lua package.path
, then you'll have to set up the LUA_PATH
environment variable accordingly. LuaRocks usually takes care of this for you when set up properly. Otherwise you can set LUA_PATH
manually in your system startup files, such as ~/.bashrc or ~/.xprofile on Linux. E.g.:
xxxxxxxxxx
export LUA_PATH=~/lua/'?.lua;;'
Note that ?
is a placeholder for the module name, the semicolon ;
can be used to separate different locations, and a double semicolon ;;
adds Lua's standard search path (make sure that you quote those special characters so that the shell doesn't try to interpret them). You should always include the double semicolon somewhere, otherwise the Lua interpreter won't be able to find its standard library modules any more. Also note that you may want to place the ;;
in front of the path instead, if the standard locations are to be searched before your custom ones.
Creation arguments
Besides the implicit self
argument, the initialize
method has two additional parameters:
sel
, the selector argument, is a string which contains the Pd name of the object class. You probably won't need this, unless you want to use it for error reporting, or if you have a generic setup function for several related object classes. We won't go into this here.
atoms
is a Lua table which contains all the arguments (Pd "atoms", i.e., numbers or strings) an object was created with. #atoms
gives you the number of creation arguments (which may be zero if none were specified), atoms[1]
is the first argument, atoms[2]
the second, and so on. As usual in Lua, if the index i
runs past the last argument, atoms[i]
returns nil
.
For instance, let's say that we want to equip our foo
object with an optional creation argument, a number, to set the initial counter value. This can be done as follows:
xxxxxxxxxx
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
if type(atoms[1]) == "number" then
self.counter = atoms[1]
else
self.counter = 0
end
return true
end
Here we check that the first creation argument is a number. In that case we use it to initialize the counter
member variable, otherwise a default value of 0 is set. Note that if there is no creation argument, atoms[1]
will be nil
which is of type "nil"
, in which case the zero default value will be used.
Note that currently our bang
handler outputs the value after incrementing it, which seems a bit awkward now that we can actually specify the counter's start value. Let's rework that method so that it spits out the current value before incrementing it:
xxxxxxxxxx
function foo:in_1_bang()
self:outlet(1, "float", {self.counter})
self.counter = self.counter + 1
end
Note that it's perfectly fine to invoke self:outlet
at any point in the method.
While we're at it, we might as well add an optional second creation argument to specify the step value of the counter. Try doing that on your own, before peeking at the solution below!
Got it? Good. Here is our final script:
xxxxxxxxxx
local foo = pd.Class:new():register("foo")
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
if type(atoms[1]) == "number" then
self.counter = atoms[1]
else
self.counter = 0
end
if type(atoms[2]) == "number" then
self.step = atoms[2]
else
self.step = 1
end
return true
end
function foo:in_1_bang()
self:outlet(1, "float", {self.counter})
self.counter = self.counter + self.step
end
That was easy enough. If you've been following along, you also know by now how to reload the patch and add a few bits to test the new features. For instance:
Log messages and errors
As soon as your objects get more complicated, you'll probably want to add some messages indicating to the user (or yourself) what's going on inside the object's methods. To these ends, Pd-Lua provides the following two facilities which let you output text messages to the Pd console:
pd.post(msg)
outputs the string msg
to the console on a separate line. You can also post multi-line messages by embedding newline (\n
) characters in the msg
string. This is also frequently used for debugging purposes, e.g., to print out incoming messages or intermediate values that your code calculates.
self:error(msg)
reports an error message, given as a string msg
, to the console. These messages are printed in red, to make them stand out, and you can use the "Find Last Error" menu option to locate the object which reported the error. (In Purr Data it's also possible to just click on the "error" link in the console to locate the object.) Note that self:error
simply prints the message in a way that ties in with "Find Last Error". It doesn't abort the method that executes it, or have any other grave consequences. Thus you can also use it for debugging purposes, like pd.post
, if you need to trace the message back to the object it came from.
For instance, let's use these facilities to have our foo
object post the initial counter value in the initialize
method, as well as report an error if any of the given creation arguments is of the wrong type. Here is the suitably modified initialize
method:
xxxxxxxxxx
function foo:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
self.counter = 0
self.step = 1
if type(atoms[1]) == "number" then
self.counter = atoms[1]
elseif type(atoms[1]) ~= "nil" then
self:error(string.format("foo: #1: %s is of the wrong type %s",
tostring(atoms[1]), type(atoms[1])))
end
if type(atoms[2]) == "number" then
self.step = atoms[2]
elseif type(atoms[2]) ~= "nil" then
self:error(string.format("foo: #2: %s is of the wrong type %s",
tostring(atoms[2]), type(atoms[2])))
end
pd.post(string.format("foo: initialized counter: %g, step size: %g",
self.counter, self.step))
return true
end
And here's how the console log looks like after loading our test patch, and creating an erroneous foo bad
object:
Note that the foo bad
object was still created with the appropriate defaults after the error message, so the initialize
method ran through to the end alright. If you want the object creation to fail after printing the error message, you only have to add a return false
statement in the elseif
branch, after the call to self:error
. Try it! (Of course, you won't be able to locate the object using the printed error message in this case, since the object wasn't actually created. But "Find Last Error" will still work, since Pd itself will also print a "couldn't create" error message.)
Here's another fun exercise: Let's have foo
print a welcome message when it first gets invoked. This can be done by adding a variable init
to the foo
class itself, which is shared between different object instances, as follows:
xxxxxxxxxx
foo.init = false
You should put this after the definition of foo
(i.e., after the line with the pd.Class:new()
call), but before any code that uses this variable. Note that we could also just have used an ordinary local variable at script level instead, but this illustrates how you create static class members in Lua.
You still have to add the code which outputs the welcome message. An obvious place for this is somewhere in initialize
, but here we use the postinitialize
method for illustration purposes:
xxxxxxxxxx
function foo:postinitialize()
if not foo.init then
pd.post("Welcome to foo! Copyright (c) by Foo software.")
foo.init = true
end
end
This will print the message just once, right after the first foo
object is created. There's another finalize
method which can be used to perform any kind of cleanup when an object gets destroyed. For instance, let's rework our example so that it keeps track of the actual number of foo
objects, and prints an additional message when the last foo
object is deleted. To these ends, we turn foo.init
into a counter which keeps track of the number of foo
objects:
xfoo.init = 0
function foo:postinitialize()
if foo.init == 0 then
pd.post("Welcome to foo! Copyright (c) by Foo software.")
end
foo.init = foo.init + 1
end
@@ -722,9 +722,9 @@
function fibs:initialize(sel, atoms)
-- one inlet for bangs and other messages
self.inlets = 1
-- two outlets for the numbers in pairs
self.outlets = 2
-- intial pair
self.a, self.b = 0, 1
-- the modulus can also be set as creation argument
self.m = type(atoms[1]) == "number" and atoms[1] or 10
-- make sure that it's an integer > 0
self.m = math.max(1, math.floor(self.m))
-- print the modulus in the console, so that the user knows what it is
pd.post(string.format("fibs: modulus %d", self.m))
return true
end
function fibs:in_1_bang()
-- output the current pair in the conventional right-to-left order
self:outlet(2, "float", {self.b})
self:outlet(1, "float", {self.a})
-- calculate the next pair; note that it's sufficient to calculate the
-- remainder for the new number
self.a, self.b = self.b, (self.a+self.b) % self.m
end
function fibs:in_1_float(m)
-- a float input changes the modulus and resets the sequence
self.m = math.max(1, math.floor(m))
self.a, self.b = 0, 1
pd.post(string.format("fibs: modulus %d", self.m))
end
-
function fibs:in_1_reset()
-- a reset message just resets the sequence
self.a, self.b = 0, 1
end
And here you can see the object running in a little test patch which outputs the two streams of Fibonacci notes to two different MIDI channels. The two streams can be enabled and disabled individually with the corresponding spigots, and you can also change the modulus on the fly.
Using arrays and tables
Pd's arrays provide an efficient means to store possibly large vectors of float values. These are often used for sample data (waveforms) of a given size (the number of samples), but can also be employed to store copious amounts of numerical control data. Arrays are usually associated with a graphical display (called a graph), and Pd's table object lets you create an array along with a graph as a special kind of subpatch.
Pd-Lua provides a Table
class to represent array and table data, and a few functions to query and manipulate that data. This comes in handy, e.g., if you want to fill an array with a computed waveform. While Pd has its own corresponding facilities, complicated waveforms are often much easier to create in Lua, which offers a fairly complete set of basic mathematical functions in its standard library, and a whole lot more through 3rd party libraries such as Numeric Lua.
Here are the array/table functions provided by Pd-Lua. Note that like in Pd arrays, indices are zero-based and thus range from 0
to tab:length()-1
.
pd.Table:new():sync(name)
: creates the Lua representation of a Pd array and associates it with the Pd array named name
. The result is nil
if an array or table of that name doesn't exist. You usually assign that value to a local variable (named tab
below) to refer to it later.
tab:length()
: returns the length of tab
(i.e., the number of samples in it)
tab:get(i)
: gets the sample at index i
from tab
; returns a number, or nil
if the index runs past the table boundaries
tab:set(i, x)
: sets the sample at index i
of tab
to x
(a number)
tab:redraw()
: redraws the graph of tab
; you should call this once you're finished updating the table
One important point worth mentioning here is that arrays and tables are subject to change at any time in Pd, as they may have their properties changed, be deleted, and recreated with new parameters. This means that you will have to call pd.Table:new():sync(name)
, assign it to a local variable, and check that value every time you want to access the Pd array in a method.
Here is a simple example of a luatab
object which takes the array name as a creation argument, and generates a waveform of the given frequency whenever a float value is received on the single inlet. After finishing generating the waveform, a bang message is output on the single outlet.
xxxxxxxxxx
local luatab = pd.Class:new():register("luatab")
+
function fibs:in_1_reset()
-- a reset message just resets the sequence
self.a, self.b = 0, 1
end
And here you can see the object running in a little test patch which outputs the two streams of Fibonacci notes to two different MIDI channels. The two streams can be enabled and disabled individually with the corresponding spigots, and you can also change the modulus on the fly.
Using arrays and tables
Pd's arrays provide an efficient means to store possibly large vectors of float values. These are often used for sample data (waveforms) of a given size (the number of samples), but can also be employed to store copious amounts of numerical control data. Arrays are usually associated with a graphical display (called a graph), and Pd's table object lets you create an array along with a graph as a special kind of subpatch.
Pd-Lua provides a Table
class to represent array and table data, and a few functions to query and manipulate that data. This comes in handy, e.g., if you want to fill an array with a computed waveform. While Pd has its own corresponding facilities, complicated waveforms are often much easier to create in Lua, which offers a fairly complete set of basic mathematical functions in its standard library, and a whole lot more through 3rd party libraries such as Numeric Lua.
Here are the array/table functions provided by Pd-Lua. Note that like in Pd arrays, indices are zero-based and thus range from 0
to tab:length()-1
.
pd.Table:new():sync(name)
, short form: pd.table(name)
: creates the Lua representation of a Pd array and associates it with the Pd array named name
. The result is nil
if an array or table of that name doesn't exist. You usually assign that value to a local variable (named tab
below) to refer to it later.
tab:length()
: returns the length of tab
(i.e., the number of samples in it)
tab:get(i)
: gets the sample at index i
from tab
; returns a number, or nil
if the index runs past the table boundaries
tab:set(i, x)
: sets the sample at index i
of tab
to x
(a number)
tab:redraw()
: redraws the graph of tab
; you should call this once you're finished updating the table
One important point worth mentioning here is that arrays and tables are subject to change at any time in Pd, as they may have their properties changed, be deleted, and recreated with new parameters. This means that you will have to call pd.Table:new():sync(name)
, assign it to a local variable, and check that value every time you want to access the Pd array in a method.
Here is a simple example of a luatab
object which takes the array name as a creation argument, and generates a waveform of the given frequency whenever a float value is received on the single inlet. After finishing generating the waveform, a bang message is output on the single outlet.
xxxxxxxxxx
local luatab = pd.Class:new():register("luatab")
function luatab:initialize(sel, atoms)
-- single inlet for the frequency, bang goes to the single outlet when we
-- finished generating a new waveform
self.inlets = 1
self.outlets = 1
-- the name of the array/table should be in the 1st creation argument
if type(atoms[1]) == "string" then
self.tabname = atoms[1]
return true
else
self:error(string.format("luatab: expected array name, got %s",
tostring(atoms[1])))
return false
end
end
-
function luatab:in_1_float(freq)
if type(freq) == "number" then
-- the waveform we want to compute, adjust this as needed
local function f(x)
return math.sin(2*math.pi*freq*(x+1))/(x+1)
end
-- get the Pd array and its length
local t = pd.Table:new():sync(self.tabname)
if t == nil then
self:error(string.format("luatab: array or table %s not found",
self.tabname))
return
end
local l = t:length()
-- Pd array indices are zero-based
for i = 0, l-1 do
-- normalize arguments to the 0-1 range
t:set(i, f(i/l))
end
-- this is needed to update the graph display
t:redraw()
-- output a bang to indicate that we've generated a new waveform
self:outlet(1, "bang", {})
else
self:error(string.format("luatab: expected frequency, got %s",
tostring(freq)))
end
end
And here is a sample patch running the luatab
object:
In the same vein, the Pd-Lua distribution includes a much more comprehensive example ltabfill.pd_lua, which leverages Lua's load
function to create a waveform from a user-specified Lua function created dynamically at runtime (instead of being hard-coded into the Lua code, which is what we did above).
Using clocks
Clocks are used internally in Pd to implement objects which "do things" when a timeout occurs, such as delays, pipes, and metronomes. Pd-Lua exposes this functionality so that objects written in Lua can do the same. The following functions are provided:
pd.Clock:new():register(self, method)
: This creates a new clock for the Pd-Lua object self
which, when it goes off, runs the method specified as a string method
. Let's say that method
is "trigger"
, then self:trigger()
will be called without arguments when the clock times out. You usually want to assign the result (a pd.Clock
object) to a member variable of the object (called self.clock
below), so that you can refer to it later.
self.clock:delay(time)
: sets the clock so that it will go off (and call the clock method) after time
milliseconds
self.clock:set(systime)
: sets the clock so that it will go off at the specified absolute systime
(measured in Pd time units of pd.TIMEUNITPERMSEC
, see below)
self.clock:unset()
: unsets the clock, canceling any timeout that has been set previously
self.clock:destruct()
: destroys the clock
NOTE: Calling self.clock:destruct()
on a clock that isn't needed any more (in the finalize
method at the latest) used to be mandatory, and is still possible, but since 0.12.12 it is no longer necessary, as it also happens automatically when the target object gets deleted. This makes it now possible to have one-shot timers like pd.Clock:new():register(self, "oneshot"):delay(1000)
which aren't assigned to any variable. (This is not recommended, though, if you want to maintain compatibility with earlier Pd-Lua versions.)
We mention in passing that you can call self.clock:delay(time)
as soon as the clock has been created, even in the initialize
method of an object. Furthermore, you can have as many clocks as you want in the same object, carrying out different actions, as long as you assign each clock to a different method.
Here is a little tictoc
object we came up with for illustration purposes.
xxxxxxxxxx
local tictoc = pd.Class:new():register("tictoc")
+
function luatab:in_1_float(freq)
if type(freq) == "number" then
-- the waveform we want to compute, adjust this as needed
local function f(x)
return math.sin(2*math.pi*freq*(x+1))/(x+1)
end
-- get the Pd array and its length
local t = pd.Table:new():sync(self.tabname)
if t == nil then
self:error(string.format("luatab: array or table %s not found",
self.tabname))
return
end
local l = t:length()
-- Pd array indices are zero-based
for i = 0, l-1 do
-- normalize arguments to the 0-1 range
t:set(i, f(i/l))
end
-- this is needed to update the graph display
t:redraw()
-- output a bang to indicate that we've generated a new waveform
self:outlet(1, "bang", {})
else
self:error(string.format("luatab: expected frequency, got %s",
tostring(freq)))
end
end
And here is a sample patch running the luatab
object:
In the same vein, the Pd-Lua distribution includes a much more comprehensive example ltabfill.pd_lua, which leverages Lua's load
function to create a waveform from a user-specified Lua function created dynamically at runtime (instead of being hard-coded into the Lua code, which is what we did above).
Using clocks
Clocks are used internally in Pd to implement objects which "do things" when a timeout occurs, such as delays, pipes, and metronomes. Pd-Lua exposes this functionality so that objects written in Lua can do the same. The following functions are provided:
pd.Clock:new():register(self, method)
, short form pd.clock(self, method)
: This creates a new clock for the Pd-Lua object self
which, when it goes off, runs the method specified as a string method
. Let's say that method
is "trigger"
, then self:trigger()
will be called without arguments when the clock times out. You usually want to assign the result (a pd.Clock
object) to a member variable of the object (called self.clock
below), so that you can refer to it later.
self.clock:delay(time)
: sets the clock so that it will go off (and call the clock method) after time
milliseconds
self.clock:set(systime)
: sets the clock so that it will go off at the specified absolute systime
(measured in Pd time units of pd.TIMEUNITPERMSEC
, see below)
self.clock:unset()
: unsets the clock, canceling any timeout that has been set previously
self.clock:destruct()
: destroys the clock
NOTE: Calling self.clock:destruct()
on a clock that isn't needed any more (in the finalize
method at the latest) used to be mandatory, and is still possible, but since 0.12.12 it is no longer necessary, as it also happens automatically when the target object gets deleted. This makes it now possible to have one-shot timers like pd.Clock:new():register(self, "oneshot"):delay(1000)
which aren't assigned to any variable. (This is not recommended, though, if you want to maintain compatibility with earlier Pd-Lua versions.)
We mention in passing that you can call self.clock:delay(time)
as soon as the clock has been created, even in the initialize
method of an object. Furthermore, you can have as many clocks as you want in the same object, carrying out different actions, as long as you assign each clock to a different method.
Here is a little tictoc
object we came up with for illustration purposes.
xxxxxxxxxx
local tictoc = pd.Class:new():register("tictoc")
function tictoc:initialize(sel, atoms)
-- inlet 1 takes an on/off flag, inlet 2 the delay time
self.inlets = 2
-- bangs are output alternating between the two outlets
self.outlets = 2
-- the delay time (optional creation argument, 1000 msec by default)
self.delay = type(atoms[1]) == "number" and atoms[1] or 1000
-- we start out on the left outlet
self.left = true
-- initialize the clock
self.clock = pd.Clock:new():register(self, "tictoc")
return true
end
function tictoc:finalize()
self.clock:destruct()
end
-- As with the metro object, nonzero, "bang" and "start" start the clock,
-- zero and "stop" stop it.
@@ -737,7 +737,7 @@
-- the clock method: tic, toc, tic, toc ...
function tictoc:tictoc()
-- output a bang, alternate between left and right
self:outlet(self.left and 1 or 2, "bang", {})
self.left = not self.left
-- reschedule
self.clock:delay(self.delay)
end
And here is the usual test patch:
An explanation of self.clock:set(systime)
is still in order. In contrast to self.clock:delay(time)
, this schedules a timeout at the given absolute time given in pd.TIMEUNITPERMSEC
units. This may be preferable in some situations, e.g., if you have to schedule some events that use increasing timestamps instead of delta times. Version 0.12.12 of Pd-Lua adds the pd.TIMEUNITPERMSEC
constant and some support functions for dealing with these time values:
pd.systime()
: Returns the current time in pd.TIMEUNITPERMSEC
units. You can use this to derive a value for self.clock:set
's systime
argument. For instance, self.clock:set(pd.systime() + time * pd.TIMEUNITPERMSEC)
is equivalent to self.clock:delay(time)
.
pd.timesince(systime)
: Returns the time since the given systime
in msec. You might use this to measure the time between two events, like Pd's built-in timer
object does. In particular, pd.timesince(0)
gives you the msec equivalent of pd.systime()
, i.e., Pd's current time in msec.
Also note that the notion of time alluded to above is Pd's internal or logical time which always advances monotonically (until it wraps around) with each dsp tick, i.e., once per 64 samples with Pd's default block size setting.
More comprehensive examples using clocks can be found in the Pd-Lua distribution; have a look, e.g., at ldelay.pd_lua and luametro.pd_lua. Also, lpipe.pd_lua demonstrates how to dynamically create an entire collection of clocks in order to implement a delay line for a stream of messages.
Using receivers
As every seasoned Pd user knows, Pd also enables you to transmit messages in a wireless fashion, using receiver symbols, or just receivers for short, as destination addresses. In Pd, this is done through the built-in send
and receive
objects, as well as the "send" and "receive symbol" properties of GUI objects.
Sending messages to a receiver is straightforward:
pd.send(sym, sel, atoms)
: Sends a message with the given selector symbol sel
(a string) and arguments atoms
(a Lua table, which may be empty if the message has no arguments) to the given receiver sym
(a string).
This works pretty much like the outlet
method, but outputs messages to the given receiver instead. For instance, let's say you have a toggle with receiver symbol onoff
in your patch, then you can turn on that toggle with a call like pd.send("onoff", "float", {1})
. (Recall that the atoms
argument always needs to be a table, even if it is a singleton, lest you'll get that "invalid atoms table" error that we discussed earlier).
One complication are receiver symbols using a $0-
patch id prefix, which are commonly used to differentiate receiver symbols in different toplevel patches or abstractions, in order to prevent name clashes. A Pd-Lua object doesn't have any idea of what toplevel patch it is located in, and what the numeric id of that patch is, so you'll have to expand the $0-
prefix on the Pd side and pass it, e.g., as a creation argument. For instance, suppose that the toggle receiver is in fact named $0-onoff
, then something like the following Pd-Lua object will do the trick, if you invoke it as luasend $0-onoff
:
xxxxxxxxxx
local luasend = pd.Class:new():register("luasend")
function luasend:initialize(sel, atoms)
self.inlets = 1
self.receiver = tostring(atoms[1])
return true
end
-
function luasend:in_1_bang()
pd.send(self.receiver, "float", {1})
end
Of course, this also handles ordinary receive symbols just fine if you pass them as a creation argument. Here is a little test patch showing luasend
in action:
It is worth noting here that the same technique applies whenever you need to pass on "$" arguments to a Pd-Lua object in a Pd abstraction.
So let's have a look at receivers now. These work pretty much like clocks in that you create them registering a method, and destroy them when they are no longer needed:
pd.Receive:new():register(self, sym, method)
: This creates a new receiver named sym
(a string) for the Pd-Lua object self
which, when a message for that receiver becomes available, runs the method specified as a string method
. Let's say that method
is "receive"
, then self:receive(sel, atoms)
will be invoked with the selector symbol sel
and arguments atoms
of the transmitted message. You want to assign the result (a pd.Receive
object) to a member variable of the object (called self.recv
below), so that you can refer to it later (if only to destroy it, see below).
self.recv:destruct()
: destroys the receiver (as with clocks, this is now entirely optional, but it may still be useful if the receiver needs to be removed before its target object ceases to be)
Here is a little example which receives any kind of message, stores it, and outputs the last stored message when it gets a bang
on its inlet.
xxxxxxxxxx
local luarecv = pd.Class:new():register("luarecv")
+
function luasend:in_1_bang()
pd.send(self.receiver, "float", {1})
end
Of course, this also handles ordinary receive symbols just fine if you pass them as a creation argument. Here is a little test patch showing luasend
in action:
It is worth noting here that the same technique applies whenever you need to pass on "$" arguments to a Pd-Lua object in a Pd abstraction.
So let's have a look at receivers now. These work pretty much like clocks in that you create them registering a method, and destroy them when they are no longer needed:
pd.Receive:new():register(self, sym, method)
, short form pd.receive(self, sym, method)
: This creates a new receiver named sym
(a string) for the Pd-Lua object self
which, when a message for that receiver becomes available, runs the method specified as a string method
. Let's say that method
is "receive"
, then self:receive(sel, atoms)
will be invoked with the selector symbol sel
and arguments atoms
of the transmitted message. You want to assign the result (a pd.Receive
object) to a member variable of the object (called self.recv
below), so that you can refer to it later (if only to destroy it, see below).
self.recv:destruct()
: destroys the receiver (as with clocks, this is now entirely optional, but it may still be useful if the receiver needs to be removed before its target object ceases to be)
Here is a little example which receives any kind of message, stores it, and outputs the last stored message when it gets a bang
on its inlet.
xxxxxxxxxx
local luarecv = pd.Class:new():register("luarecv")
function luarecv:initialize(sel, atoms)
self.inlets = 1
self.outlets = 1
-- pass the receiver symbol as creation argument
local sym = tostring(atoms[1])
pd.post(string.format("luarecv: receiver '%s'", sym))
-- create the receiver
self.recv = pd.Receive:new():register(self, sym, "receive")
return true
end
function luarecv:finalize()
self.recv:destruct()
end
function luarecv:receive(sel, atoms)
-- simply store the message, so that we can output it later
self.sel, self.atoms = sel, atoms
pd.post(string.format("luarecv: got '%s %s'", sel,
table.concat(atoms, " ")))
end
@@ -771,6 +771,6 @@
local x1, y1 = x/width-0.5, y/height-0.5
-- calculate the normalized phase, shifted by 0.5, since we want zero to be
-- the center up position
local phase = math.atan(y1, x1)/math.pi + 0.5
-- renormalize if we get an angle > 1, to account for the phase shift
if phase > 1 then
phase = phase - 2
end
self.phase = phase
local tip_x, tip_y = self:tip();
-
if tip_x ~= self.tip_x or tip_y ~= self.tip_y then
self.tip_x = tip_x
self.tip_y = tip_y
self:in_1_bang()
self:repaint()
end
end
And here's the same patch again, which now lets us drag the hand to change the phase value:
More dial action: clocks and speedometers
Now that our dial object is basically finished, let's do something interesting with it. The most obvious thing is to just turn it into a clock (albeit one with just a seconds hand) counting off the seconds. For that we just need to add a metro object which increments the phase angle and sends the value to the dial each second:
Pd lets us store the phase angle in a named variable (v phase
) which can be recalled in an expr
object doing the necessary calculations. The expr
object sends the computed value to the phase
receiver, which updates both the variable and the upper numbox, and the numbox then updates the dial. Note that we also set the variable whenever the dial outputs a new value, so you can also drag around the hand to determine the starting phase. And we added a 0
message to reset the hand to the 12 o'clock home position when needed.
Here's another little example, rather useless but fun, simulating a speedometer which just randomly moves the needle left and right:
I'm sure you can imagine many more creative uses for this simple but surprisingly versatile little GUI object, which we did in just a few lines of fairly simple Lua code. Have fun with it! An extended version of this object, which covers some more features of the graphics API that we didn't discuss here to keep things simple, can be found as dial.pd and dial.pd_lua in the tutorial examples:
The extended example adds messages for resizing the object and setting colors, and also shows how to save and restore object state in the creation arguments using the set_args()
method mentioned at the beginning of this section. The accompanying patch covers all the examples we discussed here, and adds a third example showing how to utilize our dial object as a dB meter.
Live coding
I've been telling you all along that in order to make Pd-Lua pick up changes you made to your .pd_lua files, you have to relaunch Pd and reload your patches. Well, as you probably guessed by now, this isn't actually true. So in this section we are going to cover Pd-Lua's live coding features, which let you modify your sources and have Pd-Lua reload them on the fly, without ever exiting the Pd environment. This rapid incremental style of development is one of the hallmark features of dynamic interactive programming environments like Pd and Lua. Musicians also like to employ it to modify their programs live on stage, which is where the term "live coding" comes from.
I've kept this topic for the final section of this guide, because it is somewhat advanced, and there are several different (traditional and new) methods available which differ in capabilities and ease of use. However, in modern Pd-Lua versions there is one preferred method which rules them all, so if you want to cut to the chase as quickly as possible, then feel free to just skip ahead to the pdx.lua section now.
If you're still here, then you probably want to learn about the other methods, too. So in the following we first describe the predefined Pd-Lua object classes pdlua
and pdluax
, so that you know the "traditional" live-coding instruments that Pd-Lua had on offer for a long time. We also discuss how to add a reload
message to your existing object definitions. This is quite easy to do by directly employing Pd-Lua's dofile
function, which is also what both pdlua
and pdluax
use internally.
These methods all work with pretty much any Pd-Lua version out there, but require a little bit of setup which can get time-consuming and error-prone if you're dealing with large patches involving a lot of different Lua objects.
That's why Pd-Lua nowadays includes an extension module called pdx.lua that "just works" out of the box and automatizes everything, so that you only have to put a simple reload
message in your main patch and be done with it. This is also the method we recommend, to novices and expert users alike. We describe it last so that you can also gather a good understanding of Pd-Lua's traditional live coding methods, and learn to appreciate them. These are still used in many older scripts, and Pd-Lua will continue to support them for backward compatibility.
pdlua
The pdlua
object accepts a single kind of message of the form load filename
on its single inlet, which causes the given Lua file to be loaded and executed. Since pdlua
has no outlets, its uses are rather limited. However, it does enable you to load global Lua definitions and execute an arbitrary number of statements, e.g., to post some text to the console or transmit messages to Pd receivers using the corresponding Pd-Lua functions. For instance, here's a little Lua script loadtest.lua which simply increments a global counter
variable (first initializing it to zero if the variable doesn't exist yet) and posts its current value in the console:
xxxxxxxxxx
counter = counter and counter + 1 or 0
pd.post(string.format("loadtest: counter = %d", counter))
To run this Lua code in Pd, you just need to connect the message load loadtest.lua
to pdlua
's inlet (note that you really need to specify the full filename here, there's no default suffix):
Now, each time you click on the load loadtest.lua
message, the file is reloaded and executed, resulting in some output in the console, e.g.:
xxxxxxxxxx
loadtest: counter = 0
loadtest: counter = 1
Also, you can edit the script between invocations and the new code will be loaded and used immediately. E.g., if you change counter + 1
to counter - 1
, you'll get:
xxxxxxxxxx
loadtest: counter = 0
loadtest: counter = -1
That's about all there is to say about pdlua
; it's a very simple object.
pdluax
pdluax
is a bit more elaborate and allows you to create real Pd-Lua objects with an arbitrary number of inlets, outlets, and methods. To these ends, it takes a single creation argument, the basename of a .pd_luax file. This file is a Lua script returning a function to be executed in pdluax
's own initialize
method, which contains all the usual definitions, including the object's method definitions, in its body. This function receives the object's self
as well as all the extra arguments pdluax
was invoked with, and should return true
if creation of the object succeeded.
For instance, here's a simplified version of our foo
counter object, rewritten as a .pd_luax file, to be named foo.pd_luax:
xxxxxxxxxx
return function (self, sel, atoms)
self.inlets = 1
self.outlets = 1
self.counter = type(atoms[1]) == "number" and atoms[1] or 0
self.step = type(atoms[2]) == "number" and atoms[2] or 1
function self:in_1_bang()
self:outlet(1, "float", {self.counter})
self.counter = self.counter + self.step
end
return true
end
Note the colon syntax self:in_1_bang()
. This adds the bang method directly to the self
object rather than its class, which is pdluax
. (We obviously don't want to modify the class itself, which may be used to create any number of different kinds of objects, each with their own collection of methods.) Also note that the outer function is "anonymous" (nameless) here; you can name it, but there's usually no need to do that, because this function will be executed just once, when the corresponding pdluax
object is created. Another interesting point to mention here is that this approach of including all the object's method definitions in its initialization method works with regular .pd_lua objects, too; try it!
In the patch, we invoke a .pd_luax object by specifying the basename of its script file as pdluax
's first argument, adding any additional creation arguments that the object itself might need:
These pdluax foo
objects work just the same as their regular foo
counterparts, but there's an important difference: The code in foo.pd_luax is loaded every time you create a new pdluax foo
object. Thus you can easily modify that file and just add a new pdluax foo
object to have it run the latest version of your code. For instance, in foo.pd_luax take the line that reads:
xxxxxxxxxx
self.counter = self.counter + self.step
Now change that +
operator to -
:
xxxxxxxxxx
self.counter = self.counter - self.step
Don't forget to save your edits, then go back to the patch and recreate the pdluax foo
object on the left. The quickest way to do that is to just delete the object, then use Pd's "Undo" operation, Ctrl+Z. Et voilà: the new object now decrements the counter rather than incrementing it. Also note that the other object on the right still runs the old code which increments the counter; thus you will have to give that object the same treatment if you want to update it, too.
While pdluax
was considered Pd-Lua's main workhorse for live coding in the past, it has its quirks. Most notably, the syntax is different from regular object definitions, so you have to change the code if you want to turn it into a .pd_lua file. Also, having to recreate an object to reload the script file is quite disruptive (it resets the internal state of the object), and may leave objects in an inconsistent state (different objects may use various different versions of the same script file). Sometimes this may be what you want, but it makes pdluax
somewhat difficult to use. It's not really tailored for interactive development, but it shines if you need a specialized tool for changing your objects on a whim in a live situation.
Fortunately, if you're not content with Pd-Lua's traditional facilities for live coding, it's easy to roll your own using the internal dofile
method, which is discussed in the next subsection.
dofile and dofilex
So let's discuss how to use dofile
in a direct fashion. Actually, we're going to use its companion dofilex
here, which works the same as dofile
, but loads Lua code relative to the "externdir" of the class (the directory of the .pd_lua file) rather than the directory of the Pd canvas with the pdlua object, which is what dofile
does. Normally, this won't make much of a difference, but it will matter if Lua class names are specified using relative pathnames, such as ../foo
or bar/baz
. Since we're reloading class definitions here, it's better to use dofilex
so that our objects don't break if we move things about.
The method we sketch out below is really simple and doesn't have any of the drawbacks of the pdluax
object, but you still have to add a small amount of boilerplate code to your existing object definition. Here is how dofilex
is invoked:
self:dofilex(scriptname)
: This loads the given Lua script, like Lua's loadfile
, but also performs a search on Pd's path to locate the file, and finally executes the file if it was loaded successfully. Note that self
must be a valid Pd-Lua object, which is used solely to determine the externdir of the object's class, so that the script will be found if it is located there.
The return values of dofilex
are those of the Lua script, along with the path under which the script was found. If the script itself returns no value, then only the path will be returned. (We don't use any of this information in what follows, but it may be useful in more elaborate schemes. For instance, pdluax
uses the returned function to initialize the object, and the path in setting up the object's actual script name.)
Of course, dofilex
needs the name of the script file to be loaded. We could hardcode this as a string literal, but it's easier to just ask the object itself for this information. Each Pd-Lua object has a number of private member variables, among them _name
(which is the name under which the object class was registered) and _scriptname
(which is the name of the corresponding script file, usually this is just _name
with the .pd_lua
extension tacked onto it). The latter is what we need. Pd-Lua also offers a whoami()
method for this purpose, but that method just returns _scriptname
if it is set, or _name
otherwise. Regular Pd-Lua objects always have _scriptname
set, so it will do for our purposes.
Finally, we need to decide how to invoke dofilex
in our object. The easiest way to do this is to just add a message handler (i.e., an inlet method) to the object. For instance, say that the object is named foo
which is defined in the foo.pd_lua script. Then all you have to do is add something like the following definition to the script:
xxxxxxxxxx
function foo:in_1_reload()
self:dofilex(self._scriptname)
end
As we already discussed, this code uses the object's internal _scriptname
variable, and so is completely generic. You can just copy this over to any .pd_lua file, if you replace the foo
prefix with whatever the name of your actual class variable is. With that definition added, you can now just send the object a reload
message whenever you want to have its script file reloaded.
NOTE: This works because the pd.Class:new():register("foo")
call of the object only registers a new class if that object class doesn't exist yet; otherwise it just returns the existing class.
By reloading the script file, all of the object's method definitions will be overwritten, not only for the object receiving the reload
message, but for all objects of the same class, so it's sufficient to send the message to any (rather than every) object of the class. Also, existing object state (as embodied by the internal member variables of each object) will be preserved.
In general all this works pretty well, but there are some caveats, too. Note that if you delete one of the object's methods, or change its name, the old method will still hang around in the runtime class definition until you relaunch Pd. That's because reloading the script does not erase any old method definitions, it merely replaces existing and adds new ones.
Finally, keep in mind that reloading the script file does not re-execute the initialize
method. This method is only invoked when an object is instantiated. Thus, in particular, reloading the file won't change the number of inlets and outlets of an existing object. Newly created objects will pick up the changes in initialize
, though, and have the proper number of inlets and outlets if those member variables were changed.
Let's give this a try, using luatab.pd_lua from the "Using arrays and tables" section as an example. In fact, that's a perfect showcase for live coding, since we want to be able to change the definition of the waveform function f
in luatab:in_1_float
on the fly. Just add the following code to the end of luatab.pd_lua:
xxxxxxxxxx
function luatab:in_1_reload()
self:dofilex(self._scriptname)
end
Now launch the luatab.pd patch and connect a reload
message to the luatab wave
object, like so:
Next change the wavetable function to whatever you want, e.g.:
xxxxxxxxxx
local function f(x)
return math.sin(2*math.pi*freq*x)+1/3*math.sin(2*math.pi*3*freq*x)
end
Return to the patch, click the reload
message, and finally reenter the frequency value, so that the waveform gets updated:
pdx.lua
The method sketched out in the preceding subsection works well enough for simple patches. However, having to manually wire up the reload
message to one object of each class that you're editing is still quite cumbersome. In a big patch, which is being changed all the time, this quickly becomes unwieldy. Wouldn't it be nice if we could equip each object with a special receiver, so that we can just click a message somewhere in the patch to reload a given class, or even all Pd-Lua objects at once? Or even send that message via the pdsend
program, e.g., from the text editor in which you edit the Lua source of your object?
Well, all this is in fact possible, but the implementation is a bit too involved to fully present here. So we have provided this in a separate pdx.lua module, which you can find in the sources accompanying this tutorial for your perusal. As of Pd-Lua 0.12.8, pdx.lua is pre-loaded and all the required setup is performed automatically. You only have to add a message like the following to your patch, which goes to the special pdluax
receiver (note that this is unrelated to the pdluax
object discussed previously, it just incidentally uses the same name):
xxxxxxxxxx
; pdluax reload
When clicked, this just reloads all Pd-Lua objects in the patch. You can also specify the class to be reloaded (the receiver matches this against each object's class name):
xxxxxxxxxx
; pdluax reload foo
Or maybe name several classes, like so:
xxxxxxxxxx
; pdluax reload foo, reload bar
You get the idea. Getting set up for remote control via pdsend
isn't much harder. E.g., let's say that we use UDP port 4711 on localhost for communicating with Pd, then you just need to connect netreceive 4711 1
to the pdluax
receiver in a suitable way. Let's use the luatab.pd_lua object from the previous subsection as an example. You can remove the in_1_reload
handler from that script -- it's no longer needed, as pdx.lua now dispatches the reload
messages for us. Here's how the revised patch looks like:
This doesn't look any simpler than before, but it also does a whole lot more. Clicking the message not just reloads the luatab
script, but any Lua object you have running, in any of the patches you have opened. And you can now use pdsend 4711 localhost udp
to reload your Lua objects from literally anywhere. Any decent code editor will let you bind a keyboard command which does this for you. Myself, I'm a die-hard Emacs fan, so I've included a little elisp module pd-remote.el which shows how to do this. Once you've added this to your .emacs, you can just type Ctrl+C Ctrl+K in any Lua buffer to make Pd reload your Lua scripts after editing them. It doesn't get much easier than that.
In addition, I've provided a little abstraction named pd-remote.pd which takes care of adding the netreceive
and messaging bits and also looks much tidier in your patches. Using the abstraction is easy: Insert pd-remote
into the patch you're working on, and (optionally) connect a pdluax reload
message (without the ;
prefix) to the inlet of the abstraction; or use something like pdluax reload foo
to reload a specific object class. Now you can just click on that message to reload your script files, and the abstraction will also respond to such messages on port 4711 (the port number can be changed in the abstraction if needed). Here's how that looks like in a patch:
NOTE: To make Pd find the pd-remote.pd abstraction without having to copy it to your project directory, you can add the pdlua external directory (which is where the abstraction gets installed) to your Pd library path, either in your Pd setup, or inside the patch with a declare -stdpath
object, as shown above.
The pd-remote.el file can be installed in your Emacs site-lisp directory if needed. However, the easiest way to install it is from MELPA, a large repository of Emacs packages. Please also check the pd-remote repository on GitHub for the latest pd-remote version and further details. This also includes a pointer to a Visual Studio Code extension written by Baris Altun which can be used as a replacement for pd-remote.el if you prefer VS Code for editing.
And here's a little gif showing the above patch in action. You may want to watch this in Typora or your favorite web browser to make the animation work.
So there you have it: Not one, not two, but three different ways to live-code with Pd-Lua (or four, if you count in the pdlua
object). pdx.lua certainly is the most advanced and user-friendly solution among these, but you can choose whatever best fits your purpose and is the most convenient for you.
Object reinitialization in pdx.lua
If pdx.lua reloads a script file, it normally does not run the initialize
method. This is by design, as we want the reload process to be as smooth as possible while running a patch, and invoking the initialize
method could potentially be quite disruptive, as it usually reinitializes all your member variables.
However, pdx.lua has another trick up its sleeve if you do need some kind of custom reinitialization. There are two callback methods that you can implement, prereload
and postreload
which will be invoked immediately before and after reloading the script file, respectively. Either method can be used to reinitialize your objects during reloading in any desired way. The only difference between the two methods is that prereload
still runs in the old script, while postreload
executes the new code which has just been loaded. Typically you'd use prereload
to perform any required bookkeeping or state-saving before the script gets loaded, and postreload
for custom initialization afterwards.
In particular, these callbacks can change any member variables, either directly or by invoking other methods. The most important use cases probably are to change the inlets
and outlets
variables, and to add a paint
method, which can be done on the fly to reconfigure your objects accordingly. To these ends, you can just call the initialize
method from postreload
. To demonstrate this, in the tutorial examples you'll find a pdxtest.pd patch and pdxtest~.pd_lua script. The script has the following reload
method:
xxxxxxxxxx
function pdxtest:postreload()
-- stuff to do post-reload goes here
pd.post("Reloaded!")
-- instead of doing a full initialization, you could also just change the
-- number of inlets and outlets here
self:initialize()
end
Now, if you need to change the number of inlets and outlets of the object, you can just modify the definitions of inlets
and outlets
in the script's initialize
method and reload. Easy as pie. Try it! Instructions can be found in the script.
Live coding and dsp
One caveat about using any of the above live-coding solutions in conjunction with Pd-Lua's signal processing capabilities is in order. When the Lua code of an object class gets reloaded, the existing code is replaced immediately. There isn't any kind of automatic "cross-fade" between old and new code. If you change the perform
method of that class, there may well be discontinuities in the generated output signals which result in audible clicks. This won't matter much if you're just developing an object in your studio. But live on stage you may want to avoid this -- unless you accept or even cherish such glitches as part of your live performance.
There are ways to work around this issue, however. To demonstrate this, the tutorial examples include the following live-xfade.pd patch:
The foo~
and bar~
objects in this example are essentially the same, with some minor variations in the sound generation parameters. The particular sounds in this example are not important, each object just outputs a random walk of sine waves of varying frequencies with some phase distortion. But they will produce clicks when switching them abruptly, thus we need a smooth cross-fade between the two sound sources. This is handled by the luaxfade~
object from the Signals section.
What's special here is that the transitions are being triggered automatically, by the received reload messages. By these means, you can edit, say, the foo~
object while the bar~
object is playing, then save your edits and send a reload
message. At this point the new code for foo~
is loaded while the cross-fade from bar~
to foo~
is initiated at the same time.
This method obviously requires some preparation and diligence when being used live on stage. Having some kind of automatic cross-fade functionality for dsp objects baked into Pd-Lua's run-time system would make this a lot easier. Maybe this can be provided by pdx.lua in a future release.
Conclusion
Congratulations! If you made it this far, you should have learned more than enough to start using Pd-Lua successfully for your own projects. You should also be able to read and understand the many examples in the Pd-Lua distribution, which illustrate all the various features in much more detail than we could muster in this introduction. You can find these in the examples folder, both in the Pd-Lua sources and the pdlua folder of your Pd installation.
The examples accompanying this tutorial (including the pdx.lua, pdlua-remote.el and pdlua-remote.pd files mentioned at the end of the pdx.lua section) are also available for your perusal in the examples subdirectory of the folder where you found this document.
Finally, I'd like to thank Claude Heiland-Allen for creating such an amazing tool, it makes programming Pd externals really easy and fun. Kudos also to Roberto Ierusalimschy for Lua, which for me is one of the best-designed, easiest to learn, and most capable multi-paradigm scripting languages there are today, while also being fast, simple, and light-weight.
+ if tip_x ~= self.tip_x or tip_y ~= self.tip_y then
self.tip_x = tip_x
self.tip_y = tip_y
self:in_1_bang()
self:repaint()
end
end
And here's the same patch again, which now lets us drag the hand to change the phase value:
Now that our dial object is basically finished, let's do something interesting with it. The most obvious thing is to just turn it into a clock (albeit one with just a seconds hand) counting off the seconds. For that we just need to add a metro object which increments the phase angle and sends the value to the dial each second:
Pd lets us store the phase angle in a named variable (v phase
) which can be recalled in an expr
object doing the necessary calculations. The expr
object sends the computed value to the phase
receiver, which updates both the variable and the upper numbox, and the numbox then updates the dial. Note that we also set the variable whenever the dial outputs a new value, so you can also drag around the hand to determine the starting phase. And we added a 0
message to reset the hand to the 12 o'clock home position when needed.
Here's another little example, rather useless but fun, simulating a speedometer which just randomly moves the needle left and right:
I'm sure you can imagine many more creative uses for this simple but surprisingly versatile little GUI object, which we did in just a few lines of fairly simple Lua code. Have fun with it! An extended version of this object, which covers some more features of the graphics API that we didn't discuss here to keep things simple, can be found as dial.pd and dial.pd_lua in the tutorial examples:
The extended example adds messages for resizing the object and setting colors, and also shows how to save and restore object state in the creation arguments using the set_args()
method mentioned at the beginning of this section. The accompanying patch covers all the examples we discussed here, and adds a third example showing how to utilize our dial object as a dB meter.
I've been telling you all along that in order to make Pd-Lua pick up changes you made to your .pd_lua files, you have to relaunch Pd and reload your patches. Well, as you probably guessed by now, this isn't actually true. So in this section we are going to cover Pd-Lua's live coding features, which let you modify your sources and have Pd-Lua reload them on the fly, without ever exiting the Pd environment. This rapid incremental style of development is one of the hallmark features of dynamic interactive programming environments like Pd and Lua. Musicians also like to employ it to modify their programs live on stage, which is where the term "live coding" comes from.
I've kept this topic for the final section of this guide, because it is somewhat advanced, and there are several different (traditional and new) methods available which differ in capabilities and ease of use. However, in modern Pd-Lua versions there is one preferred method which rules them all, so if you want to cut to the chase as quickly as possible, then feel free to just skip ahead to the pdx.lua section now.
If you're still here, then you probably want to learn about the other methods, too. So in the following we first describe the predefined Pd-Lua object classes pdlua
and pdluax
, so that you know the "traditional" live-coding instruments that Pd-Lua had on offer for a long time. We also discuss how to add a reload
message to your existing object definitions. This is quite easy to do by directly employing Pd-Lua's dofile
function, which is also what both pdlua
and pdluax
use internally.
These methods all work with pretty much any Pd-Lua version out there, but require a little bit of setup which can get time-consuming and error-prone if you're dealing with large patches involving a lot of different Lua objects.
That's why Pd-Lua nowadays includes an extension module called pdx.lua that "just works" out of the box and automatizes everything, so that you only have to put a simple reload
message in your main patch and be done with it. This is also the method we recommend, to novices and expert users alike. We describe it last so that you can also gather a good understanding of Pd-Lua's traditional live coding methods, and learn to appreciate them. These are still used in many older scripts, and Pd-Lua will continue to support them for backward compatibility.
The pdlua
object accepts a single kind of message of the form load filename
on its single inlet, which causes the given Lua file to be loaded and executed. Since pdlua
has no outlets, its uses are rather limited. However, it does enable you to load global Lua definitions and execute an arbitrary number of statements, e.g., to post some text to the console or transmit messages to Pd receivers using the corresponding Pd-Lua functions. For instance, here's a little Lua script loadtest.lua which simply increments a global counter
variable (first initializing it to zero if the variable doesn't exist yet) and posts its current value in the console:
xxxxxxxxxx
counter = counter and counter + 1 or 0
pd.post(string.format("loadtest: counter = %d", counter))
To run this Lua code in Pd, you just need to connect the message load loadtest.lua
to pdlua
's inlet (note that you really need to specify the full filename here, there's no default suffix):
Now, each time you click on the load loadtest.lua
message, the file is reloaded and executed, resulting in some output in the console, e.g.:
xxxxxxxxxx
loadtest: counter = 0
loadtest: counter = 1
Also, you can edit the script between invocations and the new code will be loaded and used immediately. E.g., if you change counter + 1
to counter - 1
, you'll get:
xxxxxxxxxx
loadtest: counter = 0
loadtest: counter = -1
That's about all there is to say about pdlua
; it's a very simple object.
pdluax
is a bit more elaborate and allows you to create real Pd-Lua objects with an arbitrary number of inlets, outlets, and methods. To these ends, it takes a single creation argument, the basename of a .pd_luax file. This file is a Lua script returning a function to be executed in pdluax
's own initialize
method, which contains all the usual definitions, including the object's method definitions, in its body. This function receives the object's self
as well as all the extra arguments pdluax
was invoked with, and should return true
if creation of the object succeeded.
For instance, here's a simplified version of our foo
counter object, rewritten as a .pd_luax file, to be named foo.pd_luax:
xxxxxxxxxx
return function (self, sel, atoms)
self.inlets = 1
self.outlets = 1
self.counter = type(atoms[1]) == "number" and atoms[1] or 0
self.step = type(atoms[2]) == "number" and atoms[2] or 1
function self:in_1_bang()
self:outlet(1, "float", {self.counter})
self.counter = self.counter + self.step
end
return true
end
Note the colon syntax self:in_1_bang()
. This adds the bang method directly to the self
object rather than its class, which is pdluax
. (We obviously don't want to modify the class itself, which may be used to create any number of different kinds of objects, each with their own collection of methods.) Also note that the outer function is "anonymous" (nameless) here; you can name it, but there's usually no need to do that, because this function will be executed just once, when the corresponding pdluax
object is created. Another interesting point to mention here is that this approach of including all the object's method definitions in its initialization method works with regular .pd_lua objects, too; try it!
In the patch, we invoke a .pd_luax object by specifying the basename of its script file as pdluax
's first argument, adding any additional creation arguments that the object itself might need:
These pdluax foo
objects work just the same as their regular foo
counterparts, but there's an important difference: The code in foo.pd_luax is loaded every time you create a new pdluax foo
object. Thus you can easily modify that file and just add a new pdluax foo
object to have it run the latest version of your code. For instance, in foo.pd_luax take the line that reads:
xxxxxxxxxx
self.counter = self.counter + self.step
Now change that +
operator to -
:
xxxxxxxxxx
self.counter = self.counter - self.step
Don't forget to save your edits, then go back to the patch and recreate the pdluax foo
object on the left. The quickest way to do that is to just delete the object, then use Pd's "Undo" operation, Ctrl+Z. Et voilà: the new object now decrements the counter rather than incrementing it. Also note that the other object on the right still runs the old code which increments the counter; thus you will have to give that object the same treatment if you want to update it, too.
While pdluax
was considered Pd-Lua's main workhorse for live coding in the past, it has its quirks. Most notably, the syntax is different from regular object definitions, so you have to change the code if you want to turn it into a .pd_lua file. Also, having to recreate an object to reload the script file is quite disruptive (it resets the internal state of the object), and may leave objects in an inconsistent state (different objects may use various different versions of the same script file). Sometimes this may be what you want, but it makes pdluax
somewhat difficult to use. It's not really tailored for interactive development, but it shines if you need a specialized tool for changing your objects on a whim in a live situation.
Fortunately, if you're not content with Pd-Lua's traditional facilities for live coding, it's easy to roll your own using the internal dofile
method, which is discussed in the next subsection.
So let's discuss how to use dofile
in a direct fashion. Actually, we're going to use its companion dofilex
here, which works the same as dofile
, but loads Lua code relative to the "externdir" of the class (the directory of the .pd_lua file) rather than the directory of the Pd canvas with the pdlua object, which is what dofile
does. Normally, this won't make much of a difference, but it will matter if Lua class names are specified using relative pathnames, such as ../foo
or bar/baz
. Since we're reloading class definitions here, it's better to use dofilex
so that our objects don't break if we move things about.
The method we sketch out below is really simple and doesn't have any of the drawbacks of the pdluax
object, but you still have to add a small amount of boilerplate code to your existing object definition. Here is how dofilex
is invoked:
self:dofilex(scriptname)
: This loads the given Lua script, like Lua's loadfile
, but also performs a search on Pd's path to locate the file, and finally executes the file if it was loaded successfully. Note that self
must be a valid Pd-Lua object, which is used solely to determine the externdir of the object's class, so that the script will be found if it is located there.
The return values of dofilex
are those of the Lua script, along with the path under which the script was found. If the script itself returns no value, then only the path will be returned. (We don't use any of this information in what follows, but it may be useful in more elaborate schemes. For instance, pdluax
uses the returned function to initialize the object, and the path in setting up the object's actual script name.)
Of course, dofilex
needs the name of the script file to be loaded. We could hardcode this as a string literal, but it's easier to just ask the object itself for this information. Each Pd-Lua object has a number of private member variables, among them _name
(which is the name under which the object class was registered) and _scriptname
(which is the name of the corresponding script file, usually this is just _name
with the .pd_lua
extension tacked onto it). The latter is what we need. Pd-Lua also offers a whoami()
method for this purpose, but that method just returns _scriptname
if it is set, or _name
otherwise. Regular Pd-Lua objects always have _scriptname
set, so it will do for our purposes.
Finally, we need to decide how to invoke dofilex
in our object. The easiest way to do this is to just add a message handler (i.e., an inlet method) to the object. For instance, say that the object is named foo
which is defined in the foo.pd_lua script. Then all you have to do is add something like the following definition to the script:
xxxxxxxxxx
function foo:in_1_reload()
self:dofilex(self._scriptname)
end
As we already discussed, this code uses the object's internal _scriptname
variable, and so is completely generic. You can just copy this over to any .pd_lua file, if you replace the foo
prefix with whatever the name of your actual class variable is. With that definition added, you can now just send the object a reload
message whenever you want to have its script file reloaded.
NOTE: This works because the pd.Class:new():register("foo")
call of the object only registers a new class if that object class doesn't exist yet; otherwise it just returns the existing class.
By reloading the script file, all of the object's method definitions will be overwritten, not only for the object receiving the reload
message, but for all objects of the same class, so it's sufficient to send the message to any (rather than every) object of the class. Also, existing object state (as embodied by the internal member variables of each object) will be preserved.
In general all this works pretty well, but there are some caveats, too. Note that if you delete one of the object's methods, or change its name, the old method will still hang around in the runtime class definition until you relaunch Pd. That's because reloading the script does not erase any old method definitions, it merely replaces existing and adds new ones.
Finally, keep in mind that reloading the script file does not re-execute the initialize
method. This method is only invoked when an object is instantiated. Thus, in particular, reloading the file won't change the number of inlets and outlets of an existing object. Newly created objects will pick up the changes in initialize
, though, and have the proper number of inlets and outlets if those member variables were changed.
Let's give this a try, using luatab.pd_lua from the "Using arrays and tables" section as an example. In fact, that's a perfect showcase for live coding, since we want to be able to change the definition of the waveform function f
in luatab:in_1_float
on the fly. Just add the following code to the end of luatab.pd_lua:
xxxxxxxxxx
function luatab:in_1_reload()
self:dofilex(self._scriptname)
end
Now launch the luatab.pd patch and connect a reload
message to the luatab wave
object, like so:
Next change the wavetable function to whatever you want, e.g.:
x
local function f(x)
return math.sin(2*math.pi*freq*x)+1/3*math.sin(2*math.pi*3*freq*x)
end
Return to the patch, click the reload
message, and finally reenter the frequency value, so that the waveform gets updated:
The method sketched out in the preceding subsection works well enough for simple patches. However, having to manually wire up the reload
message to one object of each class that you're editing is still quite cumbersome. In a big patch, which is being changed all the time, this quickly becomes unwieldy. Wouldn't it be nice if we could equip each object with a special receiver, so that we can just click a message somewhere in the patch to reload a given class, or even all Pd-Lua objects at once? Or even send that message via the pdsend
program, e.g., from the text editor in which you edit the Lua source of your object?
Well, all this is in fact possible, but the implementation is a bit too involved to fully present here. So we have provided this in a separate pdx.lua module, which you can find in the sources accompanying this tutorial for your perusal. As of Pd-Lua 0.12.8, pdx.lua is pre-loaded and all the required setup is performed automatically. You only have to add a message like the following to your patch, which goes to the special pdluax
receiver (note that this is unrelated to the pdluax
object discussed previously, it just incidentally uses the same name):
xxxxxxxxxx
; pdluax reload
When clicked, this just reloads all Pd-Lua objects in the patch. You can also specify the class to be reloaded (the receiver matches this against each object's class name):
xxxxxxxxxx
; pdluax reload foo
Or maybe name several classes, like so:
xxxxxxxxxx
; pdluax reload foo, reload bar
You get the idea. Getting set up for remote control via pdsend
isn't much harder. E.g., let's say that we use UDP port 4711 on localhost for communicating with Pd, then you just need to connect netreceive 4711 1
to the pdluax
receiver in a suitable way. Let's use the luatab.pd_lua object from the previous subsection as an example. You can remove the in_1_reload
handler from that script -- it's no longer needed, as pdx.lua now dispatches the reload
messages for us. Here's how the revised patch looks like:
This doesn't look any simpler than before, but it also does a whole lot more. Clicking the message not just reloads the luatab
script, but any Lua object you have running, in any of the patches you have opened. And you can now use pdsend 4711 localhost udp
to reload your Lua objects from literally anywhere. Any decent code editor will let you bind a keyboard command which does this for you. Myself, I'm a die-hard Emacs fan, so I've included a little elisp module pd-remote.el which shows how to do this. Once you've added this to your .emacs, you can just type Ctrl+C Ctrl+K in any Lua buffer to make Pd reload your Lua scripts after editing them. It doesn't get much easier than that.
In addition, I've provided a little abstraction named pd-remote.pd which takes care of adding the netreceive
and messaging bits and also looks much tidier in your patches. Using the abstraction is easy: Insert pd-remote
into the patch you're working on, and (optionally) connect a pdluax reload
message (without the ;
prefix) to the inlet of the abstraction; or use something like pdluax reload foo
to reload a specific object class. Now you can just click on that message to reload your script files, and the abstraction will also respond to such messages on port 4711 (the port number can be changed in the abstraction if needed). Here's how that looks like in a patch:
NOTE: To make Pd find the pd-remote.pd abstraction without having to copy it to your project directory, you can add the pdlua external directory (which is where the abstraction gets installed) to your Pd library path, either in your Pd setup, or inside the patch with a declare -stdpath
object, as shown above.
The pd-remote.el file can be installed in your Emacs site-lisp directory if needed. However, the easiest way to install it is from MELPA, a large repository of Emacs packages. Please also check the pd-remote repository on GitHub for the latest pd-remote version and further details. This also includes a pointer to a Visual Studio Code extension written by Baris Altun which can be used as a replacement for pd-remote.el if you prefer VS Code for editing.
And here's a little gif showing the above patch in action. You may want to watch this in Typora or your favorite web browser to make the animation work.
So there you have it: Not one, not two, but three different ways to live-code with Pd-Lua (or four, if you count in the pdlua
object). pdx.lua certainly is the most advanced and user-friendly solution among these, but you can choose whatever best fits your purpose and is the most convenient for you.
If pdx.lua reloads a script file, it normally does not run the initialize
method. This is by design, as we want the reload process to be as smooth as possible while running a patch, and invoking the initialize
method could potentially be quite disruptive, as it usually reinitializes all your member variables.
However, pdx.lua has another trick up its sleeve if you do need some kind of custom reinitialization. There are two callback methods that you can implement, prereload
and postreload
which will be invoked immediately before and after reloading the script file, respectively. Either method can be used to reinitialize your objects during reloading in any desired way. The only difference between the two methods is that prereload
still runs in the old script, while postreload
executes the new code which has just been loaded. Typically you'd use prereload
to perform any required bookkeeping or state-saving before the script gets loaded, and postreload
for custom initialization afterwards.
In particular, these callbacks can change any member variables, either directly or by invoking other methods. The most important use cases probably are to change the inlets
and outlets
variables, and to add a paint
method, which can be done on the fly to reconfigure your objects accordingly. To these ends, you can just call the initialize
method from postreload
. To demonstrate this, in the tutorial examples you'll find a pdxtest.pd patch and pdxtest~.pd_lua script. The script has the following reload
method:
xxxxxxxxxx
function pdxtest:postreload()
-- stuff to do post-reload goes here
pd.post("Reloaded!")
-- instead of doing a full initialization, you could also just change the
-- number of inlets and outlets here
self:initialize()
end
Now, if you need to change the number of inlets and outlets of the object, you can just modify the definitions of inlets
and outlets
in the script's initialize
method and reload. Easy as pie. Try it! Instructions can be found in the script.
One caveat about using any of the above live-coding solutions in conjunction with Pd-Lua's signal processing capabilities is in order. When the Lua code of an object class gets reloaded, the existing code is replaced immediately. There isn't any kind of automatic "cross-fade" between old and new code. If you change the perform
method of that class, there may well be discontinuities in the generated output signals which result in audible clicks. This won't matter much if you're just developing an object in your studio. But live on stage you may want to avoid this -- unless you accept or even cherish such glitches as part of your live performance.
There are ways to work around this issue, however. To demonstrate this, the tutorial examples include the following live-xfade.pd patch:
The foo~
and bar~
objects in this example are essentially the same, with some minor variations in the sound generation parameters. The particular sounds in this example are not important, each object just outputs a random walk of sine waves of varying frequencies with some phase distortion. But they will produce clicks when switching them abruptly, thus we need a smooth cross-fade between the two sound sources. This is handled by the luaxfade~
object from the Signals section.
What's special here is that the transitions are being triggered automatically, by the received reload messages. By these means, you can edit, say, the foo~
object while the bar~
object is playing, then save your edits and send a reload
message. At this point the new code for foo~
is loaded while the cross-fade from bar~
to foo~
is initiated at the same time.
This method obviously requires some preparation and diligence when being used live on stage. Having some kind of automatic cross-fade functionality for dsp objects baked into Pd-Lua's run-time system would make this a lot easier. Maybe this can be provided by pdx.lua in a future release.
Congratulations! If you made it this far, you should have learned more than enough to start using Pd-Lua successfully for your own projects. You should also be able to read and understand the many examples in the Pd-Lua distribution, which illustrate all the various features in much more detail than we could muster in this introduction. You can find these in the examples folder, both in the Pd-Lua sources and the pdlua folder of your Pd installation.
The examples accompanying this tutorial (including the pdx.lua, pdlua-remote.el and pdlua-remote.pd files mentioned at the end of the pdx.lua section) are also available for your perusal in the examples subdirectory of the folder where you found this document.
Finally, I'd like to thank Claude Heiland-Allen for creating such an amazing tool, it makes programming Pd externals really easy and fun. Kudos also to Roberto Ierusalimschy for Lua, which for me is one of the best-designed, easiest to learn, and most capable multi-paradigm scripting languages there are today, while also being fast, simple, and light-weight.