Hey List.
Just came across Zen Garden:
http://wiki.github.com/mhroth/ZenGarden/
Seems like the RJDJ crew is re-implementing PD in C++, in it's full object-oriented glory.
I'm excited about the idea of a more object-oriented approach, and especially with the idea of ditching all the Tk/Tcl garbage, but I don't really see the utility of re-implementing all the DSP graph code.
I haven't looked at the ZenGarden code at all yet though, so maybe they're doing a lot of borrowing where it makes sense?
Maybe we can talk about this interesting development without a flame war? Unlikely.
-s
On Fri, 16 Apr 2010, Spencer Russell wrote:
I'm excited about the idea of a more object-oriented approach,
Pd's implementation was made with an object-oriented approach. You can't get much more object-oriented than that. If you mean that the object-oriented approach has been implemented using C++'s grammar instead of having to invent yet another object system in C, you are right, and that can be a relief. However, this does not guarantee anything at all on the outcome of the project.
Much of ZenGarden is designed by copy+paste, and that's something that it doesn't get any better than Pd.
Meanwhile, the author claims ZenGarden has « clean code », presumably to imply that Miller's isn't, but there's no explanation at all on what it means to be clean. I think cleanliness means no copy paste. I also think cleanliness doesn't mean using variable-names that look like this_is_the_array_that_contains_the_outlets_sorted_by_horizontal_position.
Then the externals API... I don't think that was compatible with anything. It's a lot easier to port your Pd externals to MAX than to ZenGarden.
I haven't looked at the ZenGarden code at all yet though, so maybe they're doing a lot of borrowing where it makes sense?
maybe they're not doing any borrowing at all ? Have a look.
Maybe we can talk about this interesting development without a flame war? Unlikely.
According to Einstein, temperature is in the eye of the beholder.
_ _ __ ___ _____ ________ _____________ _____________________ ... | Mathieu Bouchard, Montréal, Québec. téléphone: +1.514.383.3801
On Sat, Apr 17, 2010 at 1:38 AM, Mathieu Bouchard matju@artengine.ca wrote:
On Fri, 16 Apr 2010, Spencer Russell wrote:
I'm excited about the idea of a more object-oriented approach,
Pd's implementation was made with an object-oriented approach. You can't get much more object-oriented than that. If you mean that the object-oriented approach has been implemented using C++'s grammar instead of having to invent yet another object system in C, you are right, and that can be a relief. However, this does not guarantee anything at all on the outcome of the project.
Agreed that Pd's code is certainly organized in an object-oriented way, and the architecture that Miller has constructed to do OOP in C is extremely clever and definitely nothing to throw sticks at. On the other hand, there are structures that come for free when using a language that supports real objects out of the box (such as real polymorphism) that are difficult if not impossible to achieve in C.
Much of ZenGarden is designed by copy+paste, and that's something that it doesn't get any better than Pd.
Meanwhile, the author claims ZenGarden has « clean code », presumably to imply that Miller's isn't, but there's no explanation at all on what it means to be clean. I think cleanliness means no copy paste. I also think cleanliness doesn't mean using variable-names that look like this_is_the_array_that_contains_the_outlets_sorted_by_horizontal_position.
I'm not ready to make blanket statements regarding the overall cleanliness of ZG vs. PD code, but there's definitely a significant reduction of boilerplate necessary to create an object, which seems like a step forward. I have some concerns about the extensibility of some of ZG's current architecture (the PdGraph object has a list of all the objects it supports hard-coded in), but it's still a young project with the architecture still somewhat in flux.
Then the externals API... I don't think that was compatible with anything. It's a lot easier to port your Pd externals to MAX than to ZenGarden.
agreed, losing the rich library of Pd externals would be a huge problem, and developing a flext-like abstraction layer seems intractable due to the significant under-the-hood differences.
It also seems important to note that the ZG guys aren't trying to replace PD wholesale, but just to provide a separate runtime library that makes Pd patches more embeddable (within other programs, on other devices). The project was started by RJDJ, so I don't imagine that dynamic patching is a high priority.
-s
Surely the pd-dev list exists for just such long, arcane and not-at-all-relevant-to-actually-using-pd discussions? No flame intended.
D.
On Sat, 17 Apr 2010, Spencer Russell wrote:
Agreed that Pd's code is certainly organized in an object-oriented way, and the architecture that Miller has constructed to do OOP in C is extremely clever
Well, not that clever. This kind of design has been implemented quite a number of times by various libraries that needed to use OOP in C : Xt, Tk, Gtk, etc., with the difference that those implemented inheritance and Pd did not, and with the difference that Pd walks a linked-list to look up any special selector...
On the other hand, there are structures that come for free when using a language that supports real objects out of the box (such as real polymorphism)
I don't know what "real objects" and "real polymorphism" mean.
It might be a difference of ontology between us...
C++ objects are as real and are as fake as anyone else's. They're just a lot less annoying to use (most of the time) or a lot more annoying to use (sometimes).
that are difficult if not impossible to achieve in C.
Ok, you'll have to give an example of that.
I'm not ready to make blanket statements regarding the overall cleanliness of ZG vs. PD code, but there's definitely a significant reduction of boilerplate necessary to create an object, which seems like a step forward.
What I see is an increase of boilerplate, or at least a massive replacement of old boilerplate by different boilerplate. There's irony in things like Pd supporting default arguments and ZenGarden making you define two constructors instead of just "(float f=0)" as in normal C++ code.
I have some concerns about the extensibility of some of ZG's current architecture (the PdGraph object has a list of all the objects it supports hard-coded in), but it's still a young project with the architecture still somewhat in flux.
Well, what I said about the externals API is probably because I don't know ZenGarden enough : I looked at how builtin classes are defined and I assumed that there was an externals API that worked exactly the same as that.
agreed, losing the rich library of Pd externals would be a huge problem,
It's not just a huge problem, it's a no-go. I developed well over a hundred externals and I'm not going anywhere without them. Many other people are dragging their own externals behind but most people are dragging other people's externals behind them and have become at least as dependent on them.
It also seems important to note that the ZG guys aren't trying to replace PD wholesale, but just to provide a separate runtime library that makes Pd patches more embeddable
That's not a Pd that many people can use. I can't think of many people that don't use any externals. When I contributed to list-abs, it was to show how complicated it can be, to make something efficient without using any externals.
(within other programs, on other devices). The project was started by RJDJ, so I don't imagine that dynamic patching is a high priority.
what does any of it have to do with dynamic-patching ? Well, there are some externals that improve dynamic-patching support, but much of dynamic-patching tends to be done by abstractions, while externals usually take care of something else.
_ _ __ ___ _____ ________ _____________ _____________________ ... | Mathieu Bouchard, Montréal, Québec. téléphone: +1.514.383.3801
I'm excited about the idea of a more object-oriented approach, and especially with the idea of ditching all the Tk/Tcl garbage, but I don't really see the utility of re-implementing all the DSP graph code.
depending on their implementation, it may be possible to do click-free changes of the dsp graph, which is the weakest part of the dsp engine of pd. from my understanding impossible to fully eliminate audio dropouts when changing max-like signal graph, since the implicit resource access order may change, depending on the use case.
tim
Yes. This was a design goal from early on. A dynamically rewritable signal graph is quite essential to advanced procedural audio.
On Sat, 17 Apr 2010 12:04:09 +0200 Tim Blechmann tim@klingt.org wrote:
I'm excited about the idea of a more object-oriented approach, and especially with the idea of ditching all the Tk/Tcl garbage, but I don't really see the utility of re-implementing all the DSP graph code.
depending on their implementation, it may be possible to do click-free changes of the dsp graph, which is the weakest part of the dsp engine of pd. from my understanding impossible to fully eliminate audio dropouts when changing max-like signal graph, since the implicit resource access order may change, depending on the use case.
tim
-- tim@klingt.org http://tim.klingt.org
After one look at this planet any visitor from outer space would say "I want to see the manager." William S. Burroughs
Pd-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
I think that using [throw~]/[catch~] and [s~]/[r~] can do the job really ..i'm not sure what are you trying to archieve but i hope you get my idea ..
also, can someone tell if sending or throwing signals adds any processing overhead?
On Sat, Apr 17, 2010 at 11:24:14AM +0100, Andy Farnell wrote:
Yes. This was a design goal from early on. A dynamically rewritable signal graph is quite essential to advanced procedural audio.
On Sat, 17 Apr 2010 12:04:09 +0200 Tim Blechmann tim@klingt.org wrote:
I'm excited about the idea of a more object-oriented approach, and especially with the idea of ditching all the Tk/Tcl garbage, but I don't really see the utility of re-implementing all the DSP graph code.
depending on their implementation, it may be possible to do click-free changes of the dsp graph, which is the weakest part of the dsp engine of pd. from my understanding impossible to fully eliminate audio dropouts when changing max-like signal graph, since the implicit resource access order may change, depending on the use case.
tim
-- tim@klingt.org http://tim.klingt.org
After one look at this planet any visitor from outer space would say "I want to see the manager." William S. Burroughs
Pd-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
--
Sent from my 3 (http://three.co.uk) mobile broadband Third world internet for a first world economy.
- 20 bytes/second * 99% packet loss * 60 second latency
All for only £20/month (Odious and predatory terms apply)
Pd-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
unfortunately, this is not a trivial issue.
dynamically changing the signal graph is possible (actually, i had an implementation of that in nova). do the topological sorting in the background and you are fine.
the tricky part are implicit dependencies. see this trivial patch: |adc~| | |send~ foo|
|receive~ foo| | |dac~|
it execution order is ambiguous. either (a) adc-send-receive-dac or (b) receive-dac-adc-send. the actual execution order depends on the implementation. the case (b) introduces one sample block of latency between send and receive, (a) doesn't introduce any latency. without the loss of generality, lets assume that the actual order of the dsp graph is (b). now you add a connection between adc~ and dac~. the topological sorting of the dsp graph may come to the execution order (a). adding the connection, you change the layout of the signal graph, changing the order of send~ and receive~ and therefore its semantics. you actually loose one sample block and therefore have an audio dropout.
if there are any possibilities to circumvent this issue, i haven't found any. for special cases, it works, but whenever implicit dependencies have to be taken into account, things are getting very messy. if you want to have dynamically changing signal graphs, don't use max-like languages. it is not a problem of the implementation, it is a problem of the programming model in general! if you need dynamically changing signal graphs, you should use a system, that is designed for this use case.
cheers, tim
Yes. This was a design goal from early on. A dynamically rewritable signal graph is quite essential to advanced procedural audio.
On Sat, 17 Apr 2010 12:04:09 +0200 Tim Blechmann tim@klingt.org wrote:
I'm excited about the idea of a more object-oriented approach, and especially with the idea of ditching all the Tk/Tcl garbage, but I don't really see the utility of re-implementing all the DSP graph code.
depending on their implementation, it may be possible to do click-free changes of the dsp graph, which is the weakest part of the dsp engine of pd. from my understanding impossible to fully eliminate audio dropouts when changing max-like signal graph, since the implicit resource access order may change, depending on the use case.
tim
On Sat, Apr 17, 2010 at 9:04 AM, Tim Blechmann tim@klingt.org wrote:
unfortunately, this is not a trivial issue.
dynamically changing the signal graph is possible (actually, i had an implementation of that in nova). do the topological sorting in the background and you are fine.
the tricky part are implicit dependencies. see this trivial patch: |adc~| | |send~ foo|
|receive~ foo| | |dac~|
it execution order is ambiguous. either (a) adc-send-receive-dac or (b) receive-dac-adc-send. the actual execution order depends on the implementation. the case (b) introduces one sample block of latency between send and receive, (a) doesn't introduce any latency. without the loss of generality, lets assume that the actual order of the dsp graph is (b). now you add a connection between adc~ and dac~. the topological sorting of the dsp graph may come to the execution order (a). adding the connection, you change the layout of the signal graph, changing the order of send~ and receive~ and therefore its semantics. you actually loose one sample block and therefore have an audio dropout.
if there are any possibilities to circumvent this issue, i haven't found any. for special cases, it works, but whenever implicit dependencies have to be taken into account, things are getting very messy. if you want to have dynamically changing signal graphs, don't use max-like languages. it is not a problem of the implementation, it is a problem of the programming model in general! if you need dynamically changing signal graphs, you should use a system, that is designed for this use case.
cheers, tim
I've actually wondered this for a while: Why is it that send~ and receive~ objects require special treatment instead of being treated the same as any other edge in the graph? I understand that in the current implementation using s~ / r~ pairs is the only way to create a graph with cycles (or fake the effect of one, anyways), but it doesn't seem obvious to me that that is the only valid way to go about it.
If they were just "invisible wires" then cycles would require other treatment, obviously, but it seems like cycles could be "broken" and turned into leaf nodes in the graph automatically, or by requiring the user to put a 1-block delay in explicitly, instead of letting the s~/r~ pair do double-duty and add the possibility for ambiguity as described above.
I suppose I would lean towards the 2nd method, to make sure the break point of the cycle is well defined.
-s
I've actually wondered this for a while: Why is it that send~ and receive~ objects require special treatment instead of being treated the same as any other edge in the graph? I understand that in the current implementation using s~ / r~ pairs is the only way to create a graph with cycles (or fake the effect of one, anyways), but it doesn't seem obvious to me that that is the only valid way to go about it.
If they were just "invisible wires" then cycles would require other treatment, obviously, but it seems like cycles could be "broken" and turned into leaf nodes in the graph automatically, or by requiring the user to put a 1-block delay in explicitly, instead of letting the s~/r~ pair do double-duty and add the possibility for ambiguity as described above.
if send~/receive~ pairs were `invisible' wires, they would turn up as true dependencies in the ugen (tilde object) graph. you would need to make sure, that they don't introduce cycles, which is possible, but you would need to decide, where to break cycles:
|r~ a| | |s~ b|
|r~ b| | |s~ c|
|r~ c| | |s~ a|
where do you introduce the delay? in bus a, b, or c? this gets even trickier, if you want to set the bus dynamically.
tim
That would have been the function of a versatile [z~] object in my mind. Default would be [z~ -1] or a one sample delay, and a second inlet would allow [z~ -blocksize] to do what we normally do with a [s~] and [r~].
There was one from Zexy that I used for a long time time before I understood how Pd differs from notated DSP, and that you can't actually do things like make a phasor without setting the blocksize to 1
To me the 'hidden' fucntionality of [s~/r~] departs from "The diagram is the program" and its far nicer to make these delays explicit and visible. All the same, thats the way it is and it's probably more pain than gain to upset it all now.
On Sat, 17 Apr 2010 09:33:20 -0400 Spencer Russell spencer.f.russell@gmail.com wrote:
On Sat, Apr 17, 2010 at 9:04 AM, Tim Blechmann tim@klingt.org wrote:
unfortunately, this is not a trivial issue.
dynamically changing the signal graph is possible (actually, i had an implementation of that in nova). do the topological sorting in the background and you are fine.
the tricky part are implicit dependencies. see this trivial patch: |adc~| | |send~ foo|
|receive~ foo| | |dac~|
it execution order is ambiguous. either (a) adc-send-receive-dac or (b) receive-dac-adc-send. the actual execution order depends on the implementation. the case (b) introduces one sample block of latency between send and receive, (a) doesn't introduce any latency. without the loss of generality, lets assume that the actual order of the dsp graph is (b). now you add a connection between adc~ and dac~. the topological sorting of the dsp graph may come to the execution order (a). adding the connection, you change the layout of the signal graph, changing the order of send~ and receive~ and therefore its semantics. you actually loose one sample block and therefore have an audio dropout.
if there are any possibilities to circumvent this issue, i haven't found any. for special cases, it works, but whenever implicit dependencies have to be taken into account, things are getting very messy. if you want to have dynamically changing signal graphs, don't use max-like languages. it is not a problem of the implementation, it is a problem of the programming model in general! if you need dynamically changing signal graphs, you should use a system, that is designed for this use case.
cheers, tim
I've actually wondered this for a while: Why is it that send~ and receive~ objects require special treatment instead of being treated the same as any other edge in the graph? I understand that in the current implementation using s~ / r~ pairs is the only way to create a graph with cycles (or fake the effect of one, anyways), but it doesn't seem obvious to me that that is the only valid way to go about it.
If they were just "invisible wires" then cycles would require other treatment, obviously, but it seems like cycles could be "broken" and turned into leaf nodes in the graph automatically, or by requiring the user to put a 1-block delay in explicitly, instead of letting the s~/r~ pair do double-duty and add the possibility for ambiguity as described above.
I suppose I would lean towards the 2nd method, to make sure the break point of the cycle is well defined.
-s
Pd-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
Giving up extensible generality and moving from a linear structure to finite but 'big enough' adjacency matrix always seemed the way to go.
I'm not speaking for Martin on ZenGarden though, I'm not sure what his current ideas are, or even if its still active.
How did topoloical sorting of a list work out in Nova Tim?
a.
On Sat, 17 Apr 2010 15:04 +0200 Tim Blechmann tim@klingt.org wrote:
unfortunately, this is not a trivial issue.
dynamically changing the signal graph is possible (actually, i had an implementation of that in nova). do the topological sorting in the background and you are fine.
the tricky part are implicit dependencies. see this trivial patch: |adc~| | |send~ foo|
|receive~ foo| | |dac~|
it execution order is ambiguous. either (a) adc-send-receive-dac or (b) receive-dac-adc-send. the actual execution order depends on the implementation. the case (b) introduces one sample block of latency between send and receive, (a) doesn't introduce any latency. without the loss of generality, lets assume that the actual order of the dsp graph is (b). now you add a connection between adc~ and dac~. the topological sorting of the dsp graph may come to the execution order (a). adding the connection, you change the layout of the signal graph, changing the order of send~ and receive~ and therefore its semantics. you actually loose one sample block and therefore have an audio dropout.
if there are any possibilities to circumvent this issue, i haven't found any. for special cases, it works, but whenever implicit dependencies have to be taken into account, things are getting very messy. if you want to have dynamically changing signal graphs, don't use max-like languages. it is not a problem of the implementation, it is a problem of the programming model in general! if you need dynamically changing signal graphs, you should use a system, that is designed for this use case.
cheers, tim
Yes. This was a design goal from early on. A dynamically rewritable signal graph is quite essential to advanced procedural audio.
On Sat, 17 Apr 2010 12:04:09 +0200 Tim Blechmann tim@klingt.org wrote:
I'm excited about the idea of a more object-oriented approach, and especially with the idea of ditching all the Tk/Tcl garbage, but I don't really see the utility of re-implementing all the DSP graph code.
depending on their implementation, it may be possible to do click-free changes of the dsp graph, which is the weakest part of the dsp engine of pd. from my understanding impossible to fully eliminate audio dropouts when changing max-like signal graph, since the implicit resource access order may change, depending on the use case.
tim
-- tim@klingt.org http://tim.klingt.org
Happiness is a byproduct of function, purpose, and conflict; those who seek happiness for itself seek victory without war. William S. Burroughs
Pd-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
Giving up extensible generality and moving from a linear structure to finite but 'big enough' adjacency matrix always seemed the way to go.
it is not really a problem of the graph representation, but it is about what i call `implicit dependency'. in order to traverse a graph, you can traverse it manually or create a topologically sorted list (which is faster and easier). in any case, this leads to a total order between all unit generators. if you change the layout of the graph, the order between objects, accessing the bus has to stay the same, to keep the access order. otherwise one sample block may be lost, or played twice.
I'm not speaking for Martin on ZenGarden though, I'm not sure what his current ideas are, or even if its still active.
How did topoloical sorting of a list work out in Nova Tim?
sorting the list is not the problem. the problem is to keep the semantics. this is not only a problem when changing the signal graph, but also when trying to parallelize the audio synthesis. the programming model of max-like languages turned out to be contra-productive and i abandoned nova, in order to write supernova, which replaces the supercollider server. since the programming model of supercollider doesn't have the notion of implicit dependencies (it was designed as system for dynamically changing synthesis graphs), the this problem doesn't exist, which also makes it way easier to write a scalable multi-processor aware audio synthesis engine.
well, my master thesis will cover these issues in more detail, will need a few more months to finish it, though
tim