How to make each instance of an abstraction contain a unique subpatch puredata
Apparently, this seems to be a pretty rare thing to want to do in pd, because nowhere can I find where someone has asked this question online. I come from a programming background, so the idea of instances of an object containing unique objects seems fairly reasonable to me (to convert to pd terms: abstractions containing unique subpatches).
In C++ for example, you can pass objects into other objects as arguments, or even types into objects. So you could have class X that contains variable Y for an object. In instance A of that class, you could pass in type int, and Y would be of type int. While, in instance B, you could pass in type string, and Y would be of type string.
I know this isn't a direct 1 to 1, but how do I achieve this sort of functionality in PD?
This kinda difficult to explain, so I'll do my best. This is my situation (btw I'm using plugdata):
I'm building a cue system for a performance. I would like to create a "cue.pd" abstraction as essentially a class from which an arbitrary number of instances can be made. Each instance needs to have it's own completely custom functionality. I understand that I could achieve this by just making "cue1.pd", cue2.pd", etc or [pd cue] multiple times. But that would mean I have to create the exact number of subpatches as cues, and that's unscalable and inelegant if I were to reuse this system in the future.
I have multiple instances of a "cue.pd" abstraction within "cue_sequencer.pd", each with a number passed in as it's first argument.

Within the "cue.pd" abstraction, I assumed that if I made a [pd impl-$0] subpatch, each subpatch within each instance would be unique, as it's name is unique.

But this is not the case, as the same subpatches with different names contained within different instances of "cue.pd" have the same contents.


How would I make it such that each instance of "cue.pd" can contain it's own completely unique subpatch? Or at least achieve the same effect with a different method.
Thanks !! :3
array-maxx and array-minn - get multiple peaks of an array / does array-sort
OK, so, some benchmarking results.
In Pd, given a 100000-element input array and asking [array-maxx] for 1000 output values, I get what seems to be is a valid result in 99 ms... which is not very slow. (Pd gains performance here from the fact that [array max] is a primitive. If you had to run the array-max iteration by [until], it would be much, much slower.)
I did try it in SC. The [array-maxx] algorithm is extremely, brutally slow in SC because SC doesn't have an array-max primitive. The 100000 x 1000 = 100,000,000 iterations take about 3.6 seconds on my machine. Ouch.
The algorithm I described (iterate over the source array once, and insert items into the output array in descending order) is 5-6 times faster than Pd, and a couple hundred times faster than the SC brute force way. I did two versions: one uses the SC array insert primitive; the other uses only array get and put.
a = Array.fill(100000, { 1000000.rand });
(
f = { |a, n = 1000|
a = a.copy;
Array.fill(n, {
var index = a.maxIndex; // Pd equivalent [array max] is much faster
var value = a[index];
a[index] = -1e30;
value
});
};
g = { |a, n = 1000|
var out;
var index;
a.do { |item|
if(out.size == 0) {
out = [item];
} {
index = out.size - 1;
while {
index >= 0 and: {
out[index] < item
}
} {
index = index - 1
};
// now index points to the latest item in the array >= source item
if(index < (out.size-1) or: { out.size < n }) {
// insert after 'index' and drop excess smaller items
out = out.insert(index + 1, item).keep(n)
}
}
};
out
};
h = { |a, n = 1000|
var out;
var index, j;
a.do { |item|
if(out.size == 0) {
out = [item];
} {
index = out.size - 1;
while {
index >= 0 and: {
out[index] < item
}
} {
index = index - 1
};
if(index < (out.size-1) or: { out.size < n }) {
// index = index + 1;
if(out.size < n) {
// if we haven't reached n output values yet,
// add an empty space and slide all items after 'index'
j = out.size - 1;
out = out.add(nil);
} {
// if we already have enough output values,
// then 'item' must be greater than the current last output value
// so drop the last one
j = out.size - 2;
};
while { j > index } {
out[j+1] = out[j];
j = j - 1
};
out[index + 1] = item;
}
}
};
out
};
)
// brute force O(m*n) way
bench { f.(a).postln };
time to run: 3.592374201 seconds.
// single-iteration with array-insert primitive
bench { g.(a).postln };
time to run: 0.13782317200003 seconds.
// single-iteration without array-insert primitive
bench { h.(a).postln };
time to run: 0.21714963900013 seconds.
I might have another stab at it in Pd. Note that you can't directly compare the Pd and SC benchmarks because the "language engine" isn't the same -- there's no guarantee of getting Pd down to 20 ms -- but, can probably do better than ~100 ms.
hjh
On-air light, trouble receiving int via OSC
@jbaker It seems that maybe data can be requested from the X32 with an osc formatted message starting /formatsubscribe .... for specific parameters... and permanently? or just for a limited time...... and are future button presses on the console also (or only) returned...?
/web in the address.... can this be replaced with "IP:port"... ?
Complete and (so far) incomprehensible osc info here....... https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://tostibroeders.nl/wp-content/uploads/2020/02/X32-OSC.pdf&ved=2ahUKEwjq9e_w2JqMAxXCdqQEHXAeISkQFnoECB8QAQ&usg=AOvVaw2xQyrtSBeKrEBddafvVqiG
It would be great if you can find the return port number for osc on the X32.
It seems that on/off (enum) and 1/0 (integer) are interchangeable, but it is not clear (yet...!) whether they are part of the message header or data following the header.
all parameters must be big‐endian and 4‐byte aligned/padded, as per OSC specification.
padding is done with null bytes.
float parameters must be in range 0.0 – 1.0, e.g.:
0.0 0x00000000 (big-endian)
0.5 0x3f000000 (big-endian)
1.0 0x3f800000 (big-endian)
integer and float parameters are signed 32‐bit values.
strings must be null‐terminated.
enum parameters can be sent as strings or integers (see below).
boolean parameters will map to enum type {OFF, ON} (or OSC integer {0, 1})
blobs (arbitrary binary data) follow specific rules depending on the section they apply to (see later in this document)
Too much reading for me today...... maybe later...
David.
sub-patch with arguments?
Hi!
I've just learned subpatches doesn't work with arguments.
Although I've been trying that in the meanwhile and I noticed a strange behavior:
I copied various version of an eq subpatch, which I numbered like [pd eq 1] [pd eq 2] etc. (don't tell me to use abstraction, I have a lot of parameters and [savestate] seems too heavy).
I don't know why it is working, but it is: within the subpatches I have for example [s $1-freq] and [r $1-freq] and all the other eqs aren't affected.
That's not all: for any reason I can't reproduce all the subpatches copies after a while turned like [pd eq N 1] (notice the space between N and 1), N 2, N 3, N 4, and again N 1 in the next column of object (!?!). The interesting thing is that all my $1 inside the subpatches have been replaced by the corresponding number I gave as argument (1 - 16).
I want to reproduce the last point so I don't have to change some names within all the subpatches. I have send and receives, but also [route $1-freq $1-slope] etc., coming from a remote computer by [netsend]
doe's anybody know about that?
using send $0-name outisde subpatcher
A sub-patch inherits the $0 value (actually inherits all arguments) from the patch that it is in... and that would work correctly.
So I assume that your "subpatcher" is an abstraction (another patch) that you have put in your main patch. The two patches will have a different value for $0 and the messages are going to the wrong address. Getting a $0 value into a parent patch can be awkward.
You could use the $0 value from the main patch by creating [subpatcher $0] and then using $1 in the subpatcher for the array names.
But to differentiate each [subpatcher] you need to give them an argument so that you can use it multiple times...... [subpatcher 1], [subpatcher 2]....... .... you can also have just one [subpatcher $0]..
David.

Randomly can not edit, have to close and reopen subpatch
following up on this since i think i have a way to reliably reproduce this weird state with a very simple example:
- create new patch
- add
[pd foo]subpatch - add some random object in the subpatch - for example a
[bla(message Cmd+Clickin the parent window (i do this a lot normally to control sliders etc. - and it preserves the focus on the subpatch window)- now try to edit in the subpatch (selecting the text in the message or moving it). try again by switching to between edit- and perform-mode via
Cmd+E... try once more and see how perform mode now has the "edit cursor" (hand) and the edit mode has the regular mouse pointer.
another detail is that when creating another object via shortcut (e.g. Cmd+1) in this state creates the object at the default position on the top left. can you confirm this with your setup, @cfry?
EDIT: after testing a bit more, it seems like the actual point here is the Cmd+Click in another window. this also creates this state for me in the parent window if i Cmd+Click in the subpatch or in another patch.
[neuralnet], yet another artificial neural network external
@cfry Well, one case is to enable some sort of automation of parameter control. For example, the two examples that control a synth, enable the control of many parameters with only a few inputs. These examples control three or five parameteres, but I have used the object to control twenty parameters with the mouse coordinates, so with two inputs only. Additionaly, it helps you explore sounds as the parameter control will most likely fall in places that will creates sounds from a synth that you haven't created yourself, as the different combinations of twenty or so parameters are way too many to be able to thoroughly explore them all.
Concerning classification, it depends on what you would like to do. You could train it for example to clasify vowels, and based on speech input, keep a count of every vowel and do something with it.
Neural networks are just a tool to facilitate cumbersome processes, which can also provide interesting results. Anyway, I'm no specialist, so it's best if you keep searching to find ways to use NNs in your work.
how to open up "subpatch" (array) view from GOP?
@whale-av said:
Where subpatch is the name of the subpatch you want to see.
vis 0 will hide it again.Some info on messages to windows....... 0.all_msg.pd although there are others that are not documented in that patch.
David.
unfortunately, when i did [; pd-plom.pd vis 1( - all 16 of them became visible, which also unfortunately just opens up the plom script, not the plom array (subpatch). do i need to call the subpatch's subpatch? like kinda like pd-plom.pd-plom1 for plom1 array to be shown?

help with polyphonic synth
I realized, after posting that, that there are two ways of thinking about the "extra parameters" going into the synth clone, which for lack of a better term I could call "global" vs "local" parameters.
Local parameters are "per-note" -- they are set at the time the note begins, and they hold their value for the duration of the note. The next note (which might overlap) could have completely different values.
Global parameters affect all notes simultaneously. This is the usual way that, for instance, filter frequency works. You twist the filter cutoff knob and all notes' cutoff changes simultaneously (even though each note could have its own filter cutoff envelope).
At minimum, pitch (note number or frequency) and velocity (on/off trigger) should be per-note. Other parameters could be global or local (and you can mix those styles).
As far as I can see, the best way is:
- All local parameters get packed into a list, along with the clone instance number (which is supplied by [poly]). The "local" list goes into the leftmost input, and only the leftmost.
- "Global" parameters add one or more inlets to the right. Note carefully in the [clone] help file that control inlets need to tag their values for specific instances. If we're using these as global parameters, then the tag should be
all. Signal inlets are always global.
IMO it's best to be consistent about the handling of these input types, to avoid introducing bugs into your patch.
Example with filter cutoff and envelope parameters treated globally:


Example with filter cutoff and envelope parameters treated locally:


(Note: The example patches use the ELSE external library, and the global one uses cyclone.)
Hope this helps. IMO polysynth is a basic use case for any audio programming environment; if what I've posted here can't be easily figured out from the documentation, then it suggests a gap in the help. (One reason why I worked it out is that I teach a class in Pd; if the students ask "how do I make a poly synth?" then I'd better have an answer at the ready. So I tried a few ways and came up with this as a basic template that Just Works... then, just do it that way.)
hjh
Collection of Pd internal messages, dynamic patching
@dfkettle Most do, all but the top message there is still valid. pd once again has dynamic patching in its help files, open the help browser and navigate to Pure Data/5.reference/pd-messages.pd. [iemguts/receivecanvas] and [r pd] connected to print will help you discover messages you can send to [iemguts/sendcanvas], [s pd] or a named canvas. Browsing your patch files in a text editor and the pd file format ref are also helpful, and I recently posted a useful abstraction for dynamic patching, removes the need for referring to the file format ref/patches to find out object info and connection messages, look.
Edit: As too creating an abstraction dynamically like this, the easiest way I know of to do this these days is too send the stuff to a subpatch and then send the [savetofile( message to the subpatch. Not perfect but it works, [look] uses this technique, it copies your selection to a subpatch in the abstraction, sends [savetofile( to the subpatch and then opens that saved file into a text and prints it to the log window. If you use this method you probably would also want to edit the #N canvas message of the saved file to delete the 6th field (the name of the subpatch) and change the 7th field from 0 to what ever font size you want the abstraction to use, simple enough to automate.




