Pass entire signal vector to buffer? t_signal? What is double **ins pointing to?

David Landon's icon

Hi All,

I'm working on writing an external that sends max audio signal over the internet, via UDP, directly from Max/MSP. I'm using Libuv for asynchronous I/O in an effort to reduce latency.

My question is this: how can I copy the entire signal vector at once, into a buffer that I can then send. I've reviewed the original Olaf Matthes netsend~ code and then the same netsend~ as updated by Remu and Oliver Guillerminet, and they use the old style performance methods where t_signal **sp is passed to the method and then the signal vector can be grabbed from sp->s_vec.

The new dsp64 process uses double, I know. And I _believe_ that it is a double pointer to another pointer that is an array of the samples, but without access to the code that passes variables into that routine, I'm fumbling around, not really knowing what's going on "under the hood". Does anybody have any insight into how to do this?

At this point, my best guess would be to hop into the perform64 method, and do something to the effect of:
t_double *inL = ins[0];
and then do something like:
memcpy(my_vector, inL , sizeof(maxvectorsize))???

Thoughts? Ideas? Any help would be GREATLY appreciated!

* As an aside: I know that audio over internet can be done using TCP via jit.catch and then jit.net.send. Though, my goal is to see what would happen if i were to forgo quality as a means of minimizing latency. The C74 post describing the above mentioned process mentions not seeing any performance gains using UDP (wouldn't it be sooooo nice if they would release that code anyway?), but I'm wondering if there's a point, with super small vector sizes, that serious, synchronized live performance could be had, even if some packets are lost in transport.

mzed's icon

Outside of perform, I've done:

#define BUFMAX 4096
double *myBuffer;
long Vs;
x->myBuffer = (double *)sysmem_newptr(BUFMAX * sizeof(double));

In DSP method:
x->Vs = maxvectorsize;

Then in perform:
memcpy(x->myBuffer, ins[0], sizeof(double) * x->Vs);

David Landon's icon

Hi MZED! Thank you, thank you, thank you. It looks like I was on the right track, but holy heck it certainly is comforting when somebody shares some code that has already worked for them. :)

I'll give it a go right now and report back. And if anyone else has other suggestions, I'm open to them, so keep it coming. Thanks again.

David Landon's icon

Hi MZED, that works like a charm. I had to do a little finagling because the buffer that Libuv uses has a character array. If anyone ever comes across this looking to do what I'm doing it seems to be working. I haven't got the receiving side completed yet, so I'm not totally sure. This is my first time working in C, so anyone seeing problems with the code below, feel free to chime in. :)

In the object's structure:
uv_buf_t buf;
long vs;

In dsp64:
x->vs = maxvectorsize;
x->buffer.base = (char*)malloc(sizeof(double) * maxvectorsize);
x->buffer.len = maxvectorsize;

In perform64:
memcpy(x->buffer.base, ins[0], sizeof(double) * x->vs);
uv_udp_try_send (with all of my handles and addresses as per Libuv's specs)

David Landon's icon

Hi all,

One more quick question. Now that I've got the signal passed to my buffer, I'm sending it over the network and memcpy'ing it into the memory of another pointer in the perform64 method, and then passing that to the outlet. So far, it looks like the only way to get the signal out is by referencing that new pointer and passing it out, sample by sample. That is: while (n--) *out++ = *my_buf++;

Can this be right? Why would I have to pass the samples to the outs array one at a time? I tried doing a memcpy(outs[0], my_buf, sampleframes * sizeof(double)), but that didn't seem to work...

If anyone wants to take a look at the code, I've got it up on GitHub: https://github.com/dlandon86. There are two repositories there, one for the send and another for the receive. It's a little bonkers because of the Libuv code, but the max stuff is fairly straightforward. This is my first time coding... ever, so feel free to pick it apart! :)

Best,
David