Recent

Author Topic: Audio Equalizer with FFT?  (Read 6523 times)

Fred vS

  • Hero Member
  • *****
  • Posts: 3919
    • StrumPract is the musicians best friend
Audio Equalizer with FFT?
« on: November 12, 2020, 11:30:52 pm »
Hello.

What is the right way to create a equalizer using fft (Fast Fourier Transform)?

I have at disposition those fft's: BandReject, BandPass, LowPass and HighPass.

Lets concentrate on the buffer of samples (array of float).

BandPass filter combines a LowPass filter with a HighPass filter.

When applying a BandPass filter to the original buffer, the selected low to high frequencies are isolated and a gain can be applied.

So it is easy if you want to gain the selected frequencies of the original buffer, just do new_value = original_value + fft_value.

But what is best way if you want to use more than 1 BandPass?
Just do a loop of the different BandPass and add all the fft-results to the original buffer?
Maybe using the BandPass filter is not the good way to create a Equalizer with multi frequencies?

Any advice is highly appreciated.

Fre;D

« Last Edit: November 12, 2020, 11:56:16 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12847
  • FPC developer.
Re: Audio Equalizer with FFT?
« Reply #1 on: November 12, 2020, 11:58:11 pm »
Afaik the result of the FFT is the frequency domain, IOW every result of the array is a frequency (range).

So then you have all freqs at once. But anything -PASS probably filters frequencies away.

I use Nils Haecks FFT unit to filter away certain high freq motor noise, but this is not real time though.
« Last Edit: November 15, 2020, 02:32:30 pm by marcov »

Fred vS

  • Hero Member
  • *****
  • Posts: 3919
    • StrumPract is the musicians best friend
Re: Audio Equalizer with FFT?
« Reply #2 on: November 13, 2020, 12:22:28 am »
Afaik the result of the FFT is the frequency domain, IOW every result of the array is a frequency (range).

So then you have all freqs at once. But anything -PASS probably filters frequencies away.

I use Nils Haecks FFT unit to filter away certain high freq motor noise

Yes, filtering range of frequencies is easy, using a lowpass or/and a high pass.

On a "real" audio equalizer, each slider (that represent a range of frequencies) can increase or decrease the gain of that range.

With the fft BandPass (Low+HighPass) it is possible too, just do:
original_buffer + fft_buffer to increase the range or original_buffer - fft_buffer to decrease the gain.

( Huh, it really works, I find it TOTALLY magic )

But is it the best way to do a equalizer, maybe it could be possible to have only one fft that can deal with multi-ranges, like a multi-ranges equalizer.


I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Audio Equalizer with FFT?
« Reply #3 on: November 13, 2020, 12:35:56 am »
Years ago I saw an equalizer designed as a group of low order (IIRC) band pass IIR filters. They were designed as Butterworth filters and transformed using bilinear transform. Author promised no distorsion when all filters are at 0dB position.
But I can't find the article in docs, bookmarks nor online (I changed browser and distro).
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Fred vS

  • Hero Member
  • *****
  • Posts: 3919
    • StrumPract is the musicians best friend
Re: Audio Equalizer with FFT?
« Reply #4 on: November 13, 2020, 01:14:55 am »
Hello Blaazen.

Ha, so using BandPass filters seems ok.

I just test a 5 bands equalizer using this for each fft-Bandpass loop:

For the first band:
Code: Pascal  [Select][+][-]
  1. result_sample := original_sample + (fft_sample*gain);

and for all the others:
Code: Pascal  [Select][+][-]
  1. result_sample := result_sample + (fft_sample*gain);

It works.
« Last Edit: November 13, 2020, 01:28:14 am by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Thaddy

  • Hero Member
  • *****
  • Posts: 19143
  • Glad to be alive.
Re: Audio Equalizer with FFT?
« Reply #5 on: November 13, 2020, 09:12:31 am »
Years ago I saw an equalizer designed as a group of low order (IIRC) band pass IIR filters. They were designed as Butterworth filters and transformed using bilinear transform. Author promised no distorsion when all filters are at 0dB position.
But I can't find the article in docs, bookmarks nor online (I changed browser and distro).
If you refer to Pascal code, it was me. I used the RBJ filter sets to write it. May be still in the musicdsp.org archives. Date somewhere between 2001-2003.
Although an FFT is technically more accurate, the Butterworth filters are more pleasing to the ear because it models analogue. And they are computationally cheap.
BTW: I believe I only used the shelving filter in series.
https://www.musicdsp.org/en/latest/Filters/197-rbj-audio-eq-cookbook.html may still also contain the Pascal translations.(all filters from the cookbook)
And indeed, at 0dB there is no distortion. Currently do not have time, but as I remember they are very easy to translate. Took me an hour or so for all of them.
Also note the RBJ filters are by far the best ones.
I do not write VST plugins anymore, but I still can give advice.
But Fred is a very capable audio programmer so the link to the audio cookbook would suffice anyway.
« Last Edit: November 13, 2020, 09:40:00 am by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Fred vS

  • Hero Member
  • *****
  • Posts: 3919
    • StrumPract is the musicians best friend
Re: Audio Equalizer with FFT?
« Reply #6 on: November 13, 2020, 02:16:42 pm »
Hello Thaddy.

Quote
https://www.musicdsp.org/en/latest/Filters/197-rbj-audio-eq-cookbook.html may still also contain the Pascal translations.(all filters from the cookbook)

WOW, I will deeply study your code, many thanks.

At the moment I use the fft done by Andrei Borovsky from the ACS package.

Code: Pascal  [Select][+][-]
  1. ...
  2.  
  3. var
  4. a3: array[0..2] of Double;
  5.     b2: array[0..1] of Double;
  6.     x0, x1, y0, y1: array[0..1] of Double;
  7.     FLowFreq, FHighFreq: Integer;
  8.     FFilterType: TAFilterType;  
  9. ...
  10.  
  11. procedure InitFilter();
  12. var
  13.   C, D: Double;
  14.   InputSampleRate: Integer = 44100;
  15.  
  16. begin
  17.   x0[0]:=0.0;
  18.   x0[1]:=0.0;
  19.   x1[0]:=0.0;
  20.   x1[1]:=0.0;
  21.   y0[0]:=0.0;
  22.   y0[1]:=0.0;
  23.   y1[0]:=0.0;
  24.   y1[1]:=0.0;
  25.  
  26.   case FFilterType of
  27.     ftBandPass:
  28.     begin
  29.       C:=1 / Tan(Pi * (FHighFreq-FLowFreq+1) / InputSampleRate);
  30.       D:=2 * Cos(2 * Pi * ((FHighFreq+FLowFreq) shr 1) / InputSampleRate);
  31.       a3[0]:=1 / (1 + C);
  32.       a3[1]:=0.0;
  33.       a3[2]:=-a3[0];
  34.       b2[0]:=-C * D * a3[0];
  35.       b2[1]:=(C - 1) * a3[0];
  36.     end;
  37.  
  38.     ftLowPass:
  39.     begin
  40.       C:=1 / Tan(Pi * FLowFreq / InputSampleRate);
  41.       a3[0]:=1 / (1 + Sqrt(2) * C + C * C);
  42.       a3[1]:=2 * a3[0];
  43.       a3[2]:=a3[0];
  44.       b2[0]:=2 * (1 - C * C) * a3[0];
  45.       b2[1]:=(1 - Sqrt(2) * C + C * C) * a3[0];
  46.     end;
  47.  
  48.     ftHighPass:
  49.     begin
  50.       C:=Tan(Pi * FHighFreq / InputSampleRate);
  51.       a3[0]:=1 / (1 + Sqrt(2) * C + C * C);
  52.       a3[1]:=-2 * a3[0];
  53.       a3[2]:=a3[0];
  54.       b2[0]:=2 * (C * C - 1) * a3[0];
  55.       b2[1]:=(1 - Sqrt(2) * C + C * C) * a3[0];
  56.     end;

All filters work but I have problems with the equalizer, how to boost or decrease some ranges of frequencies but keep the others intact, is it possible to do that with one fft?

Quote
But Fred is a very capable audio programmer so the link to the audio cookbook would suffice anyway.

Thanks but the truth is that I dont even have a tiny percentage of your skill and the one of Blaazen.

Fre;D
« Last Edit: November 13, 2020, 02:24:24 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Fred vS

  • Hero Member
  • *****
  • Posts: 3919
    • StrumPract is the musicians best friend
Re: Audio Equalizer with FFT?
« Reply #7 on: November 13, 2020, 08:14:17 pm »
Hello.

OK, I think I get it.

The trick was to use a BandReject (exclude a range and keep all others) and a BandPass * gain.

Code: Pascal  [Select][+][-]
  1. ftBandReject:
  2.     begin
  3.       C:=Tan(Pi * (FHighFreq-FLowFreq+1) / InputSampleRate);
  4.       D:=2 * Cos(2 * Pi * ((FHighFreq+FLowFreq) shr 1) / InputSampleRate);
  5.       a3[0]:=1 / (1 + C);
  6.       a3[1]:=-D * a3[0];
  7.       a3[2]:=a3[0];
  8.       b2[0]:=a3[1];
  9.       b2[1]:=(1 - C) * a3[0];
  10.     end;
  11.  
  12. ftBandPass:
  13.     begin
  14.       C:=1 / Tan(Pi * (FHighFreq-FLowFreq+1) / InputSampleRate);
  15.       D:=2 * Cos(2 * Pi * ((FHighFreq+FLowFreq) shr 1) / InputSampleRate);
  16.       a3[0]:=1 / (1 + C);
  17.       a3[1]:=0.0;
  18.       a3[2]:=-a3[0];
  19.       b2[0]:=-C * D * a3[0];
  20.       b2[1]:=(C - 1) * a3[0];
  21.     end;

Code: Pascal  [Select][+][-]
  1. result_sample := fft_sample_bandreject + (fft_sample_bandpass*gain);
« Last Edit: November 14, 2020, 12:57:02 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

ChrisR

  • Sr. Member
  • ****
  • Posts: 251
Re: Audio Equalizer with FFT?
« Reply #8 on: November 15, 2020, 01:12:10 pm »
You might want to try out this Lazarus project
  https://www.mccauslandcenter.sc.edu/crnl/tools/temporal
Which implements Robert Bristow-Johnson's bi-quad filters


Fred vS

  • Hero Member
  • *****
  • Posts: 3919
    • StrumPract is the musicians best friend
Re: Audio Equalizer with FFT?
« Reply #9 on: November 16, 2020, 01:48:55 am »
You might want to try out this Lazarus project
  https://www.mccauslandcenter.sc.edu/crnl/tools/temporal
Which implements Robert Bristow-Johnson's bi-quad filters

Hello Chris.

Many thanks to show for this great project.
Nice to analyze high frequencies.
I will deeply study it.

About Audio Equalizer, I updated the uos example FilterPlayer.lpi, I has now a simple 3 bands stereo equalizer.
It uses a BandReject filter and a BandPass filter * gain.
In attachment a screenshot of the demo.

It works very good even with a 10 bands Stereo and many others DSP added.
In attachment a screenshot of StrumPract project using uos equalizer.

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Fred vS

  • Hero Member
  • *****
  • Posts: 3919
    • StrumPract is the musicians best friend
Re: Audio Equalizer with FFT?
« Reply #10 on: November 21, 2020, 03:52:55 am »
Hello everybody.

OK, I have perfect result with equalizer using fft BandReject filter and a BandPass filter * gain.

Now I am busy for a "Playing Reverse" feature.

I have very good result using this:

At each thread-loop, before to read the audio-source, there is  a seek at audio-source.position -
     (length(buffer-samples) div channels).

When the buffer-samples is filled, a fft do this:

Code: Pascal  [Select][+][-]
  1. type
  2. TArFloat = array of cfloat;
  3.  
  4. function DSPReverse(var Buffer: TArFloat): TArFloat;
  5. var
  6.   x: integer = 0;
  7.   lengthbuf: integer;
  8.   arfl: TArFloat;
  9. begin
  10.   lengthbuf := length(Buffer);
  11.    SetLength(arfl, lengthbuf);
  12.     x := 0;
  13.  
  14.     while x < lengthbuf do         // Buffer is stereo.
  15.     begin
  16.       arfl[x]     := Buffer[lengthbuf - x -1];            // Is it the right way ?
  17.       arfl[x + 1] := Buffer[lengthbuf - x - 2];   // Is it the right way ?
  18.       Inc(x, 2);
  19.     end;
  20.     Result := arfl;
  21.   end;
  22. end;

This indeed produces a reverse sound but if the level of the samples is high, there is some "click" and "clack" in the sound.
Does somebody have a idea why, maybe the inversion of the samples is not ok?

Inverting the phases did not help (sample := -1 * sample).

Thanks.

Fre;D

[EDIT]

OK, fixed, lengthbuf must be length(Buffer) div channels.
Now, no more "click" nor "clack" but a perfect reversed sound.

Time to do a great scratching console.

Sorry for the noise.
« Last Edit: November 21, 2020, 05:28:43 am by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

 

TinyPortal © 2005-2018