Как вы делаете бикубическую (или другую нелинейную) интерполяцию повторно дискретизированных аудиоданных? - PullRequest
16 голосов
/ 14 июля 2009

Я пишу некоторый код, который воспроизводит файлы WAV с различной скоростью, так что волна либо медленнее, и ниже, либо быстрее и выше. В настоящее время я использую простую линейную интерполяцию, например так:

            int newlength = (int)Math.Round(rawdata.Length * lengthMultiplier);
            float[] output = new float[newlength];

            for (int i = 0; i < newlength; i++)
            {
                float realPos = i / lengthMultiplier;
                int iLow = (int)realPos;
                int iHigh = iLow + 1;
                float remainder = realPos - (float)iLow;

                float lowval = 0;
                float highval = 0;
                if ((iLow >= 0) && (iLow < rawdata.Length))
                {
                    lowval = rawdata[iLow];
                }
                if ((iHigh >= 0) && (iHigh < rawdata.Length))
                {
                    highval = rawdata[iHigh];
                }

                output[i] = (highval * remainder) + (lowval * (1 - remainder));
            }

Это работает нормально, но имеет тенденцию звучать нормально только тогда, когда я понижаю частоту воспроизведения (т.е. замедляю ее). Если я увеличу высоту звука при воспроизведении, этот метод будет вызывать высокочастотные артефакты, предположительно из-за потери информации о семплах.

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

Кто-нибудь знает какие-нибудь хорошие примеры или кто-нибудь может написать простой метод бикубической интерполяции? Я щедро вознагражу это, если придется. :)

Обновление : вот пара реализаций методов интерполяции на C # (спасибо Донни Дебору за первый и nosredna за второй):

    public static float InterpolateCubic(float x0, float x1, float x2, float x3, float t)
    {
        float a0, a1, a2, a3;
        a0 = x3 - x2 - x0 + x1;
        a1 = x0 - x1 - a0;
        a2 = x2 - x0;
        a3 = x1;
        return (a0 * (t * t * t)) + (a1 * (t * t)) + (a2 * t) + (a3);
    }

    public static float InterpolateHermite4pt3oX(float x0, float x1, float x2, float x3, float t)
    {
        float c0 = x1;
        float c1 = .5F * (x2 - x0);
        float c2 = x0 - (2.5F * x1) + (2 * x2) - (.5F * x3);
        float c3 = (.5F * (x3 - x0)) + (1.5F * (x1 - x2));
        return (((((c3 * t) + c2) * t) + c1) * t) + c0;
    }

В этих функциях x1 - это значение выборки перед точкой, которую вы пытаетесь оценить, а x2 - это значение выборки после вашей точки. x0 слева от x1, а x3 справа от x2. t изменяется от 0 до 1 и представляет собой расстояние между оцениваемой точкой и точкой x1.

Метод Эрмита, кажется, работает довольно хорошо и, похоже, несколько снижает шум. Что еще более важно, кажется, что это звучит лучше, когда волна ускоряется.

Ответы [ 4 ]

15 голосов
/ 14 июля 2009

Мой любимый ресурс для интерполяции звука (особенно в приложениях по сэмплированию) - Бумага Олли Нимитало "Слон" .

Я использовал пару из них, и они звучат потрясающе (намного лучше, чем прямое кубическое решение, которое относительно шумно). Существуют сплайн-формы, формы Эрмита, Ватта, параболика и т. Д. И они обсуждаются с точки зрения audio . Это не просто ваш типичный наивный полиномиальный пример.

И код включен!

Чтобы решить, какой из них использовать, вы, вероятно, захотите начать с таблицы на стр. 60, которая группирует алгоритмы по сложности операторов (сколько умножается и сколько сложений). Затем выберите одно из лучших решений «сигнал-шум» - используйте свой слух, чтобы сделать окончательный выбор. Примечание. Как правило, чем выше SNR, тем лучше.

7 голосов
/ 14 июля 2009
double InterpCubic(double x0, double x1, double x2, double x3, double t)
{
   double a0, a1, a2, a3;

   a0 = x3 - x2 - x0 + x1;
   a1 = x0 - x1 - a0;
   a2 = x2 - x0;
   a3 = x1;

   return a0*(t^3) + a1*(t^2) + a2*t + a3;
}

где x1 и x2 - выборки, интерполируемые между, x0 - левый сосед x1, а x3 - правый сосед x2. t равно [0, 1], обозначая позицию интерполяции между x1 и x2.

3 голосов
/ 02 июля 2010

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

Мы выпустили несколько простых кодов LGPL для повторной выборки, которые могут выполнять оба эти действия как часть WDL (см. Resample.h).

1 голос
/ 14 июля 2009

Вы ищете полиномиальная интерполяция . Идея состоит в том, что вы выбираете количество известных точек данных вокруг точки, которую вы хотите интерполировать, вычисляете интерполированный полином с использованием точек данных, а затем выясняете значение полинома и точки интерполяции.

Есть и другие методы. Если вы можете разбираться в математике, посмотрите реконструкция сигнала , или Google для "интерполяции сигнала".

...