PV_BufRd analysis of multiple soundfiles

It looks like you have some confusion about handling the array of record buffers.

	pvRecBuf: ~rates.collect { |rate, i|
		Buffer.alloc(s, (soundfile.duration / rate).calcPVRecSize(~windowSize, ~hopSize))

… so you will have one buffer per rate, for each file.

 SynthDef(\pv_BinBufRd, {
    	arg out=0, posLo=0.1, recBufs=0, sndBuf=0, posHi=0.9,

… but the synthdef permits only one value for recBufs. recBufs is a plural name, but 0 is a singular value – so, the argument (which knows nothing about English grammar) will accept only a singular value.

    		\recBufs, Pfunc{|event|

Then, this is providing an array of buffers to the event.

In the default event prototype, an array for a parameter means to create one synth per array element. You have 12 rates → 12 buffers → 12 synths… hold on… \dur, 0.125,… 12 synths, 8 times per second. Synth duration is 1 (based on your envelope) so you should have up to 96 synths at any moment. (Note also that, because the SynthDef accepts only one value here, there is literally no other way for the event to handle an array for this parameter.)

And the SynthDef multichannel-expands chains by ~rates so you have 96 synths x 12 FFT chains per synth = 1152 simultaneous FFT chains.

So a high degree of CPU usage is not exactly surprising.

I guess what you’re expecting is a single synth doing 12 FFT chains, 8 times per second = 96 FFT chains. For that, you would need sndBufs to be an array argument. The size is determined by ~rates, so you cannot declare sndBufs as an arg. You can use NamedControl. So, delete it from the arg list, and then in the variable declarations:

var sndBufs = NamedControl.kr(\sndBufs, Array.fill(~rates.size, 0));

Then in your pattern, you need the array of buffers to be treated not as multi-synth expansion, but as an array included in a single message. This is done by wrapping the array in another array level:

    		\recBufs, Pfunc{|event|
    			[ ~buffers[\laser][event[\bufIndex]][\pvRecBuf] ]


thanks for your help @jamshark70 .

Then I think I have a general misunderstanding of PV_BinBufRd.
In the Example the analysed Soundfiles are stored with different ~rates in ~recBufs and the original Soundfile is stored in ~soundBuf. In the SynthDef the original Soundfile stored in~soundBuf has been put into Playbuf.ar together with the array of ~rates for the rate argument. The Array of analysed Soundfiles with their corresponding rates stored in ~recBufs has been put into PV_BinBufRd.

Analysis from Example:

~rates = (1..12) * 0.1 + 0.4;

// need FFT buffers from different lengths
~recBufs = ~rates.collect { |rate, i|
	Buffer.alloc(s, (~soundfile.duration / rate).calcPVRecSize(~windowSize, ~hopSize));

// one sound buffer is enough in this case
~soundBuf = Buffer.read(s, ~path);

// make analysis of same buffer played back at different speeds

~rates.do { |rate, i| Synth(\pvrec_2, [\recBuf, ~recBufs[i], \soundBufnum, ~soundBuf, \rate, rate]) }

SynthDef from Example :

// need FFT before PV_BinBufRd !
chains = FFT(fftBufs, PlayBuf.ar(1, ~soundBuf, ~rates, loop: 1));
chains = PV_BinBufRd(chains, ~recBufs, pos, 0, 2, 10, clear);

when I now declare:

var sndBufs = NamedControl.kr(\sndBufs, Array.fill(~rates.size, 0));

in my SynthDef and change PV_BinBufRd to:

// need FFT before PV_BinBufRd !
chains = FFT(fftBufs, PlayBuf.ar(1, sndBufs, BufRateScale.kr(sndBufs), loop: 1));
chains = PV_BinBufRd(chains, recBufs, pos, 0, 2, 10, clear);

and put

\sndBufs, Pfunc{|event|


\recBufs, Pfunc{|event|
    			[ ~buffers[\laser][event[\bufIndex]][\pvRecBuf] ]

in the Pbind i have to exchange the rate argument in Playbuf.ar from ~rates to BufRateScale.kr(sndBufs) right? otherwise i get a really harsh, high frequency.

when i use the dictionary in other SynthDefs without any arrays I can just use the path to an analysed soundfile with a specific rate in the Pbind like this, right?

\recBufs, ~buffers[\laser][0][\pvRecBuf][5]

I don’t understand why you’re switching to sndBufs now. The problem was with recBufs.

My suggestion was to make recBufs an arrayed input, but this latest code snippet looks like you applied that advice to sndBuf(s) instead. The behavior shouldn’t be expected to be the same. (I think this explains the high frequency too.)

Yes, if it’s not an arrayed control, then you can just put one buffer into the event directly.


hey, im sorry you said sndBufs in your post. I changed everything and its working now. thanks alot.

smacks forehead

You’re right, it’s a typo in my post.

Really sorry about that… a bit embarrassed. Just one word wrong, and it was kinda the most important one.


haha no problem, thanks for your help :slight_smile: