Boosting specific frequencies with fft - problem

Hi I hope you all doing great!
So i m trying to make a plugin which will boost specific frequencies. I m able to find fundamental freq and audio which goes through whole chain sounds good (no clliping etc) but when i want to change a magnitude of specific freq i cant hear the diffrence (and i think i should). So when i m debbuging i can see that the magnitude is being multiplied but it doesnt make any difference. The plan is:

  1. Push samples into fifo. My buffer is 441 samples btw. Rest of fifo I fill with zeros to get better resolution.

  2. do FFT to my array of samples. ( what I found is that when even i have 441 samples on which i do fft the whole array of FFT is being filled with numbers. Maybe it should just have 882 samples after FFT and being filled with zerros after last sample?)

  3. get magnitude from FFT

  4. get fundamental freq ( to know which bins should i boost)

  5. boosting multiples of the fundamental frequency

  6. get phase to calculate complex numbers ( real, imag,real, imag) ( i m getting phase from FFT data before processing)

  7. changing fftData with data with changed magnitude

  8. inverse FFT

  9. put modified data to output.

Can anyone tell me what I m doing wrong? Maybe i have wrong sizes of arrays in my for loops? Maybe i should do magnitude. boosting etc on my 882 samples not on the whole buffer and rest of the buffer i should fill with zeros.

My code:
header file:
juce::dsp::FFT my_FFT;

static constexpr auto fftOrder = 12, fftSize = 1 << fftOrder; 
float sampleRate_sizeDiv;
std::array <float, fftSize> fifo;
std::array <float, fftSize * 2 > fftData;
std::array <float, fftSize> magnitudeData;  
int magnitudeDataSize = magnitudeData.size();
float  fftHalfSize = fftSize / 2 + 1;
float sizeMaxInv = (1.f / float(fftSize - 1));
float  sizeMaxInvPi = sizeMaxInv * juce::MathConstants<float>::pi;
int fifoIndex = 0;

float resolution = 1.f;
float m_sampleRate = 0;
float fundamentalFreq = 0;
int idx; /// bin's index
float max = 0.f; /// max amplitude of freq
float magnitude;

std::array<float, 8> multiVariables = 
{ 1.65 ,4.875, 3.136, 1.787, 6.6, 5.489, 1.382, 4.214 };

cpp file:

//// mono /////
for (int channel = 0; channel < 1; ++channel)
{
    auto* channelData = buffer.getWritePointer(1);
    for (int s = 0; s < buffer.getNumSamples(); s++)
    {
        channelData[s] = 0;
    }


    auto* channelData_0 = buffer.getWritePointer(0);
    for (int s = 0; s < buffer.getNumSamples(); s++)
    {
        float currentSample = channelData_0[s];

        if (fifoIndex == buffer.getNumSamples())
        {
            std::fill(fftData.begin(), fftData.end(), 0.0f);
            std::fill(fifo.begin() + fifoIndex, fifo.end(), 0.f);
            std::copy(fifo.begin(), fifo.end(), fftData.begin());
            my_FFT.performRealOnlyForwardTransform(fftData.data());
            fifoIndex = 0;


            /// complex ----> magnitude ///
            int magPlace = 0;
            std::fill(magnitudeData.begin(), magnitudeData.end(), 0.0f);
            for (int i = 0; i < fftData.size(); i += 2)
            {
                float magnitude = 0;
                magnitude = getMagnitude(fftData[i], fftData[i + 1]);
                magnitudeData[magPlace] = magnitude;
                magPlace++;
            }

            /// get fundamental freq /// 
            max = 0;
            idx = 0;
            for (int i = 0; i < magnitudeData.size() / 2; i++)
            {

                float potMaxMagnitude = magnitudeData[i];
                if (max < potMaxMagnitude)
                {
                    max = potMaxMagnitude;
                    idx = i;
                }
            }

            _RPT1(0, "idx %d\n", idx);
            fundamentalFreq = (idx * m_sampleRate) / fftData.size();  //// coś jest nie tak że musze dzielić przez dwa 
            _RPT1(0, "Fundamental_Freq1 %.6f\n", fundamentalFreq);

            /// boosting /// 
            // freq x2,x3,x4,x5...
            int count = 2;
            for (int i = 0; i < (multiVariables.size() - 1); i++)
            {
                magnitudeData[idx * count] *= multiVariables[i];
                magnitudeData[(magnitudeDataSize - 1) - (idx * count)] *= multiVariables[i];
                count++;
            }


            /// magnitude ----> real,image,real.... /// 
            int fftIndex = 0;
            for (int i = 0; i < magnitudeDataSize; i++)
            {

                /// phase/// 

                std::complex <float> complexNumber(fftData[fftIndex], fftData[fftIndex + 1]);
                float phase = std::arg(complexNumber);

                /// real and imag ///
                float real = magnitudeData[i] * std::cos(phase);
                float imag = magnitudeData[i] * std::sin(phase);

                /// fftData changing //
                fftData[fftIndex] = real;
                fftData[fftIndex + 1] = imag;
                fftIndex += 2;
            }


            //// inverse FFT
            my_FFT.performRealOnlyInverseTransform(fftData.data());




        }
        ///float windowAmp = std::sin(float(fifoIndex) * sizeMaxInvPi);
        fifo[fifoIndex] = currentSample;///* windowAmp;
        ++fifoIndex;


        /// output ///

        channelData_0[s] = fftData[s];
      }
   }
}

getMaganitude Function:

  float FreqBoosterAudioProcessor::getMagnitude(float real, float imag)
 {
  return std::sqrt(std::pow(real, 2) + std::pow(imag, 2));
 }

Thanks in advance!

I didn’t read your code yet, but I don’t think you can generally edit audio data directly in the frequency domain (without wrapping your FFT in a phase vocoder or similar).

  • If you want to have an inverse transform, you need complex data, and there not a realonly transfrom to start with.
    ** It seems you mixed up interleaved code examples with complex structured code!! **
    use a normal FFT, read .imag() and .real() out of the complex output array.
    .

  • the fftsize needs to be lots bigger than the lowest frequency you want to see.

  • First try a prefect inverse transform before trying your frequency domain mods.

  • Be aware that you need overlap to get any kind of nicely working system!

  • Applying of frequency domain mods is not trivial! For starters, using hann window curves for it is the simplest choice.

Okey thanks for your advices!
Have a great day!

1 Like

visualize the spectrogram to see how it is changing, a visualization will give you more information than just hearing it.