Is it possible to AmpCompA an FFT chain?

This is dealing with the following problem, normally when generating pure notes, I normalize their amplitude by doing * AmpCompA(freq) on the signal.

When making multiple instruments this gets kind of tedious. Is there a way to convert a signal into frequencies then AmpCompA all of them and resynthetize? My guess is some form of FFT/IFFT, but I might be wrong.

Here is the what I have right now,

SynthDef(\ifftamp, {
	| in, out |
	var chain, output;
	chain = FFT(LocalBuf(2048),in);
	output = IFFT.ar(chain);
	Out.ar(out, output * AmpCompA.kr(440));
}).add;

This multiplication of output by fixed AmpCompA is wrong, I would really like to run AmpCompA on frequencies in the chain, instead of trying to multiply the output, is there a way to do so? Or maybe is there a better approach to amplitude compensation on impure tones?

It may be possible to use the formula directly with pvCollect:

(
var k =  3.5041384e16;
var c1 = 424.31867740601;
var c2 = 11589.093052022;
var c3 = 544440.67046057;
var c4 = 148698928.24309;
f = {|f|
  var r = squared(f);
  var m1 = pow(r,4);
  var n1 = squared(c1 + r);
  var n2 = c2 + r;
  var n3 = c3 + r;
  var n4 = squared(c4 + r);
  var level = k * m1 / (n1 * n2 * n3 * n4);
  sqrt(level)
 };
)

You just need to calculate the freuency from the index.

It may be very expensive though, and better to use some filter on the time signal.

An equal-loudness curve as a post-processing step will affect partials individually, so you’ll get a change in both volume and timbre. Is that what you want?

The concern seems to be about boilerplate: “When making multiple instruments this gets kind of tedious.” If you have repetitive code in your SynthDefs then the best way to attack that is to write a function and reuse it.

Finally, if you do want equal-loudness post-EQ rather than simple amplitude compensation on a synthesized tone, I wouldn’t use FFT nor the A-weighting curve. A better approach would be to approximate one of the curves from the ISO 226:2023 standard with standard IIR EQ filters, which don’t have latency or windowing artifacts like FFT does. I can demonstrate how to do that on request.

2 Likes

So I am thinking about it a bit more this way.
We have a (possibly missing) fundamental and its higher harmonics (might be slightly inharmonic, but that shouldn’t shift frequency-loudness perception too much I think, I have to experiment with that) being played as a single note. I would like to generically apply some form of equalized loudness to the resulting signal so that it would be perceived at the same relative loudness as all the other notes being played at a different pitch with a possibly different timbre. The more I think about it something like AmpCompA is way too naive and FFT artifacts are also undesirable. Any suggestions are welcome. Latency does not bother me much as I mostly use non-realtime synthesis right now.

Desired effect is having a uniform control for differrent instruments in a scene playing different timbres and notes, such that it’s possible to control relative loudness of each instrument mostly algorithmically. The more I think about it the more it sounds way too complex. Maybe FFT identifying the most dominant frequency band(s) then using some compensation curve based on the dominant band from FFT without resynthetizing could work.

TL;DR Trying to come up with a value to multiply a resulting mixed wave from a single synth by such that its perceptual loudness can be a linear control.

Is there one in supercollider? I use this LSP Loudness Compensator plugin series by Linux Studio Plugins Project - lsp Plugin LADSPA LV2 to do quick checks and to sometimes shake up the mix slightly.