re: amp follower on filterbank
easy to cook up something straightforward like this. (i’m using 24 bands on the bark scale, but this is kind of arbitrary.)
[ https://gist.github.com/catfact/288693fa47cbd5d15f04c6452f42a7c7 ]
now, one caveat is that this is not really a “good” filterbank - supercollider doesn’t really have one out of the box. (AFAIK! would love to be corrected.)
by “good” i mean that recombining these subband signals will result in something not much like the original. and subband phase is distorted such that anything but pretty coarse analysis like this envelope following, will not be super useful. for this it’s fine. for more stringent applications there are more effortful options.
re: spec flatness
“spectral flatness” aka weiner entropy == geometric mean of power spectrum / arithmetic mean. so it’s low if the signal is “peaky” and high if it’s flat.
supercollider has a SpectralFlatness ugen to do this calculation on an FFT chain. NB that its output is linear, but in most psychoacoustic literature it is -db.
NB that also in psychoacoustics, it’s common to take weiner entropy of a subband for analysis. but the SC ugen won’t let you do this - it always takes the power spectrum of the whole signal. so i don’t think the results from literally feeding SpectralFlatness with a bandlimited signal will be very psychoacoustically meaningful (it will mostly be a function of subband total amplitude, width, placement, and of the filter rollof characteristics.)
that said, this naive “subband flatness” will do something, and can probably be sort of ad-hoc normalized per subband. probably good enough for music.
but if you literally want to get spec. flatness of many subbands, i’d consider trying to do the filtering in the frequency domain:
- take
FFT of signal
- use
PV_Copy for each subband
- use
PV_BrickWall to bandpass
- (the tricky part) use
.pvcalc to compute the weiner entropy of each subband directly. something approximately like:
{
arg mags, phases;
var mean, geomean, weiner;
var n, y;
n = mags.size;
// return arrays, zero initially
y = [ mags.collect({0}), phases.collect({0}) ];
mean = mags.sum / n;
geomean = exp(mags.collect({|m| log(m)}).sum / n);
weiner = geomean / mean;
y[0][0] = weiner;
y
}
(^ this is totally untested, and i haven’t really tried this specific method. the theory is that placing the calculated value in the DC magnitude bin, then running IFFT, should give you a DC signal corresponding to that value, which can then be written to a control bus. let me know if you’ve tried this or other tricks to get .kr out of a pvcalc!)
the bad news is, this .pvcalc function will be very resource intensive. the good news is, it can be set up to only run on the relevant FFT bins for each subband, saving resources and also giving a mathematically meaningful result.
but TBH i’ve found supercollider a bit frustrating for this kind of low-level work on STFT data - this is one of many instances where its easier to just make a custom ugen if you have c++ chops. (here max/msp is actually quite nice since these days, you can put gen code in a phase vocoder subpatcher.)
re: control signals
well, once you have stuff on control busses, “recording, playback, transposing, quantizing” &c becomes a technically straightforward matter of using SC’s many tools for buffer and signal manipulation. but the creative possibilities quickly become manifold…
other analyses
spectral flatness on a wide-band signal is very useful i think. especially when combined / triangulated with other metrics like spectral centroid (which is conveniently SpecCentroid in SC) - this is an approximation of brightness, where weiner entropy is a (rough) approximation of tonality.
SpecPcile gives you a specific designated point on the cumulative distribution of the power spectrum - a measure of spectral “rolloff” that can mean different things depending on where you put that point. it’s less independent from the other two.
be aware that Pitch.kr also exists, it is an autocorrelation pitch tracker that also emits the strength of the autocorrelation as a “clarity” measure. it has its own internal frequency transform and can’t be combined with other FFT chain ugens.
and finally the third-party MCLD ugens include many more spectral analysis tools, like FFTCrest which is a different kind of “peakiness” measure (max / mean.)
i guess it’s appropriate to say that i’ve used a lot of musical techniques in this vein. for example the 2nd track on side A of my record at the door consists of several minutes of sines+noise synthesis based on a few seconds of viola sounds, analyzed and resynthesized in a highly arbitrary way. and for a couple of years most of my live pieces were similarly derived (e.g. 2014 SFEMF performance.)