Manipulate Magnitudes of FFT (Optimized)

dsp_module

#1

Hey DSP Jucers :slight_smile:

I’ve been diving more into spectral processing, & my latest little project consists of two signals, A & B. What I’d like to do is:

  1. Take FFT of A & B (same FFT size)
  2. Use magnitude values of B (via dsp::FFT::performFrequencyOnlyForwardTransform) to scale magnitudes of A (via dsp::FFT::performRealOnlyForwardTransform)
  3. use the IFFT on A, and then use the output as audio output

Basically I’d like to use the magnitude “contour” of B to create a filter-like effect on A. My main question is if there’s an optimized way to scale the magnitudes of A without converting to polar form and then back to rectangular (thus using expensive trig functions)?

Right now I’m considering using an overlap-add method with a hanning window for the processing, in case anybody has suggestions for that system.

Many thanks!


#2

UAlthough I have no idea if your idea will produce any nice sounds, I think you should dig a little bit deeper in dsp related math… :wink:

You are planning to multiply the real valued magnitudes of B with the complex valued bins of A, right? In this case, no need to convert the complex values to the polar form, it‘s perfectly valid to just multiply the real and imaginary part of the complex value with the scalar.
If your results from A are in an array of std::complex values, then something like

int i = 0;
for (auto &a : complexFftAOutputArray) {
    a *= realFftBOutputArray[i];
    i++;
}

should work fine.

Anyway, I’m really curious how that will sound :grinning:


#3

Max MSP has variations on this theme in the help patches for the pfft~ object if you want to hear what it’ll sound like before putting it all together in C++. If you’re manipulating the magnitude values for successive frames then an overlap-add with a Hanning window is definitely the way to go.


#4

Ah, of course! Multiplying in rec form by a scalar won’t change the argument, just the magnitude (atan((Ay)/(Ax)) = atan(y/x), the scalar gets factored out as A/A = 1). I had somehow convinced myself otherwise :wink: Thanks for the tips, I’ll let ya’ll know how it turns out.