Skip to content

Commit

Permalink
Pre-load pdx.lua and enable live-coding support by default.
Browse files Browse the repository at this point in the history
Following up on rev. 7447be5, pdx.lua is now pre-loaded in pd.lua, and
all objects have live-coding enabled automatically, by calling
pdx.reload() immediately before intiialize().

Thus all you need is a `[; pdluax reload(` message in your patch, and
Bob's your uncle. Or you can add an instance of the pd-remote.pd
abstraction, as described in the tutorial, if you also want to remotely
control script reloads through your editor.

You can still disable this globally by commenting out the following line
near the end of pd.lua:

    pdx = require 'pdx'

Or you can disable reloads on a per-object basis by calling
pdx.unreload() in the intiialize() method. But why would you want to?
pdx.lua is well-tested at this point, incurs minimal overhead, and is by
far the easiest live-coding solution for pd-lua. Also, even with pdx.lua
pre-loaded, you can still use any of the other live-coding approaches
described in the tutorial if you prefer.

To make it possible to load pdx.lua from pd.lua (and possibly other
extension modules in the future), the extra/pdlua directory is now
always on Lua's `package.path`. Hence it was possible to revert
pd._setrequirepath() to take only one argument. (The present code won't
modify package.cpath, however. But this is fine with pdx.lua which is a
pure Lua module. And we can still add to package.cpath if a future
extension requires mixed Lua+C.)
  • Loading branch information
agraef committed Aug 30, 2024
1 parent b4197fd commit fda9cf0
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 16 deletions.
21 changes: 16 additions & 5 deletions pd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ pd._loadpath = ""
pd._currentpath = ""

-- add a path to Lua's "require" search paths
pd._setrequirepath = function(path, pdlua_path)
pd._setrequirepath = function(path)
pd._packagepath = package.path
pd._packagecpath = package.cpath
if (pd._iswindows) then
package.path = path .. "\\?;" .. path .. "\\?.lua;" .. pdlua_path .. "\\?;" .. pdlua_path .. "\\?.lua;" .. package.path
package.cpath = path .. "\\?.dll;" .. pdlua_path .. "\\?.dll;" .. package.cpath
package.path = path .. "\\?;" .. path .. "\\?.lua;" .. package.path
package.cpath = path .. "\\?.dll;" .. package.cpath
else
package.path = path .. "/?;" .. path .. "/?.lua;" .. pdlua_path .. "/?;" .. pdlua_path .. "/?.lua;" .. package.path
package.cpath = path .. "/?.so;" .. pdlua_path .. "/?.so;" .. package.cpath
package.path = path .. "/?;" .. path .. "/?.lua;" .. package.path
package.cpath = path .. "/?.so;" .. package.cpath
end
end

Expand Down Expand Up @@ -344,6 +344,9 @@ function pd.Class:construct(sel, atoms)
self.inlets = 0
self.outlets = 0
self._canvaspath = pd._canvaspath(self._object) .. "/"
if pdx then
pdx.reload(self)
end
if self:initialize(sel, atoms) then
pd._createinlets(self._object, self.inlets)
pd._createoutlets(self._object, self.outlets)
Expand All @@ -353,6 +356,9 @@ function pd.Class:construct(sel, atoms)
self:postinitialize()
return self
else
if pdx then
pdx.unreload(self)
end
return nil
end
end
Expand Down Expand Up @@ -517,4 +523,9 @@ end
DATA = 0
SIGNAL = 1
Colors = {background = 0, foreground = 1, outline = 2}

-- pre-load pdx.lua (live coding support); if you don't want this, just
-- comment out the line below
pdx = require 'pdx'

-- fin pd.lua
34 changes: 31 additions & 3 deletions pdlua.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ void initialise_lua_state()
// In plugdata we're linked statically and thus c_externdir is empty.
// So we pass a data directory to the setup function instead and store it here.
// ag: Renamed to pdlua_datadir since we also need this in vanilla when
// setting up the Lua search path when loading a pd_lua file.
// setting up Lua's package.path.
char pdlua_datadir[MAXPDSTRING];
#if PLUGDATA
// Hook to inform plugdata which class names are lua objects
Expand Down Expand Up @@ -2037,6 +2037,29 @@ static int pdlua_error(lua_State *L)
return 0;
}

static void pdlua_packagepath(lua_State *L, const char *path)
{
PDLUA_DEBUG("pdlua_packagepath: stack top %d", lua_gettop(L));
lua_getglobal(L, "package");
lua_pushstring(L, "path");
lua_gettable(L, -2);
const char *packagepath = lua_tostring(L, -1);
char *buf = malloc(2*strlen(path)+20+strlen(packagepath));
if (!buf) return;
#ifdef _WIN32
sprintf(buf, "%s\\?;%s\\?.lua;%s", path, path, packagepath);
#else
sprintf(buf, "%s/?;%s/?.lua;%s", path, path, packagepath);
#endif
lua_pop(L, 1);
lua_pushstring(L, "path");
lua_pushstring(L, buf);
lua_settable(L, -3);
free(buf);
lua_pop(L, 1);
PDLUA_DEBUG("pdlua_packagepath: end. stack top %d", lua_gettop(L));
}

static void pdlua_setrequirepath
( /* FIXME: documentation (is this of any use at all?) */
lua_State *L,
Expand All @@ -2048,8 +2071,7 @@ static void pdlua_setrequirepath
lua_pushstring(L, "_setrequirepath");
lua_gettable(L, -2);
lua_pushstring(L, path);
lua_pushstring(L, pdlua_datadir);
if (lua_pcall(L, 2, 0, 0) != 0)
if (lua_pcall(L, 1, 0, 0) != 0)
{
pd_error(NULL, "lua: internal error in `pd._setrequirepath': %s", lua_tostring(L, -1));
lua_pop(L, 1);
Expand Down Expand Up @@ -2579,6 +2601,12 @@ void pdlua_setup(void)
if (fd >= 0)
{ /* pd.lua was opened */
reader.fd = fd;
// We need to set up Lua's package.path here so that pdx.lua can be
// found (and possibly other pre-loaded extension modules in the
// future). Note that we can't just use pdlua_setrequirepath() here
// because it calls pd._setrequirepath in pd.lua which isn't loaded
// yet at this point.
pdlua_packagepath(__L(), pdlua_datadir);
#if LUA_VERSION_NUM < 502
result = lua_load(__L(), pdlua_reader, &reader, "pd.lua");
#else // 5.2 style
Expand Down
5 changes: 0 additions & 5 deletions pdlua/tutorial/examples/luatab.pd_lua
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
local luatab = pd.Class:new():register("luatab")

-- our own pdlua extension, needed for the reload functionality
local pdx = require 'pdx'

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
-- enable the reload callback
pdx.reload(self)
-- the name of the array/table should be in the 1st creation argument
if type(atoms[1]) == "string" then
self.tabname = atoms[1]
Expand Down
11 changes: 8 additions & 3 deletions pdlua/tutorial/examples/pdx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
pdx.lua: useful extensions to pd.lua
Copyright (C) 2020 Albert Gräf <[email protected]>
To use this in your pd-lua scripts: local pdx = require 'pdx'
Currently there's only the pdx.reload() function, which implements a kind of
remote reload functionality based on dofile and receivers, as explained in the
live coding functionality based on dofile and receivers, as explained in the
pd-lua tutorial. More may be added in the future.
This program is free software; you can redistribute it and/or
Expand All @@ -30,6 +28,13 @@ local pdx = {}
Reload functionality. Call pdx.reload() on your object to enable, and
pdx.unreload() to disable this functionality again.
NOTE: As of pd-lua 0.12.8, this module is now pre-loaded, and pdx.reload()
gets called automatically before running the initialize method of any object,
so calling pdx.reload() explicitly is no longer needed. (Old code importing
the module and doing the call will continue to work, though.) Instead, you
will now have to call pdx.unreload() in your initialize method if you want to
*disable* this feature for some reason.
pdx.reload installs a "pdluax" receiver which reloads the object's script file
when it receives the "reload" message without any arguments, or a "reload
class" message with a matching class name.
Expand Down

0 comments on commit fda9cf0

Please sign in to comment.