Question

I'm working on equalizer and trying to understand how to it all should work.

Please help to understand what I should to do.

What I already have:

  1. C#

  2. incoming float[] buffer (it comes from CSCore library, can be downloaded with Nuget)

  3. an implemented and working band pass filter (http://www.earlevel.com/main/2011/01/02/biquad-formulas/)

  4. a ten band equalizer 31,62...16000

  5. pieces of code:

        var sampleFilters = new EqFilter[] 
        {
            new EqFilter(sampleRate, 31, 0.24205482f, defaultGain),
            new EqFilter(sampleRate, 62, 0.11142862f, defaultGain),
            new EqFilter(sampleRate, 125, -0.013698578f, defaultGain),
            new EqFilter(sampleRate, 250, -0.40285712f, defaultGain),
            new EqFilter(sampleRate, 500, -0.27534246f, defaultGain),
            new EqFilter(sampleRate, 1000, -0.15479457f, defaultGain),
            new EqFilter(sampleRate, 2000, 0.071232915f, defaultGain),
            new EqFilter(sampleRate, 4000, 0.28904116f, defaultGain),
            new EqFilter(sampleRate, 8000, 0.45027387f, defaultGain),
            new EqFilter(sampleRate, 16000, 0.6036986f, defaultGain)
        };
    

third parameter is Q, fourth is gain but band pass filter doesn't use it.

and

        int read = base.Read(buffer, offset, count);

        for (int c = 0; c < WaveFormat.Channels; c++)
        {
            for (int i = _sampleFilters.Count; i-- > 0; )
            {
                _sampleFilters[i].Filters[c].Process(buffer, offset, read, c, WaveFormat.Channels);
            }
        }

        for (int n = offset; n < count; n++)
        {
            buffer[n] = Math.Max(-1, Math.Min(buffer[n], 1));
        }

        return read;
    }

where Process method applies bandpass filter.

What I'm trying to understand what I'm doing wrong because if I try to apply filter in such way I have silence as output. What seems correct if imagine what filter do with signal. But how I should apply it properly? In same time if I apply only one frequency filter (for example for 31Hz) it works.

One good man told me about low pass filter that I should mix in it into 'dry' signal. I tried to do same here but failed. I got silence as output again. I tried to keep input buffer, then for each frequency applied filter and mixed it with input with following formula:

result = X + Y - X*Y where X = input[i] and Y = bandpassfiltered[i]

I think I also did something wrong.

Also a big question what to do with negative value? If you try to place bands like smile you pull several band bellow middle level and have negative values. How to implement it with BPF?

Meanwhile is it correct that bands of equalizer change Q? So if pull up or down a band what I change? If it is not Q what should be changed? It is not gain because algorith doesn't take it in count.

Could someone help me to understand this all? What am I doing wrong? How should I do such things?

I'm sorry if it isn't clear. I'll try to clarify if it needs.

Was it helpful?

Solution

Each bandpass filter will, to first order, remove all the energy in frequencies other than its passband. So applying each of the bandpass filters in sequence to the same signal will remove all the signal, since the frequencies passed by one band pass filter are then removed by the subsequent filters with no overlapping passband.

Instead, you should apply each band-pass filter to the original signal, then sum the results. Something like (ignoring channel and offset):

    // Input signal is in buffer[0] to buffer[buffer.length-1]
    // accumulator[] and buffer2[] are also pre-allocated to the same length as buffer[].

    // Initialize output accumulator to zero
    for (int i = 0; i < accumulator.length; ++i)  accumulator[i] = 0;
    // Apply each bandpass filter to copies of the original input
    for (int i = _sampleFilters.Count; i-- > 0; ) {
        // Make a copy of the input
        for (int j = 0; j < buffer.length; ++j)  buffer2[j] = buffer[j];
        // Apply this filter in-place
        _sampleFilters[i].Filters[c].Process(buffer2, buffer2.length);
        // Accumulate the result
        for (int j = 0; j < accumulator.length; ++j)
            accumulator[j] += buffer2[j]
    }
    // Copy back into buffer for output
    for (int i = 0; i < buffer.length; ++i)  buffer[i] = accumulator[i];
}

There are further issues arising from phase cancellations in the frequencies of overlap between adjacent bandpass filters, but this should get you started.

I see some of your bandpass filters have negative Q. That doesn't make any sense to me. Also, even the positive Qs are smaller than 1, which doesn't sound right either. Q is center_frequency/bandwidth; you expect the the bandwidth to be smaller than the center frequency (otherwise the filter is approaching extending all the way down to zero frequency), so it's unusual to see a Q smaller than 2.

And in terms of "negative values" for the gain in different frequencies: We usually see equalization curves in terms of dB, or 20*log_10(gain), which can be positive or negative. The gain itself should be nonnegative; setting the gain to zero effectively removes all the energy at a frequency, which is removing as much of it as you can. Applying a negative gain isn't removing the energy, it's just flipping the polarity of the waveform.

What you're calling "negative values" (pulling the level "below the middle") is in fact a multiplicative gain value smaller than 1 (but greater than zero). If we describe that gain in dB, it will come out as a negative value.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top