Hello all,
I was wondering how one would go about creating an external that given two creation arguments created that many inlets and outlets? I've been browsing the source code for externals that do something similar, but I think I'm going to need a bit more of an explanation.
Thanks for the help.
see the code of cyclone/mtx~ for instance
basically, you do" for(i = 0; i < n_inlet; i++) inlet_new()...
and stuff
Em sex., 22 de mai. de 2020 às 23:17, Eric Lennartson < lennartsoneric@gmail.com> escreveu:
Hello all,
I was wondering how one would go about creating an external that given two creation arguments created that many inlets and outlets? I've been browsing the source code for externals that do something similar, but I think I'm going to need a bit more of an explanation.
Thanks for the help. _______________________________________________ Pd-dev mailing list Pd-dev@lists.iem.at https://lists.puredata.info/listinfo/pd-dev
is there a reason that cyclone/matrix~ is using dsp_add over dsp_addv?
On Fri, May 22, 2020 at 8:26 PM Alexandre Torres Porres porres@gmail.com wrote:
see the code of cyclone/mtx~ for instance
basically, you do" for(i = 0; i < n_inlet; i++) inlet_new()...
and stuff
Em sex., 22 de mai. de 2020 às 23:17, Eric Lennartson < lennartsoneric@gmail.com> escreveu:
Hello all,
I was wondering how one would go about creating an external that given two creation arguments created that many inlets and outlets? I've been browsing the source code for externals that do something similar, but I think I'm going to need a bit more of an explanation.
Thanks for the help. _______________________________________________ Pd-dev mailing list Pd-dev@lists.iem.at https://lists.puredata.info/listinfo/pd-dev
Other examples would be zexy's [mux~] and [demux~].
is there a reason that cyclone/matrix~ is using dsp_add over dsp_addv?
Generally, you don't *need* to pass the individual signal buffers to dsp_add. Many externals with variable inputs/outputs simply allocate an array of t_float pointers inside the object and store the signal buffers there, meaning that they don't pass them to dsp_add at all. It's just a matter of personal style.
One word of warning about externals with multiple signal inputs/outputs (quoting from https://github.com/pure-data/externals-howto#signal-classes):
"Optimisation of the DSP-tree tries to avoid unnecessary copy-operations. Therefore it is possible, that in- and out-signal are located at the same address in the memory. In this case, the programmer has to be careful not to write into the out-signal before having read the in-signal to avoid overwriting data that is not yet saved."
This is still a bit vague, though, I would rephrase it like this:
"In this case, the programmer has to be careful not to write into *any* out-signal before having read *all* in-signals"
Christof
On 23.05.2020 09:21, Eric Lennartson wrote:
is there a reason that cyclone/matrix~ is using dsp_add over dsp_addv?
On Fri, May 22, 2020 at 8:26 PM Alexandre Torres Porres <porres@gmail.com mailto:porres@gmail.com> wrote:
see the code of cyclone/mtx~ for instance basically, you do" for(i = 0; i < n_inlet; i++) inlet_new()... and stuff Em sex., 22 de mai. de 2020 às 23:17, Eric Lennartson <lennartsoneric@gmail.com <mailto:lennartsoneric@gmail.com>> escreveu: Hello all, I was wondering how one would go about creating an external that given two creation arguments created that many inlets and outlets? I've been browsing the source code for externals that do something similar, but I think I'm going to need a bit more of an explanation. Thanks for the help. _______________________________________________ Pd-dev mailing list Pd-dev@lists.iem.at <mailto:Pd-dev@lists.iem.at> https://lists.puredata.info/listinfo/pd-dev
Pd-dev mailing list Pd-dev@lists.iem.at https://lists.puredata.info/listinfo/pd-dev
On Sat, 2020-05-23 at 12:57 +0200, Christof Ressi wrote:
One word of warning about externals with multiple signal inputs/outputs (quoting from https://github.com/pure-data/externals-howto#signal-classes): "Optimisation of the DSP-tree tries to avoid unnecessary copy- operations. Therefore it is possible, that in- and out-signal are located at the same address in the memory. In this case, the programmer has to be careful not to write into the out-signal before having read the in-signal to avoid overwriting data that is not yet saved." This is still a bit vague, though, I would rephrase it like this: "In this case, the programmer has to be careful not to write into *any* out-signal before having read *all* in-signals"
Sounds to me like:
"In order to be absolutely sure to avoid unnecessary copy operations, you must perform copy operations."
I'm no C programmer, but I don't see how you can read *all* data before writing *without* copying it around.
Roman
"In order to be absolutely sure to avoid unnecessary copy operations, you must perform copy operations."
I think there's a misunderstanding about. Let's assume a cross fader object with three signal inputs (sig2, sig2 and mix) and have a look at the following pseudo-code:
BAD:
mix = inlet3[i]
outlet[i] = inlet1[i] * (1 - mix)
outlet[i] = outlet[i] + inlet2[i] * mix
The first line might accidentally override the value of inlet2[i]
OK:
outlet[i] = inlet1[i] * (1 - inlet3[i]) + inlet2[i] * inlet3[i]
You can see that it's possible to read the inputs with making a copy.
GOOD:
mix = inlet3[i]
outlet[i] = inlet1[i] * (1 - mix) + inlet2[i] * mix
It's better to copy the value of inlet3[i] in a temporary variable than repeatedly accessing heap memory. The compiler would typically keep the value in a register. In fact, it would do the same with the "OK" example because it can see that the value of inlet3[i] doesn't change.
---
If you have several signal outlets, you might need to "copy" the input, but this is not necessarily a bad thing. Let's have a look at a pan object, again in pseudo code:
in = inlet1[i]
f = inlet2[i]
outlet1[i] = in * (1 - f)
outlet2[i] = in * f
We have to store the input values in temporary variables before writing to the outputs. Actually, this is better than accessing heap memory repeatedly and the compiler can keep the values "in" and "f" in registers.
---
Now here's an example where we need to "copy" the input without any obvious merit. Let's assume we want a multiline object:
in1 = inlet1[i]
in2 = inlet2[i]
vol = inlet3[i]
outlet1[i] = in1 * vol
outlet2[i] = in2 * vol
It turns out that this isn't really bad, either. x86 instructions can't take memory addresses both as source and destination operands, so the compiler has to load the input into registers anyway.
---
Finally, buffer aliasing is also about saving memory and reducing cache misses, probably more than avoiding copy operations.
Christof
On 23.05.2020 15:11, Roman Haefeli wrote:
On Sat, 2020-05-23 at 12:57 +0200, Christof Ressi wrote:
One word of warning about externals with multiple signal inputs/outputs (quoting from https://github.com/pure-data/externals-howto#signal-classes): "Optimisation of the DSP-tree tries to avoid unnecessary copy- operations. Therefore it is possible, that in- and out-signal are located at the same address in the memory. In this case, the programmer has to be careful not to write into the out-signal before having read the in-signal to avoid overwriting data that is not yet saved." This is still a bit vague, though, I would rephrase it like this: "In this case, the programmer has to be careful not to write into *any* out-signal before having read *all* in-signals"
Sounds to me like:
"In order to be absolutely sure to avoid unnecessary copy operations, you must perform copy operations."
I'm no C programmer, but I don't see how you can read *all* data before writing *without* copying it around.
Roman
Pd-dev mailing list Pd-dev@lists.iem.at https://lists.puredata.info/listinfo/pd-dev