how does [list drip] actually work?
Hi folks,
This is going to be a weird and long post, because I am walking through my thinking as much as I am asking questions. Sorry for the length in advance.
I've recently become fascinated with the many possibilities afforded by the list-abs library, and what strikes me at is that [list-drip] seems to be at the heart of most of them. For those of you who don't know, [list-drip] works by separating (aka "dripping") an incoming list into its individual elements (atoms?). This allows you to do a bunch of operations on these elements before repacking them into a new list. For example, [list-compare] functions like [==] but for lists by checking each list's elements against each other to give out a binary yes or no answer. And of course, [list-drip] is at the core here.
I would like to really figure out the logic behind [list-drip], but the help file (well, really the abstraction itself) is deceptively simple. This is because [list-drip] itself is but an abstraction based on the clever use of [list-split] (which is not an abstraction but an external) and some strange binary math and triggering mechanisms that I don't understand.
Here's the [list-drip] extraction itself:
I'll just talk about this abstraction and ask questions along the way.
Here's the first part. Pretty simple. [trigger] is passing the entire list on, and then sending a bang. This seems weird but I've heard that pd will take care of all the operations starting at the right outlet of trigger first, so the bang is guaranteed to come after the list has been "dripped."
Here's the second part, where we have [list split] doing a binary "less than" operation on the list. "If the list is less than 2 elements long, it gets sent to the outlet and the [spigot] closes, else, open the spigot." This [trigger] then passes a copy of the list onto [spigot] which is either open or closed based on the above result.
Ok now here is where things start to get crazy. The list is now fed into two identical [list split] mechanisms with some weird math going on, which are also feeding back into the top of the second [trigger].
Let's break this down really quick:
First, we get the length of the list, then we feed it into [>> 1]. With some research in pd and the on the web, I come to the conclusion that we are basically dividing (integer division) by 2. This is setting the point for where [list split] outputs a list with only a certain number (but always half) of elements (using the first outlet). As I said before, this result is being fed back into the second [trigger].
So I think basically what's happening is this:
...where the rest of the list is either exactly half the total list length (if it's an even number) or half + 1 (if the total length is an odd number of elements).
So we have two "loops" going on here, where on operates on the first half of the list (will call this the "red" loop, and the other operates on the second "green loop".
Now in terms of trigger ordering, what is happening here? Are we constantly triggering the red loop until there are no more operations, and then moving on the green loop? And what does this mean in the context of the patch? I'm confused about how [trigger] acts in these situations with many nested loops.
To troubleshoot, I attached a print the outlets of both the red and green **[list split]**s, and sent the list [a b c d 1 2 3 4( to [list drip]. Here's the output from the console:
first half: symbol a
second half: symbol b
first half: list a b
first half: symbol c
second half: symbol d
second half: list c d
first half: list a b c d
first half: 1
second half: 2
first half: 1 2
first half: 3
second half: 4
second half: 3 4
second half: 1 2 3 4
To me this output looks like it was printed backwards. Is there some weird interaction between [trigger] and [print] going on?
Furthermore, how is the output of [list drip] organized so that each element is output in it's sequential order? How does the green loop know to wait for the red loop to finish?
Spigot~ for intelmac
Ok all these. But [spigot~] is not a [*~] with 0 and 1.
If we want to make a spigot~ in pd vanilla and not extended, we would need a patch / abstraction that stops the signal when right inlet is == 0 and let it pass when right inlet is > 0. This means also 0.5. There is a soloution with [select] [>] and numerical messanges but,
more of that, if we want to have signal in right inlet controlling our "spigot"?
Any ideas?
Spigot~
Here my versions of spigot~. They has a [line] object to make a 5ms fade from one to another and creation argument, to assign the initial value (default: 0).
[spigot~] is like [spigot], but with signal.
[spigot2~] is the inverted one: two signal inlets, one signal outlet.
EDIT: Instead of [== 0] to convert 0 to 1 and viseversa, this version uses [expr $f1 * -1 + 1], that inverts the value (0 to 1, 0.2 to 0.8, 0.5 to 0.5, etc). So, it is possible to make a fade from one to another. It works in both abstractions.
Spigot~
Here my versions of spigot~. They has a [line] object to make a 5ms fade from one to another and creation argument, to assign the initial value (default: 0).
[spigot~] is like [spigot], but with signal.
[spigot2~] is the inverted one: two signal inlets, one signal outlet.
EDIT: Instead of [== 0] to convert 0 to 1 and viseversa, this version uses [expr $f1 * -1 + 1], that inverts the value (0 to 1, 0.2 to 0.8, 0.5 to 0.5, etc). So, it is possible to make a fade from one to another. It works in both abstractions.
Fader + Color
Thanks!
related as well... and I found again my color-spigot.
Conditional gate
@mod said:
But time and time again we see the same sort of posts. People who just want to turn an audio signal on and off use something like [spigot~], people use [counter] instead of basic pd objects. They post these patches and run into trouble that could easily be avoided by only using vanilla objects unless necessary.
What's wrong with [counter]? Objects like those remedy the trouble of trying to figure out how to make one using only vanilla objects. Not that it's particularly difficult to do, but it may just be more intuitive or time saving to someone to use [counter].
Of course most people are using extended, but it's such a vast ocean that no-one knows how EVERY object in extended works. The object in question here, [gate], i can only hazard a guess, but i'm thinking that a maximum of 50% of users know the cyclone library and in particular the [gate] object well enough to debug a patch.
Well, that's where the basic advice that you and others have posted comes in: Right click -> Help.
Besides, I don't really think that because less people know or use an object should deter one from trying it. It may just make more sense or fit with their particular programming preferences. I know I like to build from low-level objects and work up, but not everyone is so interested. For example, I've built my own compressor abstraction. But plenty of other people would rather just load a compressor object and be done with it. Nothing wrong with either approach.
Also, I've been using Pd long enough that I feel comfortable saying I'm in "expert" territory. I don't know what every extended object does, but I don't know what EVERY vanilla object does, either.
(I'm speaking from my own bad experiences here too, because my old patches had some extended objects in them, and i answered countless emails from people having trouble with those externals not loading. I could have saved myself a lot of time by just using the correct vanilla constructs in the first place)
Now, this is a different issue, and I'm more inclined to agree here. You can definitely ensure higher compatibility by sticking to vanilla objects, as some externals don't work correctly on all OS's and vanilla users may not have some of the more popular libraries installed, but it does come with the potential costs of flexibility or computational load. And, this is only an issue if you want to share your patches or use them on other OS's.
When I'm writing a patch that's for personal use only, and I don't expect to be sharing it, I tend to use whatever I want. But if I'm making an abstraction I might share, I usually follow an order of precedence:
1. Use vanilla objects where possible/practical for best compatibility.
2. Use extended objects if needed, since it's used widely and newbie-friendly.
3. If absolutely necessary, use a popular lib not included in Pd-extended, like GridFlow or RjLib (I've never had to do this, yet).
But that's entirely for compatibility reasons only.
@Shakasin said:
But is there something in vanilla that could replace my [gate] just curious ?
. [== 1] [== 2] [== 3]
| | |
[spigot] [spigot] [spigot] etc....
Connect the gate number to the left inlet of the [== ] objects, and the value you want to pass to the left inlet of the [spigot]s.
Controlling signal flow
After taking a closer look at your patch, I'm not sure why you would even want that. I would think you'd want the [spigot] to close when it receives a new value and reopen after the soundfile is finished playing. If you leave the [spigot] open, it will just keep retriggering the soundfiles. [readsf~] sends a bang out its right outlet when it is finished playing, which you can use to to reopen the [spigot]. If you mean you want it to wait ten seconds after the soundfile is done, just stick a [delay 10000] between that and the [1(. See the attached (I also cleaned up you patch a bit).
Controlling signal flow
But how do I stop the flow of the spigot? How do I have to use the delay, so that once 10 seconds past, the spigot blocks the passage. If i connect the 0 to the 1 or put another bang after the trigger, the 1 gets banged as well. and putting the delay 1000 and the 0 after the 1, the one doesn't even get to the spigot.
Controlling signal flow
There are two problems here. The first is that you have this:
[float]
|
[bng]
|
[spigot]
|
[float]
The [bng] converting all of your numbers into bangs (which is a unique data type in Pd), so the only thing the [spigot] is passing through are bangs. When the [float] at the bottom receives a bang, it outputs its stored value, which is zero by default. So it looks like it's doing nothing because its sending zero over and over. So get rid of the [bng]. Same thing with the one after [1(.
Second--and this is more subtle--when you fan out connects from a single outlet, you can't be certain just by looking at it what order the connections execute. You can force the order using [trigger], also known as [t ]. The arguments of [t ] determine the number of outlets and what data type to convert to (if needed). When it receives a value, it outputs them from right-to-left order from its outlets, so you can be certain what gets executed first. I mention this because you probably want to make sure the [spigot] gets opened before you send the value, like this:
[float]
|
[t f b] <-- send a bang out the right outlet, then pass the float to the left outlet
| \
| [1(
| \
[spigot]
It's a good idea to get in the happen of using [t ] to improve the readability of your patches and to prevent hard to find bugs.
Sample masher and drum sequencer
Hi Tim,
First, I'm using pd 0.42.5-extended on a Windows system.
I discovered that your drum sequencer and possibly other sections of the patch are not working due to problems in "pd effectsunit" referenced by drumguts
In effectsunit:
First thing I noticed was that there were numerous [spigot~] objects. Evidently [spigot~] does not exist in the windows version, but I did find this thread with an abstraction that works: http://puredata.hurleur.com/sujet-1181-spigot
After adding that abstraction to my system, the drum sequencer is working properly. I observed however that the system wigs out if the bpm is set to 0 (the default), so you may want to set some non-zero default BPM.
The Vanilla Samples section is also working as expected.
However, I'm not able to get anything to happen with the left and right turntable sections. I can load a sample into it, but nothing happens.
Also, I'm not sure what is supposed to be going on in the area between the two turntables, but I'm getting an error in the console window:
playlist .text 150 100 \{Helvetica 10 bold\} white grey black red
... couldn't create