What is a good way to share data between gen~ patches?

zolikov's icon

Hi,

I created two gen~ patches. One of them shares a momentary value of a phasor operator through a buffer~ object. The second gen~ patch reads this buffer and this way the data is shared.
As a control, I sent this information back to the first gen~ patch the same way. The third scope~ object shows the difference between the original signal and the signal that was travelled.
It seems like they are not 100% in sync. What would be the best way to share data between gen~ objects?

First, I set the buffer length to 1 sample, but for some reason, the experiment didn't work.

Max Patch
Copy patch and select New From Clipboard in Max.


Graham Wakefield's icon

Somewhat guesswork because I think you also need to share the "sender" and "receiver" patchers, but my suspicion may be because you are overwriting the same buffer slot on every sample.

Sharing data between different gen~ objects is subject to all the same conditions as sharing between any MSP objects. [gen~] itself is an MSP object. The genpatcher inside it is a different thing entirely, but you can think of it as being a sub-context that runs at a vector size of 1.

So the way to think of it is this:
- MSP objects process audio in blocks of time. The block of time is determined by the signal vector size in the audio status settings. E.g. mine is currently set to 32, so 32 samples of audio are processed by one MSP object, then 32 samples of audio by the next MSP object, and so on, until all the MSP objects have done the work, and time can advance, and the next lot of 32 samples goes through the whole chain again.
- Inside a gen~ patcher it is different -- you can think of it as always having a signal vector size of 1, so every object does its work on 1 sample at a time.
- But the interface between gen~ and the outside world is always in those longer 32 blocks. So one gen~ object does 32 lots of 1-sample at a time work, then the next gen~ obejct does 32 lots of 1-sample at a time work, and so on.
- That is: only 1 MSP object is actually doing work at once, and that includes gen~ objects. Although the MSP patcher gives the illusion of running lots of things at the same time, in reality only one MSP object is running at any particular time, and they pass audio data between each other in vectors of samples. All of this happens faster than real time, so you don't hear it.

So, going back to the buffer~ sharing example, if one gen~ object is writing into e.g. frame 0 of a buffer~, it will keep overwriting this value until the 32nd iteration. Then the next gen~ object will start reading from that buffer, picking up whatever was left, running for 32 iterations, and then it's done. Then the next, etc.

Now if the data you are sharing updates more slowly than MSP's vector size, that's fine. But otherwise, you'll be losing data. If you want to share audio-rate data between gen~ patchers, you could use a buffer~ of length 32, write data into consecutive frames of the buffer~ in one gen~, and read these frame by frame in the other gen~. But really what you would have done there is implement exactly what an MSP patch cable does. That is, the best way to stream audio between gen~ objects is via audio cables.

Short answer: you can't send data between different gen~ patchers faster than MSP's vector size.

You can, however, embed one genpatcher inside another genpatcher, all inside one gen~ object, where they can talk to each other with single-sample latency or less, and that would be the recommended way to go if that's what you need.

---

Unrelated tip: [buffer xxx @samps 2] would save the loadbang/msg combo.

zolikov's icon

Hi Graham, thank you very much for your comment - I really appreciate all the detail. It is precisely because I was struggling with understanding how the objects work in relation to each other that was experimenting with this patch. It was not clear for me that only one object can work at a time. Your comment is very helpful, and embedding the gen~ patchers can be a solution for me. I see the logic of the whole process much clearer now.

PS. thaks for the unrelated tip too!