Hello.
I noticed that Equalizer APO produces different frequency responses when switching to different sampling rates. This affects the sound, because the actual sound is very different from what is expected.
I am writing my own program to create a convolution file based on autoeq filters, but I configure the filters in EAPO. I noticed that the impulses obtained by my program fully correspond to the EAPO curves, that is, they also differ from each other. Here is my code
https://github.com/3bagorion33/squig2proq/blob/master/squig2proq/ir_utils.py
As you can see, it is based on RBJ coefficients. Since the frequency response in your program, obtained from the filter text file, and the frequency response of my pulse coincide, I assume that you are using the same method.
Since I am not good at math, I asked AI to analyze this code. Here is the answer I received
https://grok.com/share/c2hhcmQtMg%3D%3D_d6d6b36e-2922-4f55-b0f0-5b546ff8170e
I applied the recommendations and got an impulse response whose frequency response became the same at 48000 and 96000. And it corresponds to the EAPO graph obtained from the text filter at a sampling rate of 96000.
In summary, there is clearly an error in the algorithm, because the frequency responses should be the same regardless of the sampling frequency. Increasing the Resolution parameter of the effect does not help.
I hope the developer sheds some light upon your remarks but he isn't that active on his Equalizer APO project. So I'll give you my experience on the matter.
Equalizer APO has 2 ways of filtering (EQ-ing): by biquad filters and by convolution. Of course these 2 techniques are quite different, totally not comparable. It seems to me that you're speaking about the biquad filters.
As developer of the Peace Equalizer I know about these calculations as they are needed to produce the Peace filter (EQ) graph for the user. If you're noticing a difference above, say 10 kHz, then that's how biquad filtering works. Biquad filters differs (by calculation) per sample frequency. So one has to be careful about comparing results. In a good comparison the sample frequency must exactly be the same. In other words, looking at your 2 screenshots (48 kHz vs 96 kHz) of course there's a difference. It's just biquad filtering. Btw. I don't know if this is also true for filtering by convolution.
The question is if this difference is audible. For a healthy young person the 22 kHz mark is the absolute maximum. For most of us our hearing is 15 kHz or lower. Currently I'm on 14 kHz (and dropping). The biquad filtering difference begins to occur at 10 kHz and that's pretty high itself. Music is more about our "normal" frequency spectrum so between 100 Hz to 4000 Hz. In other words, if there's audible difference at the high frequencies then this change gets nullified by the other frequencies of music, also knowing the difference begin to stand out at 20 kHz. But if it's audible then the fix is to use a higher sample rate. Nowadays 44100 Hz is the lowest and 96 kHz is very common as an option.
So the calculations Equalizer APO uses for biquad filtering isn't wrong. It's how biquad filters work and that's fine. When a user isn't satisfied by these biquad filters he/she has the option for filtering by convolution.
When it comes to changing the level in a large frequency range at low Q, even a slight change in filter gain leads to a significant redistribution of spectral energy, which inevitably affects the sound color. At a Q factor of 1, I can hear a change of 0.2 dB. Changes in these peaks and dips in the high frequencies are also clearly audible because they either do not sufficiently suppress the resonances of the headphones or do not sufficiently compensate for their dips.
That's right. But it doesn't mean that the calculations are wrong. It's just how biquad filters work. Or rather the limitations of them. Btw. Convolution is also sample frequency depended. For each sample frequency another impulse response file/data must be created.
As developer of the Peace Equalizer it seems that only a tiny amount of Peace/Equalizer APO users are concerned by the implications you're talking about. Over the 10 years of developing the Peace Equalizer I only had a few conversations about the topic and related ones like the phase changes biquad filters produce.
Generally speaking biquad filters are okay. But years ago I checked if the calculations by Equalizer APO are done according to the biquad filters cookbook. They seem to be exactly done according to the cookbook. But then again, there can be some small miscalculation in one or more filters of which I'm not aware of. But sample frequncy isn't a part of it. Knowing that omega0 is depending on the sample frequency in biquad filters it's only logical there's a difference. Btw. This is also true for hardware filters of which biquad filters are based on.
Unfortunately, I was unable to find any information on how to correct these coefficients. Either it is so obvious that no one thinks to write an article about it, or it is so complicated that no one has been able to figure it out yet. Nevertheless, various VSTs can handle this. Are there other ways to obtain a correct frequency response?
Unfortunately I don't either know the math behind it. I've just implemented the coefficients. How to manipulate them is complicated, well at least for me not knowing the math.
Sorry, I really don't know. At least a high sample frequency ensures less issues in the 10 kHz above region. Looking back at your first screenshots I see you've used convolution. If there's a problem with this technique too then both biquad filters and convolution eq-ing have the same issue. So it may be all about using/setting a high sample frequency. On the other hand, there can be EQ filtering methods that don't have issues or have less issues.
Sorry for my poor English. I'm probably not explaining this very well.
Yes, I initially used a simple filter file. When I saw that it had different characteristics depending on the sampling frequency, I decided to use a fab filter and wrote a program to parse from the autoeq format to the fab format. But it turned out that the frequency response of the fab filter was completely different.
So my next iteration was to try to get a convolution. Since I'm not very good at math either, I asked ChatGPT about methods for obtaining it, and it gave me formulas with bicubic coefficients. And so I got a 96k convolution, which has exactly the same characteristics as the 96k file. Of course, if you get the convolution right, EAPO will draw the correct characteristics. But that's exactly the problem 😂
I don't understand why ChatGPT gave you biquad filter coefficients. The technique of convolution filtering is entirely different from the technique of the biquad filters. One can't compare the two. ChatGPT shouldn't have given you something that isn't related to convolution.
By using Benchmark executable of Equalizer APO one could turn Equalizer APO biquad filters (commands like FILTER 1 ON .., etc.) into a convolution file. The resulting impulse response file will be exactly the same as the output of the biquad filters. If not the same then it's a bug. So have you used the Benchmark command?
I don't understand, how to use it...
Okay. I got it. As expected, Benchmark uses the same biquadratic filters: the green response is the target frequency response obtained when tuned to 48k, and the red one is obtained at 96k.
I think that's why ChatGPT advised me to use bicubic filters, because they are used everywhere:
My task is to make the characteristics at 96k the same as at 48k.
My mistake was that I started adjusting the characteristics by ear at 48k. If I had done this at 96k from the start, 48k could have been obtained by simple resampling. Resampling from 48k to 96k does not make sense because then all frequencies above 24k will be missing from the impulse and, accordingly, will also be missing from the resulting signal after convolution, which makes it pointless to use 96k.
During my research, I found that the characteristic obtained at 48k (which I, damn it, tuned) is actually incorrect: the closer the frequency is to the Nyquist frequency (fs/2), the greater the actual Q value. But the problem is that this distortion grows constantly, and the Q factor is Q(f0-)<Q(f0)<Q(f0+). Thus, even with Q compensation, it is simply impossible to obtain the same characteristic at any frequency that was at the base when tuning the filter. Unfortunately, I made this mistake out of ignorance and tuned to 48k.
Well, now I plan to try to compensate for the absence of frequencies above Nyquist by extending the frequency response shelf. So far, I haven't been able to do it. The latest idea is to generate a delta function spectrum with the desired amplitude, cut off everything below the Nyquist frequency, and attach it to the target 96k impulse obtained from 48k. If that doesn't work, then I'll have to develop my own software that can combine two frequency responses and adjust the new 96k filter to the old 48k filter.
Last edit: orion33 2025-07-24
No, it doesn't use the biquad filters. It just creates a file according to a frequency sweep which can be used as impulse file for convolution (either in a DAW or in Equalizer APO itself).
And no, Equalizer APO has biquad filters and convolution filtering. You use them by entering the commands, for instance:
A biquad filter: "Filter 10: ON PK Fc 4000 Hz Gain -3.5 dB Q 0.5"
A convolution filter: "GraphicEQ: 10 0; 21 0; 42 0; 83 2; 166 0; 333 0; 577 0; 1000 0; 2000 0; 4000 0; 8000 0; 16000 0; 20000 0"
The Benchmark command just outputs a file according to the filtering you have done by entering Equalizer APO commands. This can be a combination of biquad filters, convolution, pre amps, VST plugins, etc.
I have to say that I understand what you're doing. If I compare things I won't compare convolution (GraphicEQ) with biquads filters. It's pointless. Either one compares biquad filters at 48 kHz with 96 kHz, or compares GraphicEQ at 48kHz with 96 kHz. ChatGPT doesn't know what it's talking about. It's plain rubbish.
So what are you comparing? Convolution or biquad filters? Please, let me see your config.txt file.
Like you I don't think any Q value can change the 48 kHz into the 96 kHz frequency response.
Also, what's the benefit of correcting 48 kHz in the first place? I doubt if that's easy to do or even necessary. The solutions may already be on the internet. Or just use a higher sample rate like 96 kHz. Resampling music of a lower sample rate to higher ones can be done by some clever music player apps/streamers and VST plugins.
Well, imagine you have a txt file with filters like this:
Filter: ON PK Fc 245 Hz Gain -1 dB Q 10
Filter: ON PK Fc 255 Hz Gain -1 dB Q 10
Filter: ON PK Fc 300 Hz Gain 0.4 dB Q 0.5
Filter: ON PK Fc 375 Hz Gain 0.15 dB Q 3
Filter: ON PK Fc 490 Hz Gain -0.5 dB Q 10
Filter: ON PK Fc 510 Hz Gain -0.5 dB Q 10
Filter: ON PK Fc 730 Hz Gain 0.8 dB Q 4
How would you obtain a convolution impulse from this? What steps would you take?
Using the Benchmark executable of Equalizer APO. Or easier, my interface of it (called Vibe). I would create a file for each sample frequency. The benchmarking sample frequency must be equal to the one set in Windows of the (output) audio device as this frequency may be used for benchmarking. Only then the resulting convolution files can be compared, in this case a comparison of the biquad filters by different sample frequencies.
Perhaps you did the following. Comparison can be done in the Configuration Editor. The biquad filters should be removed and all other commands, just to clear (flatten) the graph in the analysis panel. Then load all convolution files, deactivate all of them, activate just one, take a screenshot of the graph, deactivate this one, activate another, take a screenshot, etc.
With this approach, the convolution files are different for different sampling frequencies. As you mentioned above, Benchmark uses the same filters as EAPO, so the characteristics of each convolution impulse correspond to what EAPO displays. The impulse files that you see in my first screenshot are disabled, as you can also see.
Thus, this method does not allow you to obtain two impulses with identical frequency characteristics for different sampling frequencies.
I've reread your first post again, well several times. Unfortunately I can't see the Grok chat in order to verify what's being written. I want to see the recommendations.
Looking at your Python code it could indeed be that you've managed to get the same frequency response for 48 kHz and 96 kHz. However, currently the graph in Equalizer APO reflects what is being filtered by the biquad filters you set. In other words, the frequency response is exactly according to this graph and depends on the set sample frequency of the audio device. If the Grok recommendations can be implemented in the source code of Equalizer APO then perhaps that will make an improvement. But then this isn't biquad filters any longer. Btw. Their math is correct. I've checked it years ago during the implementation of the graph (interface) in the Peace Equalizer. I did find a bug which was corrected. The math is according the formulas of the Cookbook and how to implement it in programming code, well besides the initial bug (I believe it as a mistake of a forgetting to type a minus sign).
Knowing the above, I guess a new set of corrected filters can be introduced if the recommendations by Grok are alright and if this can be used for real time processing the audio samples of a sound/song.