I'm trying to code an object with a variable number of inlets and outlets, that's more complex than the one I posted a few days ago. Writing to its input works fine, but when I try to write to its output, Pd crashes. The culprit is when I try to access each individual output.
In the new routine, I allocate memory likes this:
``` x->x_in = (t_sample **)getbytes(ninlets * sizeof(t_sample *)); x->x_out = (t_sample **)getbytes(noutlets * sizeof(t_sample *)); for (i = 0; i < ninlets; i++) x->x_in[i] = (t_sample *)getbytes(x->x_blksize * sizeof(t_sample)); for (i = 0; i < noutlets; i++) x->x_out[i] = (t_sample *)getbytes(x->x_blksize * sizeof(t_sample)); ```
But Pd crashes when I try to access any output other that x->x_out[0][0]. In a function that is called by the perform routine, I do the following:
``` for (i = 0; i < x->x_noutlets; i++) { x->x_out[i][x->x_sample_index] = (t_sample)x->x_outvec[i]; } ```
and Pd crashes. Debugging with gdb pointed to this line. Changing the code to x->x_out[0][0] does not crash Pd. I have also confirmed that x->x_outvec[i] is not crashing Pd.
Since memory for x->x_out has been allocated, and since I'm not trying to access an element beyond this allocated memory (which is also confirmed), why does Pd crash? Or am I doing something wrong in the memory allocation part?
I'm pretty sure it's because x_blksize is 0. (Internally, getbytes() always allocates at least 1 byte, which explains why you can successfully access the first sample.)
In the new routine, I allocate memory likes this:
In the new routine, you may only allocate the vectors that hold the input and output signals (t_sample **), as the number of channels won't change (well, unless you are creating a multi-channel object).
However, if you try to allocate buffers to cache the inputs, you can only do that in the "dsp" method, as this is the place where you know the actual blocksize.
I'm not really sure what you're trying to do. "x_in" and "x_out" are of type "t_sample **", so I would assume that they are supposed to hold the input/output signal vectors. However, then you allocate actual signal buffers for each channel which makes no sense to me. If you want to save the inputs, this would have to be *another* buffer. (Ideally, you would save all input signals in a single continuous buffer for better cache utilization.) There is (almost) never be a need to buffer the outputs*).
---
BTW, instead of posting code snippets, it would be more helpful to post (a link) to the whole source code, so we can get a better picture of what you're trying to do.
Christof
*) the only exception I can think of is when you use a library that uses a fixed floating point precision that does not match Pd's own precision. For example, I need to do this in my [vstplugin~] object, so it can use single-precision-only VST plugins in a double-precision Pd.
On 22.09.2023 12:32, Alexandros Drymonitis wrote:
I'm trying to code an object with a variable number of inlets and outlets, that's more complex than the one I posted a few days ago. Writing to its input works fine, but when I try to write to its output, Pd crashes. The culprit is when I try to access each individual output.
In the new routine, I allocate memory likes this:
x->x_in = (t_sample **)getbytes(ninlets * sizeof(t_sample *)); x->x_out = (t_sample **)getbytes(noutlets * sizeof(t_sample *)); for (i = 0; i < ninlets; i++) x->x_in[i] = (t_sample *)getbytes(x->x_blksize * sizeof(t_sample)); for (i = 0; i < noutlets; i++) x->x_out[i] = (t_sample *)getbytes(x->x_blksize * sizeof(t_sample));
But Pd crashes when I try to access any output other that x->x_out[0][0]. In a function that is called by the perform routine, I do the following:
for (i = 0; i < x->x_noutlets; i++) { x->x_out[i][x->x_sample_index] = (t_sample)x->x_outvec[i]; }
and Pd crashes. Debugging with gdb pointed to this line. Changing the code to x->x_out[0][0] does not crash Pd. I have also confirmed that x->x_outvec[i] is not crashing Pd.
Since memory for x->x_out has been allocated, and since I'm not trying to access an element beyond this allocated memory (which is also confirmed), why does Pd crash? Or am I doing something wrong in the memory allocation part?
Pd-dev mailing list Pd-dev@lists.iem.at https://lists.puredata.info/listinfo/pd-dev
On 9/22/23 14:26, Christof Ressi wrote:
BTW, instead of posting code snippets, it would be more helpful to post (a link) to the whole source code, so we can get a better picture of what you're trying to do.
I'm aware of that, but it's a rather big project, around 5000 lines, and I haven't published it yet. It's based on [neuralnet], which is hosted here https://github.com/alexdrymonitis/neuralnet. I'm trying to create a signal version of this object. The control object takes lists of data, but the signal will have to take signals, therefore it must have a variable number of inlets and outlets, depending on the network structure. I could go with multichannel signals, but trying to code a simple external a few days ago, didn't get me very far.
It's in my plans, once I get this variable I/O sorted,to add the possibility to pack signals to a multichannel inlet or outlet, but that's for a later stage.
I'm pretty sure it's because x_blksize is 0. (Internally, getbytes() always allocates at least 1 byte, which explains why you can successfully access the first sample.)
x_blksize is not 0, it gets the value returned from sys_getblksize(). It is also updated in the dsp routine, in case the block size changes, where I resize the bytes of the inlets and outlets with resizebytes().
In the new routine, I allocate memory likes this:
In the new routine, you may only allocate the vectors that hold the input and output signals (t_sample **), as the number of channels won't change (well, unless you are creating a multi-channel object).
So you're saying that I only need to do the initial allocation, like this:
`x->x_in = (t_sample **)getbytes(ninlets * sizeof(t_sample *));`
and not try to allocate `t_sample *` bytes in the for loop? I did try this, but again the object is crushing.
What I'm trying to do is get the input signals, copy them to a t_atom vector, process the input (it's a neural network object), and then copy the processed data which is stored in a *t_float, to the outlets of the object.
To do this, in the perform routine, I run the following loop:
``` for (i = 0; i < n; i++) { for (j = 0; j < ninlets; j++) { x->x_input[0][j] = x->x_in[j][i]; } x->x_sample_index = i; forward_pass(x); } ```
`n` is the block size. Then `forward_pass()` ends up in what I posted in the OP. Here it is again:
``` for (i = 0; i < x->x_noutlets; i++) { x->x_out[i][x->x_sample_index] = (t_sample)x->x_outvec[i]; } ```
In my understanding, if the necessary allocated memory for the outlets has indeed been allocated, why would this crash?
I'm not really sure what you're trying to do. "x_in" and "x_out" are of type "t_sample **", so I would assume that they are supposed to hold the input/output signal vectors. However, then you allocate actual signal buffers for each channel which makes no sense to me.
I guess it doesn't make sense to someone who knows C and the Pd API very well, but I'm not one of them :) I've coded a few externals, but this one is more complex and I'm trying to get my head around this.
So you're saying that I only need to do the initial allocation, like this:
`x->x_in = (t_sample **)getbytes(ninlets * sizeof(t_sample *));`
and not try to allocate `t_sample *` bytes in the for loop? I did try this, but again the object is crushing.
Yes, because "x_in" and "x_out" are supposed to hold the signal vectors ("s_vecf") of the inlets and outlets, which you would assign in the "dsp" method.
Christof
Getting back here after a while, just to confirm that Christof was right. I would like to clarify if the following chunk is necessary to be placed in the dsp routine:
``` t_sample **dummy = x->in; for (i = 0; i < x->inchnls; i++) *dummy++ = sp[i]->s_vec; dummy = x->out; for (i = x->inchnls; i < x->inchnls+x->outchnls; i++) *dummy++ = sp[i]->s_vec; ```
Without this the object crashes. From what I understand, the sp pointer contains the input and output samples, together with the block size, right? So, it's necessary to write the input and output to the pointer of pointers for the inlets and outlets.
Anyway, thanks for the help.
Alexandros
On 9/23/23 11:39, Christof Ressi wrote:
So you're saying that I only need to do the initial allocation, like this:
`x->x_in = (t_sample **)getbytes(ninlets * sizeof(t_sample *));`
and not try to allocate `t_sample *` bytes in the for loop? I did try this, but again the object is crushing.
Yes, because "x_in" and "x_out" are supposed to hold the signal vectors ("s_vecf") of the inlets and outlets, which you would assign in the "dsp" method.
Christof
Pd-dev mailing list Pd-dev@lists.iem.at https://lists.puredata.info/listinfo/pd-dev
Yes. the perform routine needs to access the signal vectors.
If the object has a fixed number of inlets and outlets, you simply pass the signal vectors directly to `dsp_add`.
If the number of inlets and outlets is variable, you have to store the signal vector pointers somewhere in the object.
Note that in the latter case, you could also use `dsp_addv`, where the `t_int` arguments are passed as an array. This is left as an exercise to the reader :)
Christof
On 10.10.2023 12:27, Alexandros Drymonitis wrote:
Getting back here after a while, just to confirm that Christof was right. I would like to clarify if the following chunk is necessary to be placed in the dsp routine:
t_sample **dummy = x->in; for (i = 0; i < x->inchnls; i++) *dummy++ = sp[i]->s_vec; dummy = x->out; for (i = x->inchnls; i < x->inchnls+x->outchnls; i++) *dummy++ = sp[i]->s_vec;
Without this the object crashes. From what I understand, the sp pointer contains the input and output samples, together with the block size, right? So, it's necessary to write the input and output to the pointer of pointers for the inlets and outlets.
Anyway, thanks for the help.
Alexandros
On 9/23/23 11:39, Christof Ressi wrote:
So you're saying that I only need to do the initial allocation, like this:
`x->x_in = (t_sample **)getbytes(ninlets * sizeof(t_sample *));`
and not try to allocate `t_sample *` bytes in the for loop? I did try this, but again the object is crushing.
Yes, because "x_in" and "x_out" are supposed to hold the signal vectors ("s_vecf") of the inlets and outlets, which you would assign in the "dsp" method.
Christof
Pd-dev mailing list 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