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

Я пишу код, который воспроизводит файлы 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 # реализаций методов интерполяции (спасибо Donnie DeBoer за первый и 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.

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


person MusiGenesis    schedule 14.07.2009    source источник
comment
Разве не бикубичность то, что вы делаете с 2D-сигналом (т. Е. Изображением)? Неужто вы имеете в виду кубический для одномерного (т.е. звукового) сигнала? Хотя я могу ошибаться ...   -  person Goz    schedule 14.07.2009
comment
@Goz: это может быть просто кубический для 1D аудио (я не знаю). Отчасти моя проблема в том, что все образцы кода, которые я видел, предназначены для 2D-графики, а мне нужен только один D.   -  person MusiGenesis    schedule 14.07.2009
comment
@MusiGenesis, да, вы НЕ хотите использовать решение для графики. Ухо очень разборчивое. Вы хотите использовать решение, обеспечивающее высокое отношение сигнал / шум. Смотрите мой ответ ниже.   -  person Nosredna    schedule 14.07.2009
comment
Я просто перечитал и заметил, что вы собираетесь предложить награду. Чувак, почему я так быстро ответил?   -  person Nosredna    schedule 14.07.2009
comment
Я еще не выбрал ответ, так что награда может появиться. Я могу выложить всю свою репутацию.   -  person MusiGenesis    schedule 14.07.2009
comment
Не думаю, что тебе стоит выкладывать всю свою репутацию. Лучшее, что вы можете сделать, чтобы взять существующий образец и создать версию с избыточной дискретизацией, - это использовать кривую, которая добавляет как можно меньше шума к исходному сэмплу. Вы не можете вернуть недостающую информацию. Поэтому вряд ли у вас получится лучше, чем замечательные формулы Elephant. Однако вы можете задать вопрос: почему звук у меня «дешевый», когда я увеличиваю его частоту?   -  person Nosredna    schedule 14.07.2009
comment
Я задавал этот вопрос много лет. :)   -  person MusiGenesis    schedule 14.07.2009
comment
Многие инструменты имеют характерные звуки, которые портятся при повышении высоты звука. Человеческий голос один. В мужских и женских голосах есть форманты. Если вы просто повысите высоту звука, это может прозвучать дешево или глупо. Но если поднять высоту звука и оставить форманты, он может звучать лучше. Некоторые синтезаторы имеют секции формантного фильтра.   -  person Nosredna    schedule 14.07.2009


Ответы (4)


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

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

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

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

person Nosredna    schedule 14.07.2009
comment
И снова отличная ссылка. Я сейчас копаюсь в этом. Я только что реализовал кубическую интерполяцию из другого ответа, и это звучало ужасно. - person MusiGenesis; 14.07.2009
comment
Если вы используете какой-либо из них с отношением сигнал / шум, скажем, выше 60, вы не сможете услышать артефакты. Если вы это сделаете, вы, вероятно, допустили ошибку при реализации. И не стоит недооценивать легкость, с которой вы можете ошибиться, какая точка есть какая, а какая у вас промежуточная ценность. Я напортачил с первой попытки. Возможно, вы даже испортили кубик. Это помогает графически отображать разделы ввода и вывода. :-) - person Nosredna; 14.07.2009
comment
Ха, как будто я никогда не ошибаюсь! - person MusiGenesis; 14.07.2009
comment
Думаю, я правильно реализовал кубическую форму - это была лишь небольшая модификация моего исходного кода. - person MusiGenesis; 14.07.2009
comment
Плохой результат кубики меня не удивил. Но невероятно легко отклониться на единицу или получить промежуточное значение в 1-x, когда оно должно быть x, и т. Д. - person Nosredna; 14.07.2009
comment
Возможно, я пропустил это в тексте, но в чем разница между реализацией x-формы и реализацией z-формы? - person MusiGenesis; 14.07.2009
comment
Это обсуждается на 35 и 36. Если я правильно помню, они эквивалентны по результату, но один может быть дешевле в вычислении, чем другой, в зависимости от конкретного интерполятора. Для вас это не должно иметь значения. Он делает и то, и другое для каждого уравнения и предлагает более дешевое решение. - person Nosredna; 14.07.2009
comment
Кроме того, извините за мою плотность, но в связанной статье эти интерполяторы рекомендуются для данных с передискретизацией, но я работаю над предварительно записанными файлами WAV, которые не могут быть передискретизированы (если я не понимаю термин?). Автор говорит, что передискретизация оставлена ​​на усмотрение читателя, поэтому, возможно, мне нужно задать здесь еще один вопрос. - person MusiGenesis; 14.07.2009
comment
Однако прошло 3 или 4 года с тех пор, как я использовал один из них. Так что я, скорее всего, ошибаюсь в каком-то конкретном пункте. Единственное, в чем я уверен, - это то, что интерполяторы в статье лучше всего, что я когда-либо находил. Когда я искал газету, у меня был момент паники, потому что я был не там, где раньше. Я получил 404 и чуть не сделал ложный выпад. Затем я поискал имя файла pdf и, наконец, нашел его. Страшный. - person Nosredna; 14.07.2009
comment
Автор упоминает передискретизацию высокого N с простой линейной интерполяцией как высококачественный подход к этой проблеме. Это может быть лучшим подходом для моих целей, так как я мог бы один раз сделать передискретизацию исходного звука, а затем быстро воспроизвести на лету разные скорости с линейной интерполяцией. - person MusiGenesis; 14.07.2009
comment
Я сохранил копию на своем ноутбуке - хранитель. - person MusiGenesis; 14.07.2009
comment
Идеально иметь данные с передискретизацией. Если вы этого не сделаете, вы ничего не сможете с этим поделать. Я использовал их в кольцевых модуляторах реального времени, генераторах и т. Д. - person Nosredna; 14.07.2009
comment
Можно ли получить данные с передискретизацией из предварительно записанного файла WAV? Я задам это еще раз, как реальный вопрос - я просто не хочу выглядеть особенно глупо. - person MusiGenesis; 14.07.2009
comment
@MusiGnesis, ваша ситуация отличается от моей. Что бы вы ни делали, я хочу знать, что вы сделали, если это принесет хорошие результаты. Что мне нравится в этих уравнениях, так это то, что вы не получаете шума или странных обертонов. - person Nosredna; 14.07.2009
comment
Нет, вы не можете получить данные с передискретизацией из предварительно записанного файла WAV. Найквист, по сути, говорит, что у вас нет никакой реальной информации ни для каких частот выше 1/2 частоты дискретизации. - person Nosredna; 14.07.2009
comment
Поскольку у вас есть существующие данные (и это та же проблема, что и сгенерированные в реальном времени данные, за исключением того, что мы можем выбрать работу наших осцилляторов на 2x, 4x, 8x или в зависимости от того, что будет обрабатывать процессор), все, что вы можете сделать, это нарисовать изгибайте точки, чтобы добавить минимально возможное количество шума. Вы не можете получить никаких дополнительных данных из своего образца - эти данные больше не существуют - они также могут быть в черной дыре. - person Nosredna; 14.07.2009
comment
Я собираюсь реализовать 4-точечный метод Эрмита, который, по его мнению, лучше всего подходит для данных без передискретизации. Забавно то, что я никогда не считал линейную интерполяцию настолько ужасной, но я использую данные файла WAV для тональных звуков синтезатора, и обычно мне удается только понизить частоту. Я хотел бы иметь возможность поднять высоту звука, не звучая как FM-синтезатор звуковой карты 1993 года. - person MusiGenesis; 14.07.2009
comment
Возможно ли, что вас беспокоит эффект Элвина и бурундуков? Вы что-нибудь знаете о формантных фильтрах? (Но линейная интерполяция абсолютно добавляет шум на 10 дБ ниже вашего сигнала.) - person Nosredna; 14.07.2009
comment
Я делаю вариант синтеза волновой таблицы, но мой код формирует огибающие амплитуды для всех нот, поэтому общая форма одинакова независимо от высоты тона. Конкретная проблема, с которой я сталкиваюсь, заключается в том, что часть сустейна звучит как скрипучая (если это имеет смысл), когда я создаю ноту на более высокой частоте. Интерполяция Эрмита, кажется, делает эту часть более качественной и четкой, но, возможно, мои аудионейроны сегодня умирают быстрее. - person MusiGenesis; 14.07.2009
comment
Как дела сустейн? Повторять один и тот же раздел снова и снова? Откуда этот раздел? Вы поднимаете низкочастотный шум в слышимый диапазон. - person Nosredna; 14.07.2009
comment
Это петлевой подход. Я не думаю, что проблема в том, что низкочастотный шум переходит в слышимый. Царапины очень высокочастотны - я могу избавиться от них с помощью фильтра нижних частот, но мне не нравится общий эффект притупления, и я стараюсь избегать выполнения БПФ. - person MusiGenesis; 14.07.2009
comment
Любые частоты рядом с Найквистом могут сделать это с вами, когда вы увеличите скорость. Вы должны выполнить фильтр нижних частот, прежде чем увеличивать скорость, иначе вы будете вырезать звуки, которые ему принадлежат, а не только те, которые загибаются (вероятно, поэтому вам не хватает яркости). Предположим, у вас есть семпл, который вы хотите воспроизвести на 44100. У вас есть семпл, который вы хотите воспроизвести с удвоенной скоростью. Установите обрезание lowpass на 11025, сделайте фильтр, затем увеличьте скорость. Вы не хотите, чтобы какие-либо частоты превышали Найквиста. - person Nosredna; 15.07.2009
comment
Спасибо. Это обновленный адрес, который содержит исправленный документ и сопроводительный zip-файл с исходным кодом: yehar.com/blog /? p = 197 - person Tobia; 29.11.2020
comment
Привет, я проверил все алгоритмы и остановился на B-сплайне для простого и хорошего качества, но у него есть ошибка, потому что, когда я вычисляю выборку между x0, x1, x2, x3, все значения между x1 и x2 имеют немного offset, coz, если я попытаюсь нарисовать кривые звуковой волны из этого алгоритма, это покажет, что кривая никогда не достигает значений x1 и x2, но немного ниже исходной формы волны. В настоящее время используется Hermite без такой ошибки. Кто-нибудь может мне посоветовать, как и когда использовать Оптимальный алгоритм, это полезно? у него много вариаций 2x, 4x, 8x как и когда его использовать? - person Diljeet; 30.11.2020
comment
@Nosredna И, пожалуйста, кто-нибудь может предложить, какой алгоритм лучше всего подходит для понижающей дискретизации, если я использую Optimal 2x для всей передискретизации с любой частоты дискретизации до любой частоты дискретизации, будет ли это нормально, или я должен использовать все алгоритмы и переключиться на них 2x, 4x, 8x .. всякий раз, когда это необходимо? и подходит ли алгоритм Optimal 2x для понижающей дискретизации? - person Diljeet; 30.11.2020

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.

person Donnie DeBoer    schedule 14.07.2009
comment
Мне нравится. Я собираюсь попробовать это. - person MusiGenesis; 14.07.2009
comment
Одно замечание: поскольку кубическая интерполяция использует 4 отсчета (2 интерполируются между и их 2 ближайшими соседями), вы должны выяснить, как обрабатывать самый первый интервал интерполяции и самый последний интервал интерполяции данных сигнала. Часто люди просто изобретают образцы фантомов слева и справа. - person Donnie DeBoer; 14.07.2009
comment
Без проблем. В моем примере выше используется фантомный образец справа. - person MusiGenesis; 14.07.2009
comment
Что ж, работает, но звучит, к сожалению, даже хуже, чем линейная интерполяция. Линейная интерполяция, кажется, производит больше общего низкоуровневого шипения, тогда как эта кубическая формула имеет тенденцию производить высокий звон. - person MusiGenesis; 14.07.2009
comment
Если вы посмотрите на обработанный образец с помощью анализатора спектра, вы увидите шипение как минимальный уровень шума. Звон, вероятно, является результатом нескольких добавленных частот кубической модуляции по амплитуде. - person Nosredna; 14.07.2009
comment
Будьте осторожны при копировании этого кода, оператор ^ часто используется за пределами C-языков для обозначения степени, но в большинстве языков это оператор XOR. Поэтому замените t ^ 3 на t t t и t ^ 2 на t * t. - person Karsten Becker; 28.06.2021

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

Мы выпустили простой код передискретизации LGPL, который может выполнять обе эти задачи как часть WDL (см. Пример .час).

person Justin Frankel    schedule 02.07.2010
comment
Да я согласен. В конце концов я вернулся к прямой интерполяции, так как улучшение по сравнению с линейной интерполяцией было практически незаметным. - person MusiGenesis; 06.05.2011

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

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

person Oren Trutner    schedule 14.07.2009
comment
Я могу смириться с математикой, но в основном я ищу образцы кода (желательно C # или C). - person MusiGenesis; 14.07.2009