Using BuffFFT with pmono

Hey there, this is probably one specifically Sam Pluta but appreciate any help

I am trying to use BuffFFT within a synthdef, played back with pmono. The below code works for calling Synth(), but not with pmono. I pass the analysis array of buffers to BufFFTTrigger as a ref array, but I still only hear one of the two overlaps when I use pmono.

(
~makeSpec = {|file, dict, fftSize, overlaps=2|
    dict.put(\filepath, file);
    dict.put(\file, Buffer.readChannel(s, file, channels: [0]));
    dict.put(\fftSize, fftSize);
	//overlaps hardcoded
	// dict.put(\overlaps, overlaps);
    dict.put(\analysis, Array.fill(overlaps, {Buffer.alloc(s, fftSize)}).asRef);
};

SynthDef(\fftStretch_mono, {|buf, fftSize, analysis=#[0, 1]|
    var sig;
    var chain;
    var pos;
    var startsamp, endsamp;
    var bufFrames = BufFrames.kr(buf);
	
	//args equiv to 1/overlap, 0..overlap, overlap for overlap=2
	chain = BufFFTTrigger(analysis, 0.5, [0, 1], 2);
	
	//or this?
	// chain = BufFFTTrigger(\analysis.ir(#[0, 1]), 0.5, [0, 1], 2);

    startsamp = (\pos.kr(0) * bufFrames);
    endsamp = startsamp + (\len.kr(1) * bufFrames);

    pos = Phasor.ar(
        rate: \rate.kr(1),
        start: startsamp,
        end: endsamp,
    );

    chain = BufFFT_BufCopy(chain, buf, pos, BufRateScale.kr(buf));
    chain = BufFFT(chain);
    chain = PV_Diffuser(chain, chain>(-1));

    sig = Mix(BufIFFT(chain, 0)).dup*0.8;
    sig = sig * \gain.kr(0).dbamp;
    sig = sig * \amp.kr(1);
	sig = sig.sanitize;
    Out.ar(\out.kr(0), sig);
}).add;
)

(
~specBuff=Dictionary();
~makeSpec.(Platform.resourceDir +/+ "sounds/a11wlk01.wav", ~specBuff, 8192, 2)
)

//WORKS
(
Synth(\fftStretch_mono,
	[buf: ~specBuff.at(\file), analysis: ~specBuff.at(\analysis), fftSize: ~specBuff.at(\fftsize), rate: 0.01, pos: 0.3, len: 0.05])
)

//DOESNT
(
Pmono(\fftStretch_mono,
    \buf, ~specBuff.at(\file),
    \analysis, ~specBuff.at(\analysis),
    \fftSize, ~specBuff.at(\fftSize),
    \rate, 0.01,
    \pos, 0.3,
    \len, 0.05,
).trace.play(t);
)

A perhaps surprising observation is that Pmono isn’t “mono” – it can play chords.

(
p = Pmono(\default,
	\degree, Pwhite(-7, 7, inf) + #[0, 2, 4],
	\dur, Pwhite(1, 3, inf) * 0.25,
).play;
)

p.stop;

The default event prototype defines a meaning for arrayed values: create multiple synths, and distribute the array values across those synths.

If you wrap your array in another layer of array, then the meaning is:

  • Outer array contains one element, so one synth will be made.
  • This one synth will receive the entire inner array for the given parameter.

Pmono does not override this meaning.

(
Pmono(\fftStretch_mono,
    \buf, ~specBuff.at(\file),
    \analysis, [~specBuff.at(\analysis)],
    \fftSize, ~specBuff.at(\fftSize),
    \rate, 0.01,
    \pos, 0.3,
    \len, 0.05,
).trace.play(t);
)

Not sure if there are other problems, but this is definitely a bit of fine print that will affect your results.

hjh

1 Like

Thank you, this worked! it was my understanding that backtick or .asRef was used to denote this, and I was pretty sure that it worked without wrapping [ ] with Pbind/non-pmono patterns. Is this not the case?

I don’t recall the history, but it isn’t the case now:

(freq: [200, 300]).play;

[ "#bundle", 16898226057054405476, 
  [ 9, "default", 1000, 0, 1, "out", 0, "freq", 200, "amp", 0.1, "pan", 0 ],
  [ 9, "default", 1001, 0, 1, "out", 0, "freq", 300, "amp", 0.1, "pan", 0 ]
]
[ "#bundle", 16898226060490379313, 
  [ 15, 1000, "gate", 0 ],
  [ 15, 1001, "gate", 0 ]
]


(freq: [[200, 300]]).play;

[ "#bundle", 16898226201727454778, 
  [ 9, "default", 1002, 0, 1, "out", 0, "freq", [ 200, 300, ], "amp", 0.1, "pan", 0 ]
]
[ "#bundle", 16898226205163428614, 
  [ 15, 1002, "gate", 0 ]
]


(freq: `[200, 300]).play;

[ "#bundle", 16898226292506929559, 
  [ 9, "default", 1005, 0, 1, "out", 0, "freq", 200, "amp", 0.1, "pan", 0 ],
  [ 9, "default", 1006, 0, 1, "out", 0, "freq", 300, "amp", 0.1, "pan", 0 ]
]
[ "#bundle", 16898226295942903396, 
  [ 15, 1005, "gate", 0 ],
  [ 15, 1006, "gate", 0 ]
]

(When in doubt, devise a minimal test.)

hjh

1 Like

Ohhh wait… you might have been thinking of Klang and Klank UGens. It is true for those, but not true for events.

hjh

1 Like

Never responded to this but yes, that is exactly what I was thinking of. I made the assumption that BufFFTtrigger required ref arrays in the first place - I was conceptualising it as processing multiple FFT windows per synthdef rather than “polyphonically”