Эквалайзер во временной области для NAudio (.net)

Я хочу создать 6-полосный (или более) эквалайзер для проекта с открытым исходным кодом, над которым я работаю (iStudio) . Я уже реализовал эквалайзер SkypeFx, но он имеет только 3-х полосный эквалайзер, а я хочу более профессиональный. Поэтому я сам разработал несколько фильтров, используя Matlab, и разработал 6 фильтров ARMA для эквалайзера сэмпла. Конечно, мне нужно фильтровать вывод в реальном времени. Поэтому я продолжил реализацию дифференциального уравнения для этой цели.

    private double[] Filter(float[] buffer, SignalFilter filter, float filterWeight, int count)
    {
        double[] y = new double[buffer.Length];
        for (int n = 0; n < count; n++)
        {
            y[n] = 0.0f;
            for (int k = 0; k < filter.B.Count; k++)
            {
                if (n - k >= 0)
                {
                    y[n] = y[n] + filter.B[k] * (double)buffer[n - k];
                }
            }

            for (int k = 1; k < filter.A.Count; k++)
            {
                if (n - k >= 0)
                {
                    y[n] = y[n] - filter.A[k] * y[n - k];
                }
            }
        }

        return y;
    }

Эта функция довольно проста. В буфере я храню выборки в реальном времени, фильтр представляет собой класс с 2 массивами с коэффициентами AR и MA. Функция вызывается функцией процесса, которая только пропускает буфер через все доступные фильтры и суммирует результат вместе:

    public void Process(float[] buffer, int offset, int count)
    {
        List<double[]> filtered = new List<double[]>();

        for (int i = 0; i < _filters.Count - 5; i++)
        {
            filtered.Add(Filter(buffer, _filters[i], Values[i], count));
        }
        for (int i = 0; i < count; i++)
        {
            buffer[i] = 0.0f;
            for (int x = 0; x < filtered.Count; x++)
            {
                buffer[i] += (float)(filtered[x][i] * ((Values[x] + 1) / 2));
            }
        }
    }

Код был немного укорочен, но этого должно хватить. Эквалайзер отчасти работает, но у него есть две проблемы: первая — создаваемая им задержка (вероятно, нуждается в оптимизации) и искажение звука. Между каждым отфильтрованным буфером есть небольшие удары.

Итак, мой вопрос таков: Почему звук искажается и как это исправить?

Спасибо.


person Legoless    schedule 15.06.2012    source источник
comment
Возможно, вам будет удобнее получить ответ на dsp.stackexchange.com.   -  person earlNameless    schedule 15.06.2012
comment
Спасибо, но я подумал, что это ошибка программирования, потому что теоретически это должно работать.   -  person Legoless    schedule 15.06.2012
comment
вы позволяете значениям с плавающей запятой превышать 1,0? если да будут искажения при преобразовании в 16 бит для отправки на звуковую карту   -  person Mark Heath    schedule 15.06.2012
comment
Значения с плавающей запятой не превышают 1,0 или -1,0, на самом деле я реализовал эти проверки просто для уверенности (но они были удалены из кода в этом посте).   -  person Legoless    schedule 16.06.2012
comment
этот должен работать 2: stackoverflow.com/questions/22018898/sound-with-equalizer   -  person Florian    schedule 04.05.2014


Ответы (1)


Я сам решил проблему, кэшируя несколько значений и используя их в уравнении, когда приходит следующий буфер и значения выходят за пределы индекса текущего буфера (добавляет еще к IF в функции фильтра). Для каждого фильтра требуется собственный кеш, поэтому значения берутся из одного фильтра.

    private double[] Filter(float[] buffer, SignalFilter filter, int count, int index)
    {
        double[] y = new double[count];
        for (int n = 0; n < count; n++)
        {
            for (int k = 0; k < filter.B.Count; k++)
            {
                if (n - k >= 0)
                {
                    y[n] = y[n] + filter.B[k] * buffer[n - k];
                }
                else if (_cache.GetRawCache ().Count > 0)
                {
                    double cached =  _cache.GetRawCache ()[_cache.GetRawCache().Count + (n - k)];
                    y[n] = y[n] + filter.B[k] * cached;
                }
            }

            for (int k = 1; k < filter.A.Count; k++)
            {
                if (n - k >= 0)
                {
                    y[n] = y[n] - filter.A[k] * y[n - k];
                }
                else if (_cache.GetCache(index).Count > 0)
                {
                    double cached =  _cache.GetCache(index)[_cache.GetCache(index).Count + (n - k)];
                    y[n] = y[n] - filter.A[k] * cached;
                }
            }
        }

        return y;
    }
person Legoless    schedule 16.06.2012
comment
Привет, интересно, а можно ли получить точность объекта SignalFilter? - person Pierre-Olivier Pignon; 08.01.2017