Hi (Claude),
inspired by Matteo's question I briefly tried to implement a [pipe] clone in pdlua, however I ran into problems which might hint at either some design issues with clock support in pdlua or, more likely, my lack of understanding how clocks work.
Anyway here's the problem: [pipe] in Pd is an object which as far as I understand the code creates lots of pd-clocks as part of a "hang-list" where pending events are collected. So the workflow is like this:
Everytime [pipe] receives a message, it creates a new "t_hang" structure item (in a list of these) with the message payload and a new clock inside. That clock is set to call back hang_tick(t_hang *h) after a delay. When its time has come, hang_tick sends the payload to the outlet and destroys the t_hang-object including the clock afterwards.
For the luapipe [lpipe] I thought I'd mimick that approach and collect the scheduled events in a table as member of the pdlua-class, like self.events.
So the method to add an event could look like this in pseudo-Lua:
function M:in_1(sel, atoms) local deltatime = atoms[1] -- delay local e = event.new() e.payload = atoms e.clock = makeclock(deltatime) table.insert(self.events, e) end
My problem is the hypothetical "makeclock". It should be a clock that somehow is tied to the event. But as I see it, clocks in pdlua are supposed to be tied to a pdclass object itself, and their callback methods don't accept any additional arguments to specify which of the event they should handle.
Any ideas how to work around this?
Frank Barknecht _ ______footils.org__
Frank Barknecht wrote:
Hi (Claude),
inspired by Matteo's question I briefly tried to implement a [pipe] clone in pdlua, however I ran into problems which might hint at either some design issues with clock support in pdlua or, more likely, my lack of understanding how clocks work.
[snip]
For the luapipe [lpipe] I thought I'd mimick that approach and collect the scheduled events in a table as member of the pdlua-class, like self.events.
It's easier to use idiomatic Lua, I think.
So the method to add an event could look like this in pseudo-Lua:
function M:in_1(sel, atoms) local deltatime = atoms[1] -- delay local e = event.new() e.payload = atoms e.clock = makeclock(deltatime) table.insert(self.events, e) end
My problem is the hypothetical "makeclock". It should be a clock that somehow is tied to the event. But as I see it, clocks in pdlua are supposed to be tied to a pdclass object itself, and their callback methods don't accept any additional arguments to specify which of the event they should handle.
Any ideas how to work around this?
Lua has lexical scope, and allows you to create closures (ie, functions that reference some part of their context). You don't need a table of events, you can just 'embed' the data in the function for each event.
I changed the interface of your object btw, having an "anything" inlet for messages and a "float" inlet for delay time, which is safer (you had an anything method, but assume the first atom is a float - bug!).
Something like this probably works (untested...):
-- initialise self.nextID to some number in constructor
function M:in_2_float(f) self.deltatime = math.max(0, f) end
function M:in_1(sel, atoms) -- we need unique method names for our clock callbacks self.nextID = self.nextID + 1 local id = "trigger" .. self.nextID local clock = pd.Clock:new():register(self, id) -- the clock callback outlets the data and cleans up self[id] = function(self) self:outlet(1, sel, atoms) clock:destruct() self[id] = nil end -- now start the clock clock:delay(self.deltatime) end
Hope this helps, was an interesting problem,
Hallo, Claude Heiland-Allen hat gesagt: // Claude Heiland-Allen wrote:
Frank Barknecht wrote:
inspired by Matteo's question I briefly tried to implement a [pipe] clone in pdlua, however I ran into problems which might hint at either some design issues with clock support in pdlua or, more likely, my lack of understanding how clocks work.
Lua has lexical scope, and allows you to create closures (ie, functions that reference some part of their context). You don't need a table of events, you can just 'embed' the data in the function for each event.
I changed the interface of your object btw, having an "anything" inlet for messages and a "float" inlet for delay time, which is safer (you had an anything method, but assume the first atom is a float - bug!).
Error checking was deliberately left out. ;) In the end I'd like to have the delay time up front to be able to use qlist-ish messages like: "0 a b c, 1000 x y z, 300 bang".
Something like this probably works (untested...):
-- initialise self.nextID to some number in constructor
function M:in_2_float(f) self.deltatime = math.max(0, f) end
function M:in_1(sel, atoms) -- we need unique method names for our clock callbacks self.nextID = self.nextID + 1 local id = "trigger" .. self.nextID local clock = pd.Clock:new():register(self, id) -- the clock callback outlets the data and cleans up self[id] = function(self) self:outlet(1, sel, atoms) clock:destruct() self[id] = nil end -- now start the clock clock:delay(self.deltatime) end
Ah, a very elegant solution. It's tested now (attached) and seems to work really well.
Frank Barknecht _ ______footils.org__
Frank Barknecht wrote:
Error checking was deliberately left out. ;) In the end I'd like to have the delay time up front to be able to use qlist-ish messages like: "0 a b c, 1000 x y z, 300 bang".
Ok, makes sense. However, what should be output for:
"0 a b c" -> "a b c" or "list a b c" ? "0 123" -> "float 123" or "list 123" ? "0 1 2 3" -> "list 1 2 3" ? "0" -> "bang" or "list" ?
The whole Pd selector system mess arises again, when it could be neatly side-stepped ;)
You could wrap the [lpipe] with two inlets in an abstraction to get the [qlist]-ish message behaviour, going the other way would be rather hard.
Thanks,
Claude Heiland-Allen wrote:
Frank Barknecht wrote:
Error checking was deliberately left out. ;) In the end I'd like to have the delay time up front to be able to use qlist-ish messages like: "0 a b c, 1000 x y z, 300 bang".
Ok, makes sense. However, what should be output for:
"0 123" -> "float 123" or "list 123" ?
aren't they synomymous by now?
"0 1 2 3" -> "list 1 2 3" ?
obvious.
"0" -> "bang" or "list" ?
aren't they synonymous by now? (i know your bugreport)
"0 a b c" -> "a b c" or "list a b c" ?
this one is the hardest. personally i would vote for "list a b c". according to [route] it would be "a b c".
however, you could just circumvent this by leaving the entire message intact ("0 123" stays "list 0 123") and let the user decide :-)
fgamsdr IOhannes