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 that's needed is
a `[; pdluax reload(` message in your patch, or you can use the
pd-remote.pd abstraction, as described in the tutorial.

To make it possible to load pdx.lua from pd.lua (and possibly other
extension modules in the future), the pdlua external directory is now
always on Lua's `package.path`. Hence it was possible to revert
pd._setrequirepath() to take only one argument.

Note that if you don't want this, you can still disable pdx.lua globally
by commenting out the following line near the end of pd.lua:

    pdx = require 'pdx'

Or you can call pdx.unreload() in the initialize() method of your
object. But this shouldn't be necessary. pdx.lua incurs minimal
overhead, and even with pdx.lua pre-loaded, you can still use any of the
other live-coding approaches described in the tutorial if you prefer.
  • Loading branch information
agraef committed Aug 30, 2024
1 parent b4197fd commit fa18655
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 fa18655

Please sign in to comment.