back to table of contents
This section explains what are external objects and libraries. It also describes everything on how to install and load them in Pure Data.
You can write your own external objects that you and others can use in their Pd applications in C or (if you're smart and brave) in C++ or FORTRAN. In the "6.externs" subdirectory of the documentation you can find simple examples of externals with their source code and test patches.
There’s also an excellent guide to writing externals project by IOhannes zmölnig at https://github.com/pure-data/externals-howto. Check also the pd-lib-builder project (a helper makefile for Pure Data external libraries by Katja Vetter) at http://github.com/pure-data/pd-lib-builder
Internal objects come as part of the Pd binary, whereas external objects are separate from it. The main Pd distribution (a.k.a. “Pd Vanilla”) also comes with a few “extra” objects that are not part of its binary. Therefore, the set of “vanilla objects” (the built-in objects in Pd) include internals and externals. Nonetheless, “externals” mostly refer objects not available in the Pd Vanilla distribution, that you need to download and install them properly so they can be loaded into Pd patches.
To get a full list of all objects in Pd Vanilla, go to the Help menu and then select List of Objects, or alternatively right click on an empty spot of a patch’s window and select “help” - this loads the help-intro.pd file (see below).
The set of externals that come with Pd are available in the ‘extra’ library and is located in a folder named “extra” inside the Pd application. These appear at the very end of the “help-intro.pd” and can also be viewed in the Help Browser menu (Help => Browser). See figure below, which shows how the browser looks in a fresh install of Pd and lists the objects in the extra folder.
An object in Pd can be either a patch - meaning a Pd file (a.k.a abstraction) - or a compiled binary (note that a binary can contain only one or several external objects, as discussed further on).
These are Pd objects compiled to binaries from programming code (like in C or C++). They have to be compiled for your operating system, which means the binaries have different extensions according to each platform. For instance:
You can have a Pd patch behave like an object by loading it into other patches - these are usually called “abstractions”. Note that some of the externals in “extra” are abstractions (for instance, rev1~ or hilbert~). Like any other Pd patch, an abstraction may contain any kind of objects (internals, compiled externals and even other abstractions).
In practical terms, an external library is a collection of external objects of any kind (abstractions or compiled objects). But when it comes to compiled objects, a library can provide several objects as a single binary pack or as a set of separate binaries (where each object has its own binary).
The “classic” library format is a single binary pack (with two or more externals), but splitting into separate binaries became a very common practice. A single external binary (not part of any set of objects) is still, technically, a library with just one object. But again, the prevailing idea is that a library is that it is just a set of objects.
It’s important to note that there are differences on how externals are loaded depending if they’re a single binary pack or a set of separate binaries (as explained in the next subsections).
Libraries can come in all sorts of ways; as only a collection of abstractions (like "list-abs"), only compiled objects, or both. It can even mix compiled externals both as a set of separate binaries and a single binary pack. Basically, any combination is possible for a set of external.
One example that combines all external options is cyclone 0.3, which provides most of its objects as a set of separate binaries, but also includes a small collection of 12 objects as a single binary pack plus a few abstractions.
Installing externals in Pd is quite simple, all you need to do is download your externals from somewhere, such as from Pd Vanilla directly, and include them in a proper folder.
Currently, when launching for the first time with a fresh install, Pd asks if you want to create a documents directory for patches that includes an “externals” subdirectory. This externals folder is where it’s advised to include external libraries and it’s automatically included in the user added search paths (under Preferences => Path), see figure below.
The figure above is a screenshot, where the “Pd” folder is created under ~/Documents, and inside it we have the externals subfolder. Even if you did not create this folder, here is where you can create it by clicking the “Reset” button under “Pd Documents Directory”.
Externals can actually be anywhere in your computer, but Pd must know where to look for them. Pd looks for files (including externals) in the user added search paths, but it also searches in other folders not listed there such as: the same folder that your patch is saved on (the Relative Path) or the Standard Paths, which are:
Officially, there’s only one ‘Standard Path’ which is the ‘extra’ folder. The others are not automatically created by Pd and are part of an old structure. Currently, the best practice is to use the default external folders or user added paths, but these other options are documented here anyway and may be useful in some edge cases.
The Global folder affects all Pure Data Applications for all users. The User-specific folder affects all Pure Data Applications for that user. And since you can have different versions of Pd installed in your system, the Application-specific folder affects only that particular Pd Application - multiple Pd applications can be of different versions (an older and a newer one or both 32-bit and 64-bit). For reference, here’s the list of the Standard Paths for all operating systems:
Since version 0.47-0, Pd Vanilla has its own external manager! This is a built in .tcl plug-in named "deken" (check https://github.com/pure-data/deken for reference). Open it by selecting the Help => Find externals tab. Then you can type the library’s name you’re looking for and hit ‘enter’ or click ‘search’. You can also look for an external name and the library that contains it might be shown. All available versions of the library specific for your operating system will be shown to you. See figure below.
When you click on the version you want, Pd asks if you want to the
external folder set in “Path => Prferences”, which should be
~/Documents/Pd/external by default. If you say yes, there is where it gets
downloaded to, but if you say no, you can specify somewhere else.
Before loading an external, we need to make sure Pd finds it. The current best practice is to use the declare object, but there are alternatives.
If the library is a single binary pack, this binary needs to be pre loaded so Pd can load its externals. This is done either with declare or manually via Preferences => Startup.
If the external library only contains abstractions or objects compiled as a set of separate binaries, Pd just needs to know its path. Again, this can be done with declare or manually via Preferences => Path, but yet another option here is to use slash declarations.
The declare object behaves quite similarly to adding search paths to the user added paths (under Preferences => Path) or adding libraries (under Preferences => Startup). The difference is that this will only work for the patch containing that contain the declare object - unlike using path/startup, which installs permanently for any patch.
Let's take for an example the ELSE library. This library contains separate binaries and abstractions, so Pd only needs to know its location 11 path, hence we use the -path flag as in [declare -path else]. This makes Pd look for a folder named else to add it to the search path.
But where does Pd look for this folder? In the locations it knows where to look (the Relative Path, the Standard Paths or the User Added Paths). So let’s say you put the ELSE library folder in “~/Documents/Pd/externals”, which is the current best practice, Pd will know to look for it there and will find it!
Now, in the case of a single external, the best practice is to include it in a folder with the same name, like the freeverb~ external. In this situation, you don’t need to add the external folder to the path. For example, if you download the freeverb~ external into “~/Documents/Pd/externals” and try to load it, the trick is that If Pd finds a ‘freeverb~’ folder, it knows it should look inside it for the actual external, so it will succeed in finding it just by that!
The -lib flag is needed for the classic Pd library format, which is a single binary pack with many externals. One such example is the zexy library. So once you’ve downloaded it, you can use [declare -lib zexy]. In the same way, Pd will search for the zexy binary in locations it knows where to look (as in “~/Documents/Pd/externals”).
Does this mean you need to also include the zexy folder path, so Pd knows to search for the zexy binary inside? Not really! Just like the freeverb~ example, if Pd finds a ‘zexy’ folder in the locations it’s searching, it knows to look for the ‘zexy’ binary there!
This is basically the same as using [declare] but it will permanently work every time Pd starts, and for any patch you open.
We’ve seen that even if you have a folder into “~/Documents/Pd/externals” you still need to tell Pd to look for it. You can manually add a User Added Paths in Preferences => Path by clicking “New”.
Another possibility is that under deken’s preferences tabs you can click once on “Should newly installed libraries be added to Pd’s search Path?”. This prompts you if you want to add a downloaded library to the user added search paths (by default, it never asks you to do it). You can also click twice so it always adds anything you download to the search path, which is not quite recommended as sometimes you’ll download a single binary pack, where adding it to the search path doesn’t really help.
In "Preferences => Startup", you load a window that says "Pd libraries to load on startup". This is where you can manually and permanently load single binary pack libraries. But since this is only needed during startup, you need to restart Pd. The startup is also used for configuring Pd in many ways, see 3.6. Preferences and startup options for reference.
As we’ve seen with ‘zexy’, it’s common that the name of the binary is the same as the library’s, so you don’t need to worry about setting the path. Another example is the ‘cyclone’ library. As previously mentioned, cyclone 0.3 is a special case that includes objects as abstractions, as a set of separate binaries and also has a set a single binary pack that loads objects with non alphanumeric names, which need to be loaded as a single binary pack (which loads objects with non alphanumeric names that need to be loaded as such to avoid issues). One particularity of cyclone is that loading its binary will also force Pd to add its path to the search paths, so you don’t need to bother adding it to the path as well in order to be able to load its abstractions or separate binaries. Another example that uses this feature is Gem , which loads as a binary pack but also includes a few abstractions that rely on the path search.
It depends on the developer, but it is a common and good practice that when you load a library, Pd’s terminal window will print something to tell us that the libraries were loaded successfully. Here’s a screenshot of the result of loading cyclone and zexy via the startup (same happens if you load them via [declare], clearly).
You can also use slash declarations to search for externals in paths that are relative to the locations Pd automatically searches for files. But this doesn’t work for single binary packs.
For instance, let’s say you’ve downloaded the ELSE library into ~/Documents/Pd/externals. Instead of using [declare -path else] or adding the ELSE folder to the user added paths manually, you can just prepend “else/“ before an object name. This will make Pd look for this object in a folder called ‘else’ in one of its search paths (which includes ~/Documents/Pd/externals) and find it! Here’s an example:
Now, what’s the difference over using [declare] or adding the folder to the user added paths? The only use case is if you have two externals with the same name from two different libraries in the same patch. With this method, you can specify which one is which!
A library name prefix may also be pertinent in the context of single binary packs. The cyclone library has a set of 12 objects with non 15 alphanumeric names, such as [>~], and uses an internal trick of adding a class creator, so creating the object as [cyclone/>~] also works. But note that the library still needs to be loaded anyway (via startup or [declare]).
There’s also the case where you can have placed single binary pack library in a folder with a different name not added to the user paths. Not that you should have done that, but a slash declaration with “folder/libname” in Startup or declare would also work for that matter.
Once you make sure Pd can load an external, this is what happens when you create it. Whenever you type the name of an object (into an "object" text box) that Pd doesn't yet know about, Pd looks for a relocatable object file, named, for instance, "profile.pd_linux". Pd looks first in the directory containing the patch, then in directories listed as user added paths, then in the standard paths. Pd will then add whatever object is found there to its "class list," which is the set of all Pd classes you can use. If all this works, Pd then attempts again to create the object you asked for, this time perhaps successfully. There is no difference between an object defined this way and an object built into Pd (an internal).
In the case of compiled externals, once the new object is loaded into
Pd, it's there for the duration of your Pd session. This means that if you
replace the binary for a new one, the object won't be updated even if you
recreate it. Hence, if you're working on a new object and decide to change it,
you have to exit and re-enter Pd to get the change to take. This is not needed
for abstractions, which get updated any time they’re replaced and reloaded.