I've been playing with Jamie Bullock's 'a_grain' lately (see http://www.puredata.org/Members/jb/a_grain%7E/view ), and in order to understand it better, I've been refactoring it.
A_grain has 14 inputs to control various parameters; my first approach to cleaning it up was to put all the inlets, in the correct order, at the top of the patch -- I then connected those inlets to 'send' objects with $0 variables, placing matching 'receive's close by where they are needed. This really cleaned up the wiring quite a bit, and made it easier to "read".
Now it occurs to me that I could eliminate the inlets entirely, and just write to send/receive pairs directly (perhaps also passing in a "prefix" as an argument that is prepended to all receives inside the abstraction, which would allow multiple instantiations of the abstraction, with independent control of each). At the UI-level patch, I could use named senders (from number boxes, sliders, whatever) just hovering nearby the a_grain abstraction; no wires, no mess.
I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest wiring caused by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not necessarily near the abstraction they're sending to -- it could become very hard to understand/maintain the patch.
I'll be interested to hear other PD user's thoughts on this.
Phil Stone UC Davis
I can already anticipate what some might suggest: try using a single inlet and then pipe that to [route] or [OSCroute].
Then you can use descriptive messaging to both a) provide better information about what data is going where, and b) cut down on having a zillion inlets at the top of your abstractions.
Using OSC style messaging is handy too--just look at RRadical for an example.
~Kyle
On 10/12/06, Phil Stone pkstone@ucdavis.edu wrote:
I've been playing with Jamie Bullock's 'a_grain' lately (see http://www.puredata.org/Members/jb/a_grain%7E/view ), and in order to understand it better, I've been refactoring it.
A_grain has 14 inputs to control various parameters; my first approach to cleaning it up was to put all the inlets, in the correct order, at the top of the patch -- I then connected those inlets to 'send' objects with $0 variables, placing matching 'receive's close by where they are needed. This really cleaned up the wiring quite a bit, and made it easier to "read".
Now it occurs to me that I could eliminate the inlets entirely, and just write to send/receive pairs directly (perhaps also passing in a "prefix" as an argument that is prepended to all receives inside the abstraction, which would allow multiple instantiations of the abstraction, with independent control of each). At the UI-level patch, I could use named senders (from number boxes, sliders, whatever) just hovering nearby the a_grain abstraction; no wires, no mess.
I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest wiring caused by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not necessarily near the abstraction they're sending to -- it could become very hard to understand/maintain the patch.
I'll be interested to hear other PD user's thoughts on this.
Phil Stone UC Davis
PD-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
Hallo, Kyle Klipowicz hat gesagt: // Kyle Klipowicz wrote:
I can already anticipate what some might suggest: try using a single inlet and then pipe that to [route] or [OSCroute].
Definitely! For example my pdx7 has 5*6 + 6*6 + 6*2 + 6 == 84 synthesis parameters. It has two inlets.
Frank Barknecht _ ______footils.org_ __goto10.org__
Pardon me for replying in this clumsy way, but I'm not sure how to
maintain thread integrity on my replies, since I receive PD-list in
digest mode. Since Kyle was kind enough to write me directly, I'm
hoping replying to him and his cc of the list will preserve the thread.
In reality, though, I'm replying to a few people at once here.
Kyle Klipowicz wrote:
I can already anticipate what some might suggest: try using a single inlet and then pipe that to [route] or [OSCroute].
Then you can use descriptive messaging to both a) provide better information about what data is going where, and b) cut down on having a zillion inlets at the top of your abstractions.
Using OSC style messaging is handy too--just look at RRadical for an example.
~Kyle
This does seem like a good idea, and Frank's follow-up is intriguing, too. My only objection to it is that you still have a lot of wiring that you wouldn't have with my second approach, i.e., you still have to patch the output of [route] or [OSCroute] to the various places the data is needed. Plus, you need to pack the sent information in one place on the parent patch -- another jumble of wires or an additional set of send-receives. I think symbolic routing is a good idea in general, though, so maybe these are not such important considerations.
carmen writes:
Now it occurs to me that I could eliminate the inlets entirely, and just write to send/receive pairs >directly
how do you find out which instance to send to. are you accessing the abstraction's $0 from outside the abstraction
One idea, which I've used successfully on another patch, is to add a parameter to the abstraction which is a message prefix.
So, if I called [a_grain~ env samp xyz] the third argument 'xyz' would
be the message prefix (it could be anything one liked, even '$0' if you
only needed to distinguish one set of messages for an abstraction).
Senders in the parent patch would send to xyz-(whatever), as in [s
xyz-pointerhop].
The abstraction has [receive] objects of the form [r $3-pointerhop].
Each instantiation of that abstraction will therefore only receive
messages intended for it, and one can address as many copies as one likes.
What I like about this is the lack of wires. In the parent patch, there's no wiring (!). I just assign appropriate sends, with the correct prefix, to my sliders, number boxes, etc. In the abstraction(s), there's an appropriately named (with the $3 prefix) receive object sitting right next to whatever needs the message.
I do want to go to the next stage and learn how to persist presets, so Frank's tutorial is particularly appreciated. I'll probably adopt his system for its obvious advantages. I'm just trying to train myself to "think PD" in the most efficient way, in the meantime.
Thanks for the responses,
Phil Stone UC Davis
On 10/12/06, *Phil Stone* < pkstone@ucdavis.edu mailto:pkstone@ucdavis.edu> wrote:
I've been playing with Jamie Bullock's 'a_grain' lately (see http://www.puredata.org/Members/jb/a_grain%7E/view ), and in order to understand it better, I've been refactoring it. A_grain has 14 inputs to control various parameters; my first approach to cleaning it up was to put all the inlets, in the correct order, at the top of the patch -- I then connected those inlets to 'send' objects with $0 variables, placing matching 'receive's close by where they are needed. This really cleaned up the wiring quite a bit, and made it easier to "read". Now it occurs to me that I could eliminate the inlets entirely, and just write to send/receive pairs directly (perhaps also passing in a "prefix" as an argument that is prepended to all receives inside the abstraction, which would allow multiple instantiations of the abstraction, with independent control of each). At the UI-level patch, I could use named senders (from number boxes, sliders, whatever) just hovering nearby the a_grain abstraction; no wires, no mess. I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest wiring caused by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not necessarily near the abstraction they're sending to -- it could become very hard to understand/maintain the patch. I'll be interested to hear other PD user's thoughts on this. Phil Stone UC Davis _______________________________________________ PD-list@iem.at <mailto:PD-list@iem.at> mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
--
http://theradioproject.com http://perhapsidid.blogspot.com
(((())))(()()((((((((()())))()(((((((())()()())()))) (())))))(()))))))))))))(((((((((((()()))))))))((()))) ))(((((((((((())))())))))))))))))))__________ _____())))))(((((((((((((()))))))))))_______ ((((((())))))))))))((((((((000)))oOOOOOO
Beware of NOT wiring enough.
Of course, we've all seen what beautifully unintelligible spiderweb artwork people are capable of spewing out when they don't patch with the courtesy of showing their ideas methodically. But an invisible web of sends and recieves can be just as misleading.
I like to use a combination, where there is a single [inlet] to a [route] that uses local [send]/[recieve] pairs within the abstraction. I really like this idea of Frank's to use one "master" send/recieve pair and then weed it all out with [route] objects: it makes it easier to remember what to type!
~Kyle
On 10/12/06, Phil Stone pkstone@ucdavis.edu wrote:
Pardon me for replying in this clumsy way, but I'm not sure how to maintain thread integrity on my replies, since I receive PD-list in digest mode. Since Kyle was kind enough to write me directly, I'm hoping replying to him and his cc of the list will preserve the thread. In reality, though, I'm replying to a few people at once here.
Kyle Klipowicz wrote:
I can already anticipate what some might suggest: try using a single inlet and then pipe that to [route] or [OSCroute].
Then you can use descriptive messaging to both a) provide better information about what data is going where, and b) cut down on having a zillion inlets at the top of your abstractions.
Using OSC style messaging is handy too--just look at RRadical for an example.
~Kyle
This does seem like a good idea, and Frank's follow-up is intriguing, too. My only objection to it is that you still have a lot of wiring that you wouldn't have with my second approach, i.e., you still have to patch the output of [route] or [OSCroute] to the various places the data is needed. Plus, you need to pack the sent information in one place on the parent patch -- another jumble of wires or an additional set of send-receives. I think symbolic routing is a good idea in general, though, so maybe these are not such important considerations.
carmen writes:
Now it occurs to me that I could eliminate the inlets entirely, and
just write to send/receive pairs >directly
how do you find out which instance to send to. are you accessing the
abstraction's $0 from outside the abstraction
One idea, which I've used successfully on another patch, is to add a parameter to the abstraction which is a message prefix.
So, if I called [a_grain~ env samp xyz] the third argument 'xyz' would be the message prefix (it could be anything one liked, even '$0' if you only needed to distinguish one set of messages for an abstraction). Senders in the parent patch would send to xyz-(whatever), as in [s xyz-pointerhop].
The abstraction has [receive] objects of the form [r $3-pointerhop]. Each instantiation of that abstraction will therefore only receive messages intended for it, and one can address as many copies as one likes.
What I like about this is the lack of wires. In the parent patch, there's no wiring (!). I just assign appropriate sends, with the correct prefix, to my sliders, number boxes, etc. In the abstraction(s), there's an appropriately named (with the $3 prefix) receive object sitting right next to whatever needs the message.
I do want to go to the next stage and learn how to persist presets, so Frank's tutorial is particularly appreciated. I'll probably adopt his system for its obvious advantages. I'm just trying to train myself to "think PD" in the most efficient way, in the meantime.
Thanks for the responses,
Phil Stone UC Davis
On 10/12/06, *Phil Stone* < pkstone@ucdavis.edu mailto:pkstone@ucdavis.edu> wrote:
I've been playing with Jamie Bullock's 'a_grain' lately (see http://www.puredata.org/Members/jb/a_grain%7E/view ), and in order
to
understand it better, I've been refactoring it. A_grain has 14 inputs to control various parameters; my first approach to cleaning it up was to put all the inlets, in the correct order,
at
the top of the patch -- I then connected those inlets to 'send' objects with $0 variables, placing matching 'receive's close by where they are needed. This really cleaned up the wiring quite a bit, and made it easier to "read". Now it occurs to me that I could eliminate the inlets entirely, and just write to send/receive pairs directly (perhaps also passing in a "prefix" as an argument that is prepended to all receives inside the abstraction, which would allow multiple instantiations of the abstraction, with independent control of each). At the UI-level patch, I could use named senders (from number boxes, sliders, whatever) just hovering nearby the a_grain abstraction; no wires, no mess. I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest wiring
caused
by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not necessarily
near
the abstraction they're sending to -- it could become very hard to understand/maintain the patch. I'll be interested to hear other PD user's thoughts on this. Phil Stone UC Davis _______________________________________________ PD-list@iem.at <mailto:PD-list@iem.at> mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
--
http://theradioproject.com http://perhapsidid.blogspot.com
(((())))(()()((((((((()())))()(((((((())()()())()))) (())))))(()))))))))))))(((((((((((()()))))))))((()))) ))(((((((((((())))())))))))))))))))__________ _____())))))(((((((((((((()))))))))))_______ ((((((())))))))))))((((((((000)))oOOOOOO
I second that thought! I have recently begun to try to avoid send/
receive as much as possible and instead focus on encapsulation in
abstractions and subpatches. I think this makes for much cleaner,
more readable, and less buggy code.
.hc
On Oct 12, 2006, at 6:03 PM, Kyle Klipowicz wrote:
Beware of NOT wiring enough.
Of course, we've all seen what beautifully unintelligible spiderweb
artwork people are capable of spewing out when they don't patch
with the courtesy of showing their ideas methodically. But an
invisible web of sends and recieves can be just as misleading.I like to use a combination, where there is a single [inlet] to a
[route] that uses local [send]/[recieve] pairs within the
abstraction. I really like this idea of Frank's to use one
"master" send/recieve pair and then weed it all out with [route]
objects: it makes it easier to remember what to type!~Kyle
On 10/12/06, Phil Stone pkstone@ucdavis.edu wrote: Pardon me for replying in this clumsy way, but I'm not sure how to maintain thread integrity on my replies, since I receive PD-list in digest mode. Since Kyle was kind enough to write me directly, I'm hoping replying to him and his cc of the list will preserve the
thread. In reality, though, I'm replying to a few people at once here.Kyle Klipowicz wrote:
I can already anticipate what some might suggest: try using a
single
inlet and then pipe that to [route] or [OSCroute].
Then you can use descriptive messaging to both a) provide better information about what data is going where, and b) cut down on
having
a zillion inlets at the top of your abstractions.
Using OSC style messaging is handy too--just look at RRadical for an example.
~Kyle
This does seem like a good idea, and Frank's follow-up is intriguing, too. My only objection to it is that you still have a lot of wiring that you wouldn't have with my second approach, i.e., you still
have to patch the output of [route] or [OSCroute] to the various places the
data is needed. Plus, you need to pack the sent information in one
place on the parent patch -- another jumble of wires or an additional set of send-receives. I think symbolic routing is a good idea in general, though, so maybe these are not such important considerations.carmen writes:
Now it occurs to me that I could eliminate the inlets entirely,
and just write to send/receive pairs >directly
how do you find out which instance to send to. are you accessing
the abstraction's $0 from outside the abstraction
One idea, which I've used successfully on another patch, is to add a parameter to the abstraction which is a message prefix.
So, if I called [a_grain~ env samp xyz] the third argument 'xyz'
would be the message prefix (it could be anything one liked, even '$0' if
you only needed to distinguish one set of messages for an abstraction). Senders in the parent patch would send to xyz-(whatever), as in [s xyz-pointerhop].The abstraction has [receive] objects of the form [r $3-pointerhop]. Each instantiation of that abstraction will therefore only receive messages intended for it, and one can address as many copies as one
likes.What I like about this is the lack of wires. In the parent patch, there's no wiring (!). I just assign appropriate sends, with the correct prefix, to my sliders, number boxes, etc. In the abstraction(s), there's an appropriately named (with the $3 prefix) receive object sitting right next to whatever needs the message.
I do want to go to the next stage and learn how to persist presets, so Frank's tutorial is particularly appreciated. I'll probably adopt his system for its obvious advantages. I'm just trying to train myself to "think PD" in the most efficient way, in the meantime.
Thanks for the responses,
Phil Stone UC Davis
On 10/12/06, *Phil Stone* < pkstone@ucdavis.edu mailto:pkstone@ucdavis.edu> wrote:
I've been playing with Jamie Bullock's 'a_grain' lately (see http://www.puredata.org/Members/jb/a_grain%7E/view ), and in
order to
understand it better, I've been refactoring it. A_grain has 14 inputs to control various parameters; my first approach to cleaning it up was to put all the inlets, in the correct
order, at
the top of the patch -- I then connected those inlets to 'send' objects with $0 variables, placing matching 'receive's close by where
they
are needed. This really cleaned up the wiring quite a bit, and
made it
easier to "read". Now it occurs to me that I could eliminate the inlets entirely, and just write to send/receive pairs directly (perhaps also passing in a "prefix" as an argument that is prepended to all receives inside the abstraction, which would allow multiple instantiations of the abstraction,
with
independent control of each). At the UI-level patch, I could
use
named senders (from number boxes, sliders, whatever) just hovering nearby the a_grain abstraction; no wires, no mess. I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest
wiring caused
by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not
necessarily near
the abstraction they're sending to -- it could become very
hard to
understand/maintain the patch. I'll be interested to hear other PD user's thoughts on this. Phil Stone UC Davis _______________________________________________ PD-list@iem.at <mailto:PD-list@iem.at> mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
--
http://theradioproject.com http://perhapsidid.blogspot.com
(((())))(()()((((((((()())))()(((((((())()()())()))) (())))))(()))))))))))))(((((((((((()()))))))))((()))) ))(((((((((((())))())))))))))))))))__________ _____())))))(((((((((((((()))))))))))_______ ((((((())))))))))))((((((((000)))oOOOOOO
--
http://theradioproject.com http://perhapsidid.blogspot.com
(((())))(()()((((((((()())))()(((((((())()()())()))) (())))))(()))))))))))))(((((((((((()()))))))))((()))) ))(((((((((((())))())))))))))))))))__________ _____())))))(((((((((((((()))))))))))_______ ((((((())))))))))))((((((((000)))oOOOOOO _______________________________________________ PD-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/ listinfo/pd-list
"[W]e have invented the technology to eliminate scarcity, but we are
deliberately throwing it away to benefit those who profit from
scarcity." -John Gilmore
Hallo, Phil Stone hat gesagt: // Phil Stone wrote:
I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest wiring caused by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not necessarily near the abstraction they're sending to -- it could become very hard to understand/maintain the patch.
A neat trick is to use one (!) send/receive pair for all (!) your abstractions, but "tagging" your abstractions with an argument, that you pass to a [route $1] inside.
An even neater trick is to use [sssad] to handle all this routing.
I'm working on a saving-tutorial which covers this in more detail. It's almost done, attached is the preview edition.
Frank Barknecht _ ______footils.org_ __goto10.org__
Wow, that's a great tutorial, it really explains the way [sssad] works quite well! Now I feel more comfortable using it!
~Kyle
On 10/12/06, Frank Barknecht fbar@footils.org wrote:
Hallo, Phil Stone hat gesagt: // Phil Stone wrote:
I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest wiring caused by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not necessarily near the abstraction they're sending to -- it could become very hard to understand/maintain the patch.
A neat trick is to use one (!) send/receive pair for all (!) your abstractions, but "tagging" your abstractions with an argument, that you pass to a [route $1] inside.
An even neater trick is to use [sssad] to handle all this routing.
I'm working on a saving-tutorial which covers this in more detail. It's almost done, attached is the preview edition.
Ciao
Frank Barknecht _ ______footils.org_ __goto10.org__
PD-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
My first thought is that I think that inlets are a more intuitive way
of handling input parameters in Pd. But there is definitely a limit
to how many inlets and outlets you can have. I try to break down the
problem into small enough units so that only inlets can be used, no
parameter messages.
If you have more than 5 or so parameters, then I think a message-
based parameter system is necessary. Then I think that it should be
only a message-based system, not something like 5 inlets which one
inlet that handles a bunch of extra messages. Keep in mind, these
are general rules, so I am sure there occasional exceptions where it
makes sense.
It the case that you describe, I would first try to break up the
problem into more objects, maybe one that handles enveloping/
windowing and one that handles grain making (I am just guessing here,
I don't know a_grain). But if you still want it to be one object
with 14 paramenters, I would make everything use messages, like you
suggest.
.hc
On Oct 12, 2006, at 2:24 PM, Phil Stone wrote:
I've been playing with Jamie Bullock's 'a_grain' lately (see http:// www.puredata.org/Members/jb/a_grain%7E/view ), and in order to
understand it better, I've been refactoring it.A_grain has 14 inputs to control various parameters; my first
approach to cleaning it up was to put all the inlets, in the
correct order, at the top of the patch -- I then connected those
inlets to 'send' objects with $0 variables, placing matching
'receive's close by where they are needed. This really cleaned up
the wiring quite a bit, and made it easier to "read".Now it occurs to me that I could eliminate the inlets entirely, and
just write to send/receive pairs directly (perhaps also passing in
a "prefix" as an argument that is prepended to all receives inside
the abstraction, which would allow multiple instantiations of the
abstraction, with independent control of each). At the UI-level
patch, I could use named senders (from number boxes, sliders,
whatever) just hovering nearby the a_grain abstraction; no wires,
no mess.I'm wondering what experienced PD architects consider the best
practice here; if the second approach is better, I begin to
question the advisability of wired inlets for more than two or
three arguments. The left-to-right ordering of them, along with
the rats-nest wiring caused by high numbers of inputs, seem to
argue against them. The only downside I can see to the second
method is that if it's not done neatly, i.e., the senders are
placed indiscriminately and not necessarily near the abstraction
they're sending to -- it could become very hard to understand/ maintain the patch.I'll be interested to hear other PD user's thoughts on this.
Phil Stone UC Davis
PD-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/ listinfo/pd-list
If nature has made any one thing less susceptible than all others of
exclusive property, it is the action of the thinking power called an
idea, which an individual may exclusively possess as long as he keeps
it to himself; but the moment it is divulged, it forces itself into
the possession of everyone, and the receiver cannot dispossess
himself of it. - Thomas Jefferson
On Thu, 2006-10-12 at 11:24 -0700, Phil Stone wrote:
I've been playing with Jamie Bullock's 'a_grain' lately (see http://www.puredata.org/Members/jb/a_grain%7E/view ), and in order to understand it better, I've been refactoring it.
Great news!
A_grain has 14 inputs to control various parameters; my first approach to cleaning it up was to put all the inlets, in the correct order, at the top of the patch -- I then connected those inlets to 'send' objects with $0 variables, placing matching 'receive's close by where they are needed. This really cleaned up the wiring quite a bit, and made it easier to "read".
Looking back at it I'm really glad I provided some documentation. The patch is a complete mess!
Now it occurs to me that I could eliminate the inlets entirely, and just write to send/receive pairs directly (perhaps also passing in a "prefix" as an argument that is prepended to all receives inside the abstraction, which would allow multiple instantiations of the abstraction, with independent control of each). At the UI-level patch, I could use named senders (from number boxes, sliders, whatever) just hovering nearby the a_grain abstraction; no wires, no mess.
The approach I am starting to use for all of my abstractions is to have the first inlet, and first outlet for all control-rate data, and use messages containing key/value tuples passed to [route] objects inside the abstraction to pass data in. What I like about this that once everything is connected up it is easy to see what parameters the data coming into the abstraction correspond to. It is also possible to implement a kind of pseudo-inheritance by nesting abstractions that implement this approach.
Anyhow, I look forward to seeing the results of your refactoring. I think it will inspire me to add some more features to [a_grain~] as per the TODO...
best,
Jamie
I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest wiring caused by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not necessarily near the abstraction they're sending to -- it could become very hard to understand/maintain the patch.
I'll be interested to hear other PD user's thoughts on this.
Phil Stone UC Davis
PD-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
Hi Jamie,
Nice to hear from you. I've been having fun with a_grain, and I'm beginning to understand it a little better.
I've attached what I've done with it so far, which uses the no-wire/message method I described below. I don't think this is always the best way to go about this (see discussion on this thread), but I'm finding it useful in this case, because it makes a complex patch with many inputs easier to read. Also included is the test runner (derived from yours), which shows how the message sending objects (number boxes and toggles) send to prefix-tagged destinations in the a_grain abstraction (the prefix being passed to a_grain as its third argument).
I've only begun to "untangle" a_grain, as you can see. But at least I
can see what the various parts are doing at this point. Very cool.
I've only included the two files I changed, by the way. Anyone else
wanting to actually try these changes needs to get the original folder from
http://www.puredata.org/Members/jb/a_grain%7E/view
then copy a_grain~.pd over its namesake, and add a_grainTest.pd to the folder and run it.
I'm enjoying a_grain and it's helping me understand granular synthesis à la PD; thank you for making it and putting it out there.
Phil Stone UC Davis
Jamie Bullock wrote:
On Thu, 2006-10-12 at 11:24 -0700, Phil Stone wrote:
I've been playing with Jamie Bullock's 'a_grain' lately (see http://www.puredata.org/Members/jb/a_grain%7E/view ), and in order to understand it better, I've been refactoring it.
Great news!
A_grain has 14 inputs to control various parameters; my first approach to cleaning it up was to put all the inlets, in the correct order, at the top of the patch -- I then connected those inlets to 'send' objects with $0 variables, placing matching 'receive's close by where they are needed. This really cleaned up the wiring quite a bit, and made it easier to "read".
Looking back at it I'm really glad I provided some documentation. The patch is a complete mess!
Now it occurs to me that I could eliminate the inlets entirely, and just write to send/receive pairs directly (perhaps also passing in a "prefix" as an argument that is prepended to all receives inside the abstraction, which would allow multiple instantiations of the abstraction, with independent control of each). At the UI-level patch, I could use named senders (from number boxes, sliders, whatever) just hovering nearby the a_grain abstraction; no wires, no mess.
The approach I am starting to use for all of my abstractions is to have the first inlet, and first outlet for all control-rate data, and use messages containing key/value tuples passed to [route] objects inside the abstraction to pass data in. What I like about this that once everything is connected up it is easy to see what parameters the data coming into the abstraction correspond to. It is also possible to implement a kind of pseudo-inheritance by nesting abstractions that implement this approach.
Anyhow, I look forward to seeing the results of your refactoring. I think it will inspire me to add some more features to [a_grain~] as per the TODO...
best,
Jamie
I'm wondering what experienced PD architects consider the best practice here; if the second approach is better, I begin to question the advisability of wired inlets for more than two or three arguments. The left-to-right ordering of them, along with the rats-nest wiring caused by high numbers of inputs, seem to argue against them. The only downside I can see to the second method is that if it's not done neatly, i.e., the senders are placed indiscriminately and not necessarily near the abstraction they're sending to -- it could become very hard to understand/maintain the patch.
I'll be interested to hear other PD user's thoughts on this.
Phil Stone UC Davis
PD-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
#N canvas 571 140 520 531 10; #X floatatom 141 313 10 0 0 0 - - -; #X obj 274 6 nbx 5 14 -10 1000 0 1 ag1-ptrhopsize empty ptrhopsize(s) 60 5 0 10 -225271 -1 -1 -5 256; #X obj 274 23 nbx 5 14 0 100 0 1 ag1-ptrdeviation empty ptrdeviation() 60 5 0 10 -225271 -1 -1 5 256; #X obj 274 40 nbx 5 14 0 100 0 1 ag1-ptrdeviationsmear empty ptrdeviationsmear(ms) 60 5 0 10 -225271 -1 -1 7 256; #X obj 274 57 nbx 5 14 0 1000 0 1 ag1-ptrdrunkinc empty ptrdrunkinc(ms) 60 5 0 10 -225271 -1 -1 0 256; #X obj 274 80 nbx 5 14 0 4000 0 1 ag1-grainreadrate empty grainreadrate(Hz) 60 5 0 10 -225271 -1 -1 157 256; #X obj 274 97 nbx 5 14 0 1000 0 1 ag1-grainsize empty grainsize(ms) 60 5 0 10 -225271 -1 -1 11 256; #X obj 274 114 nbx 5 14 0 100 0 1 ag1-grainsizedeviation empty grainsizedeviation() 60 5 0 10 -225271 -1 -1 0 256; #X obj 274 131 nbx 5 14 0 1000 0 1 ag1-grdevsmear empty graindeviationsmear(ms) 60 5 0 10 -225271 -1 -1 0 256; #X obj 274 148 nbx 5 14 0 1000 0 1 ag1-grdrunkinc empty graindrunkinc(ms) 60 5 0 10 -225271 -1 -1 0 256; #X obj 274 165 nbx 5 14 0 100 0 1 ag1-grainamp empty grainamp(0-100) 60 5 0 10 -225271 -1 -1 52 256; #X obj 274 194 nbx 5 14 0 100 0 1 ag1-tabstrtoff empty tabstartoffset(+%) 60 5 0 10 -225271 -1 -1 4 256; #X obj 274 211 nbx 5 14 -100 0 0 1 ag1-tabendoff empty tabendoffset(-%) 60 5 0 10 -225271 -1 -1 0 256; #X obj 58 260 tgl 15 0 empty empty ON/OFF 0 -6 0 8 -225271 -1 -1 0 1; #N canvas 37 82 520 561 tables 0; #N canvas 0 22 450 300 (subpatch) 0; #X array env 100 float 1; #A 0 0 0.000986636 0.00394267 0.00885636 0.0157084 0.0244717 0.0351118 0.0475865 0.0618467 0.0778361 0.0954915 0.114743 0.135516 0.157727 0.181288 0.206107 0.232087 0.259123 0.287111 0.315938 0.345492 0.375655 0.406309 0.437333 0.468605 0.5 0.531395 0.562667 0.593691 0.624345 0.654509 0.684062 0.71289 0.740877 0.767913 0.793893 0.818712 0.842274 0.864484 0.885257 0.904509 0.922164 0.938153 0.952414 0.964888 0.975528 0.984292 0.991144 0.996057 0.999013 1 0.999013 0.996057 0.991144 0.984292 0.975528 0.964888 0.952414 0.938153 0.922164 0.904508 0.885257 0.864484 0.842274 0.818712 0.793893 0.767913 0.740877 0.71289 0.684062 0.654508 0.624345 0.593691 0.562667 0.531395 0.5 0.468605 0.437333 0.406309 0.375655 0.345491 0.315938 0.28711 0.259123 0.232087 0.206107 0.181288 0.157726 0.135516 0.114743 0.0954915 0.077836 0.0618466 0.0475864 0.0351117 0.0244717 0.0157084 0.00885636 0.00394264 0.000986636; #X coords 0 1 99 0 150 100 1; #X restore 79 63 graph; #N canvas 0 22 450 300 (subpatch) 0; #X array samp 97088 float 0; #X coords 0 1 97087 -1 150 100 1; #X restore 79 189 graph; #N canvas 0 22 450 300 (subpatch) 0; #X array samp2 105536 float 0; #X coords 0 1 105535 -1 150 100 1; #X restore 79 322 graph; #X obj 238 138 soundfiler; #X obj 238 53 select 0 1; #X obj 238 30 inlet; #X msg 269 106 read -resize 2.wav samp2; #X obj 238 167 s $0-tabsize; #X msg 238 79 read -resize 1.wav samp; #X connect 3 0 7 0; #X connect 4 0 8 0; #X connect 4 1 6 0; #X connect 5 0 4 0; #X connect 6 0 3 0; #X connect 8 0 3 0; #X restore 73 82 pd tables; #N canvas 0 22 450 428 README 0; #X text 5 11 The two arguments to the a_grain~ abstraction give the enveloping function table name and the sample data table name respectively. The first outlet is th audio output , the second outputs the current read position. The abstraction works by reading audio 'grains' of grainsize from a selection delimited by 0 + tabstartoffset and tabsize + tabendoffset (where tabendoffset should be negative). A table lookup for each grain is performed by a phasor that runs at grainreadrate. After each successive grain has been read , the starting point for the table lookup is incremented by ptrhopsize. A windowing function is applied to each grain , and some control over the steepness of this function is given by grainamp. Random offsets can be introduced for the point from which the grain is read (ptrdeviation) , and the grainsize (grainsizedeviation). These are expressed as a percentage of the original value. Both offsets have a smear time , which introduces a linear ramp towards the new value and 'smooths' the sound. The random offsets can be random values between -deviation and +deviation , or change using a 'random walk' with a step size of ptrdrunkinc or graindrunkinc. This will be the behaviour if rand-drunk is set to 1 This abstraction requires various output~ by Miller Puckette , and a_rand , a_drunk and a_tgl as included with the patch.; #X restore 389 286 pd README; #X msg 100 14 0; #X msg 100 42 1; #X msg 57 14 samp; #X msg 55 42 samp2; #X obj 31 15 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1; #X obj 31 43 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1; #X text 218 501 EXPERIMENTAL VERSION; #X obj 22 260 vsl 15 120 0.0001 20 1 1 empty empty gain -2 -6 0 8 -225271 -1 -1 8800 1; #X obj 127 195 s ag1-grantabsize; #X obj 274 244 tgl 15 1 ag1-rd empty rand-drunk 17 7 0 10 -225271 -1 -1 0 1; #X obj 37 119 s ag1-samptab; #X obj 126 162 r $0-tabsize; #X floatatom 66 197 7 0 0 0 - - -; #X obj 59 285 a_grain~ env samp ag1; #X obj 267 347 loadbang; #X msg 268 374 ; pd dsp 1; #X msg 268 417 ; pd dsp 0; #X obj 61 457 dac~; #X obj 61 434 *~; #X obj 77 410 line~; #X obj 76 334 moses 0.0002; #X msg 76 359 0; #X obj 77 385 pack 0 50; #X connect 13 0 29 0; #X connect 16 0 14 0; #X connect 17 0 14 0; #X connect 18 0 26 0; #X connect 19 0 26 0; #X connect 20 0 18 0; #X connect 20 0 16 0; #X connect 21 0 19 0; #X connect 21 0 17 0; #X connect 23 0 36 0; #X connect 27 0 24 0; #X connect 27 0 28 0; #X connect 29 0 34 0; #X connect 29 1 0 0; #X connect 30 0 31 0; #X connect 34 0 33 0; #X connect 34 0 33 1; #X connect 35 0 34 1; #X connect 36 0 37 0; #X connect 36 1 38 0; #X connect 37 0 38 0; #X connect 38 0 35 0;
#N canvas 5 24 1172 702 10; #X obj 367 126 phasor~; #X floatatom 380 106 5 0 0 1 - - -; #X obj 389 163 *~; #X obj 527 466 cos~; #X obj 358 234 +~; #X obj 145 219 +; #X obj 98 219 float; #X obj 107 77 bang~; #X obj 107 97 a_counter; #X msg 69 72 0; #X obj 107 157 t b b; #X obj 107 116 >=; #X msg 374 213 0; #X obj 160 64 expr (44100 / 64) / $f1; #X obj 408 356 snapshot~; #X obj 107 135 sel 1; #X obj 365 546 *~; #X obj 527 444 expr~ ($v1 * .5) - 0.25; #X obj 308 183 samphold~; #X obj 595 158 a_rand; #X obj 462 179 * 44.1; #X obj 461 158 +; #X obj 500 158 t b f; #X obj 463 248 line~; #X obj 527 492 *~ 50; #X obj 463 225 pack f f; #X obj 180 148 line~; #X obj 180 125 pack f f; #X obj 202 412 +; #X obj 189 374 t b f; #X obj 11 377 * -1; #X obj 23 349 expr 0.5 * ($f1 / 100) * $f2; #X obj 618 129 expr 0.5 * ($f1 / 100) * $f2; #X obj 655 158 * -1; #X obj 408 413 sel 1; #X obj 926 99 switch~; #X msg 926 76 $1 20; #X obj 925 51 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 ; #X obj 438 433 s $0-cycle; #X obj 527 514 tabread4~ $1; #X obj 4 97 s $0-blockbang; #X obj 365 566 outlet~; #X obj 365 521 tabread4~ $2; #X obj 477 356 r $3-grantabsize; #X obj 205 234 * 44.1; #X obj 669 236 a_drunk; #X msg 721 204 1; #X msg 755 204 50; #X msg 691 204 0; #X obj 811 26 * 0.001; #X obj 634 182 * 1000; #X obj 622 203 * 1000; #X msg 167 507 1; #X msg 201 507 50; #X msg 137 506 0; #X obj 151 619 * 0.001; #X obj 24 454 * 1000; #X obj 12 504 * 1000; #X obj 50 430 a_tgl; #X obj 161 480 loadbang; #X obj 722 181 loadbang; #X obj 795 66 a_tgl; #X floatatom 24 476 5 0 0 0 - - -; #X obj 925 31 inlet on/off; #X obj 824 44 r $3-rd; #X obj 88 376 r $3-rd; #X obj 202 435 s $0-ptrhop; #X msg 98 195 0; #X obj 407 380 expr if($f1 >= ($f2 + $f5) && ($f3 >= 0) , $f4 , if(($f1 <= $f4) && ($f3 < 0) , ($f2 - $f5) , 1)); #X text 731 424 Ensures table size limit is respected , and that the offsets never overlap; #X obj 910 486 t b f; #X obj 931 535 t b f; #X obj 779 601 expr $f1 / 100 * $f2; #X obj 914 582 r $3-grantabsize; #X obj 751 646 expr $f1 / 100 * $f2; #X obj 886 627 r $3-grantabsize; #X obj 751 513 expr if(($f1 <= 0) || ($f1 - $f2) >= 99.9 , 0 , $f1) ; #X obj 778 561 expr if(($f1 >= 0) || ($f2 - $f1) >=99.9 , 0 , $f1) ; #X text 186 82 Smear time; #X obj 751 667 s $0-segstart; #X obj 779 622 s $0-segend; #X obj 484 562 outlet; #X text 533 562 Current pointer position; #X obj 377 456 r $3-samptab; #X msg 376 500 set $1; #X obj 376 478 symbol; #X obj 151 595 a_drunk; #X obj 50 409 a_rand; #X text 36 0 Granular synthesis using incremental table lookup + pulse train enveloping. Table name for enveloping function is given by the first arg , table for sample data is given by second arg (or changed via the first inlet).; #X text 526 275 If the pointer position is greater than or equal to the segment size and moving forwards move the pointer to the start of the segment otherwise if the pointer position is less than or equal to the segment start , and moving backwards , move the pointer to the end of the segment , otherwise do nothing.; #X obj 202 312 r $3-ptrhopsize; #X obj 23 299 r $3-ptrdeviation; #X obj 179 98 r $3-ptrdeviationsmear; #X obj 195 563 r $3-ptrdrunkinc; #X obj 366 79 r $3-grainreadrate; #X obj 808 106 r $3-grainsize; #X obj 460 111 r $3-grainsize; #X obj 619 53 r $3-grainsizedeviation; #X obj 472 200 r $3-grdevsmear; #X obj 730 156 r $3-grdrunkinc; #X obj 561 467 r $3-grainamp; #X obj 750 463 r $3-tabstrtoff; #X obj 911 463 r $3-tabendoff; #X text 215 297 Pointer rate; #X obj 594 104 r $0-blockbang; #X obj 206 210 r $0-ptrhop; #X obj 128 195 r $0-cycle; #X obj 675 356 r $0-segstart; #X obj 770 356 r $0-segend; #X obj 593 356 r $0-ptrhop; #X obj 416 335 r $0-blockbang; #X obj 49 323 r $0-blockbang; #X connect 0 0 2 0; #X connect 0 0 17 0; #X connect 0 0 18 1; #X connect 1 0 0 0; #X connect 1 0 13 0; #X connect 2 0 4 0; #X connect 3 0 24 0; #X connect 4 0 14 0; #X connect 4 0 42 0; #X connect 5 0 6 1; #X connect 6 0 5 0; #X connect 6 0 27 0; #X connect 7 0 8 0; #X connect 7 0 40 0; #X connect 8 0 11 0; #X connect 9 0 8 1; #X connect 10 0 9 0; #X connect 10 1 6 0; #X connect 11 0 15 0; #X connect 12 0 4 1; #X connect 13 0 11 1; #X connect 14 0 68 0; #X connect 14 0 81 0; #X connect 15 0 10 0; #X connect 16 0 41 0; #X connect 17 0 3 0; #X connect 18 0 4 1; #X connect 19 0 61 0; #X connect 20 0 25 0; #X connect 21 0 20 0; #X connect 22 0 21 0; #X connect 22 1 21 1; #X connect 23 0 2 1; #X connect 24 0 39 0; #X connect 25 0 23 0; #X connect 26 0 18 0; #X connect 27 0 26 0; #X connect 28 0 66 0; #X connect 29 0 28 0; #X connect 29 1 28 1; #X connect 30 0 57 0; #X connect 30 0 87 1; #X connect 31 0 30 0; #X connect 31 0 56 0; #X connect 31 0 87 2; #X connect 32 0 19 2; #X connect 32 0 33 0; #X connect 32 0 50 0; #X connect 33 0 19 1; #X connect 33 0 51 0; #X connect 34 1 38 0; #X connect 36 0 35 0; #X connect 37 0 36 0; #X connect 39 0 16 1; #X connect 42 0 16 0; #X connect 43 0 68 1; #X connect 44 0 5 1; #X connect 45 0 49 0; #X connect 46 0 45 2; #X connect 47 0 45 3; #X connect 49 0 61 1; #X connect 50 0 45 5; #X connect 51 0 45 4; #X connect 52 0 86 2; #X connect 53 0 86 3; #X connect 54 0 86 1; #X connect 55 0 58 1; #X connect 56 0 62 0; #X connect 56 0 86 5; #X connect 57 0 86 4; #X connect 58 0 29 0; #X connect 59 0 54 0; #X connect 59 0 52 0; #X connect 59 0 53 0; #X connect 60 0 48 0; #X connect 60 0 46 0; #X connect 60 0 47 0; #X connect 61 0 22 0; #X connect 63 0 37 0; #X connect 64 0 61 2; #X connect 65 0 58 2; #X connect 67 0 6 0; #X connect 68 0 34 0; #X connect 70 0 76 0; #X connect 70 1 76 1; #X connect 71 0 77 0; #X connect 71 1 77 1; #X connect 72 0 80 0; #X connect 73 0 72 1; #X connect 74 0 79 0; #X connect 75 0 74 1; #X connect 76 0 74 0; #X connect 77 0 72 0; #X connect 83 0 85 0; #X connect 84 0 42 0; #X connect 85 0 84 0; #X connect 86 0 55 0; #X connect 87 0 58 0; #X connect 90 0 28 0; #X connect 90 0 31 1; #X connect 91 0 31 0; #X connect 92 0 27 1; #X connect 93 0 86 2; #X connect 94 0 0 0; #X connect 95 0 32 1; #X connect 96 0 21 0; #X connect 97 0 32 0; #X connect 98 0 25 1; #X connect 99 0 45 2; #X connect 100 0 24 1; #X connect 101 0 76 0; #X connect 101 0 71 0; #X connect 102 0 70 0; #X connect 102 0 77 0; #X connect 104 0 19 0; #X connect 105 0 44 0; #X connect 106 0 6 1; #X connect 107 0 68 3; #X connect 108 0 68 4; #X connect 109 0 68 2; #X connect 110 0 14 0; #X connect 111 0 86 0; #X connect 111 0 87 0;