From 267170167d52cab9e97f879d9127a1cf04f6bb58 Mon Sep 17 00:00:00 2001 From: Martin Peach Date: Tue, 15 Mar 2011 20:53:57 +0000 Subject: This is a version of Claude Heiland-Allen's lua for Pd. The objects are named pdlua and pdluax instead of lua and luax. So far it seems to work on linux. svn path=/trunk/externals/pdlua/; revision=15030 --- src/pd.lua | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 src/pd.lua (limited to 'src/pd.lua') diff --git a/src/pd.lua b/src/pd.lua new file mode 100644 index 0000000..341894f --- /dev/null +++ b/src/pd.lua @@ -0,0 +1,303 @@ +--[[ +pdlua -- a Lua embedding for Pd +Copyright (C) 2007,2008 Claude Heiland-Allen + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +--]] + +-- storage for Pd C<->Lua interaction +pd._classes = { } +pd._objects = { } +pd._clocks = { } +pd._receives = { } + +-- add a path to Lua's "require" search paths +pd._setrequirepath = function(path) + pd._packagepath = package.path + pd._packagecpath = package.cpath + if (pd._iswindows) then + package.path = path .. "\\?;" .. path .. "\\?.lua;" .. package.path + package.cpath = path .. "\\?.dll;" .. package.cpath + else + package.path = path .. "/?;" .. path .. "/?.lua;" .. package.path + package.cpath = path .. "/?.so;" .. package.cpath + end +end + +-- reset Lua's "require" search paths +pd._clearrequirepath = function() + package.path = pd._packagepath + package.cpath = pd._packagecpath +end + +-- constructor dispatcher +pd._constructor = function (name, atoms) + if nil ~= pd._classes[name] then + local o = pd._classes[name]:new():construct(name, atoms) + if o then + pd._objects[o._object] = o + return o._object + end + end + return nil +end + +-- destructor dispatcher +pd._destructor = function (object) + if nil ~= pd._objects[object] then + pd._objects[object]:destruct() + end +end + +-- inlet method dispatcher +pd._dispatcher = function (object, inlet, sel, atoms) + if nil ~= pd._objects[object] then + pd._objects[object]:dispatch(inlet, sel, atoms) + end +end + +-- clock method dispatcher +pd._clockdispatch = function (c) + if nil ~= pd._clocks[c] then + local m = pd._clocks[c]._method + pd._clocks[c]._target[m](pd._clocks[c]._target) + end +end + +-- prototypical OO system +pd.Prototype = { } +function pd.Prototype:new(o) + o = o or {} + setmetatable(o, self) + self.__index = self + return o +end + + +-- clocks +pd.Clock = pd.Prototype:new() +function pd.Clock:register(object, method) + if nil ~= object then + if nil ~= object._object then + self._clock = pd._createclock(object._object, method) + self._target = object + self._method = method + pd._clocks[self._clock] = self + return self + end + end + return nil +end +function pd.Clock:destruct() + pd._clocks[self._clock] = nil + pd._clockfree(self._clock) + self._clock = nil +end +function pd.Clock:dispatch() + local m = self._target[self._method] + if type(m) == "function" then + return m(self._target) + else + self._target:error( + "no method for `" .. self._method .. + "' at clock of Lua object `" .. self._name .. "'" + ) + end +end +function pd.Clock:set(systime) + pd._clockset(self._clock, systime) +end +function pd.Clock:delay(delaytime) + pd._clockdelay(self._clock, delaytime) +end +function pd.Clock:unset() + pd._clockunset(self._clock) +end + +-- tables +pd.Table = pd.Prototype:new() +function pd.Table:sync(name) + self.name = name + self._length, self._array = pd._getarray(name) + if self._length < 0 then + return nil + else + return self + end +end +function pd.Table:destruct() + self._length = -3 + self._array = nil +end +function pd.Table:get(i) + if type(i) == "number" and 0 <= i and i < self._length then + return pd._readarray(self._length, self._array, i) + else + return nil + end +end +function pd.Table:set(i, f) + if type(i) == "number" and type(f) == "number" and 0 <= i and i < self._length then + return pd._writearray(self._length, self._array, i, f) + else + return nil + end +end +function pd.Table:length() + if self._length >= 0 then + return self._length + else + return nil + end +end +function pd.Table:redraw() + pd._redrawarray(self.name) +end + +-- receivers +function pd._receivedispatch(receive, sel, atoms) + if nil ~= pd._receives[receive] then + pd._receives[receive]:dispatch(sel, atoms) + end +end +pd.Receive = pd.Prototype:new() +function pd.Receive:register(object, name, method) + if nil ~= object then + if nil ~= object._object then + self._receive = pd._createreceive(object._object, name) + self._name = name + self._target = object + self._method = method + pd._receives[self._receive] = self + return self + end + end + return nil +end +function pd.Receive:destruct() + pd._receives[self._receive] = nil + pd._receivefree(self._receive) + self._receive = nil + self._name = nil + self._target = nil + self._method = nil +end +function pd.Receive:dispatch(sel, atoms) + self._target[self._method](self._target, sel, atoms) +end + +-- patchable objects +pd.Class = pd.Prototype:new() +function pd.Class:register(name) + if nil ~= pd._classes[name] then -- already registered + return pd._classes[name] -- return existing + else + self._class = pd._register(name) -- register new class + pd._classes[name] = self -- record registration + self._name = name + return self -- return new + end +end +function pd.Class:construct(sel, atoms) + self._object = pd._create(self._class) + self.inlets = 0 + self.outlets = 0 + if self:initialize(sel, atoms) then + pd._createinlets(self._object, self.inlets) + pd._createoutlets(self._object, self.outlets) + self:postinitialize() + return self + else + return nil + end +end +function pd.Class:destruct() + pd._objects[self] = nil + self:finalize() + pd._destroy(self._object) +end +function pd.Class:dispatch(inlet, sel, atoms) + local m = self["in_" .. inlet .. "_" .. sel] + if type(m) == "function" then + if sel == "bang" then return m(self) end + if sel == "float" then return m(self, atoms[1]) end + if sel == "symbol" then return m(self, atoms[1]) end + if sel == "pointer" then return m(self, atoms[1]) end + if sel == "list" then return m(self, atoms) end + return m(self, atoms) + end + m = self["in_n_" .. sel] + if type(m) == "function" then + if sel == "bang" then return m(self, inlet) end + if sel == "float" then return m(self, inlet, atoms[1]) end + if sel == "symbol" then return m(self, inlet, atoms[1]) end + if sel == "pointer" then return m(self, inlet, atoms[1]) end + if sel == "list" then return m(self, inlet, atoms) end + return m(self, inlet, atoms) + end + m = self["in_" .. inlet] + if type(m) == "function" then + return m(self, sel, atoms) + end + m = self["in_n"] + if type(m) == "function" then + return m(self, inlet, sel, atoms) + end + self:error( + "no method for `" .. sel .. + "' at inlet " .. inlet .. + " of Lua object `" .. self._name .. "'" + ) +end +function pd.Class:outlet(outlet, sel, atoms) + pd._outlet(self._object, outlet, sel, atoms) +end +function pd.Class:initialize(sel, atoms) end +function pd.Class:postinitialize() end +function pd.Class:finalize() end +function pd.Class:dofile(file) + return pd._dofile(self._object, file) +end +function pd.Class:error(msg) + pd._error(self._object, msg) +end + + +local lua = pd.Class:new():register("pdlua") -- global controls +function lua:initialize(sel, atoms) + self.inlets = 1 + self.outlets = 0 -- FIXME: might be nice to have errors go here? + return true +end +function lua:in_1_load(atoms) -- execute a script + self:dofile(atoms[1]) +end + + +local luax = pd.Class:new():register("pdluax") -- classless lua externals +function luax:initialize(sel, atoms) -- motivation: pd-list 2007-09-23 + local f = self:dofile(atoms[1] .. ".pd_luax") + if nil ~= f then + local atomstail = { } -- munge for better lua<->luax compatibility + for i,_ in ipairs(atoms) do + if i > 1 then + atomstail[i-1] = atoms[i] + end + end + return f(self, atoms[1], atomstail) + else + return false -- error message already output by dofile() + end +end -- cgit v1.2.1