Обратите внимание на обнаружение начала - PullRequest
31 голосов
/ 17 ноября 2008

Я разрабатываю систему в помощь музыкантам, выполняющим транскрипцию. Цель состоит в том, чтобы выполнить автоматическую транскрипцию музыки (она не должна быть идеальной, так как пользователь исправит ошибки / ошибки позже) на монофонической записи одного инструмента. У кого-нибудь здесь есть опыт автоматической транскрипции музыки? Или цифровая обработка сигналов вообще? Мы очень ценим помощь любого, независимо от вашего происхождения.

До сих пор я исследовал использование быстрого преобразования Фурье для обнаружения основного тона, и ряд тестов как в MATLAB, так и в моих собственных программах тестирования Java показали, что он достаточно быстрый и точный для моих нужд. Другим элементом задачи, которую необходимо решить, является отображение произведенных MIDI-данных в виде нот, но это то, что меня сейчас не касается.

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

Ответы [ 6 ]

50 голосов
/ 17 ноября 2008

Вот график, который иллюстрирует пороговый подход к обнаружению появления ноты:

alt text

На этом изображении показан типичный файл WAV, в котором последовательно воспроизводятся три отдельные ноты. Красная линия представляет выбранный порог сигнала, а синие линии представляют начальные позиции нот, возвращаемые простым алгоритмом, который отмечает начало, когда уровень сигнала пересекает порог.

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

Более простое решение состоит в том, чтобы сначала использовать в вашем волновом файле несколько нелогичное название сжатия (, а не MP3-сжатие - это нечто совсем другое ). Сжатие по существу сглаживает пики в ваших аудиоданных, а затем усиливает все, так что большее количество звука приближается к максимальным значениям. Эффект на приведенном выше примере будет выглядеть следующим образом (что показывает, почему название «сжатие», по-видимому, не имеет смысла - на аудиооборудовании оно обычно обозначается как «громкость»):

alt text

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

В терминах кодирования WAV-файл, загруженный в память, по сути представляет собой массив двухбайтовых целых чисел, где 0 представляет отсутствие сигнала, а 32 767 и -32 768 представляют пики. В своей простейшей форме алгоритм обнаружения порога будет просто запускаться с первой выборки и считывать массив, пока не найдет значение, превышающее порог.

short threshold = 10000;
for (int i = 0; i < samples.Length; i++)
{
    if ((short)Math.Abs(samples[i]) > threshold) 
    {
        // here is one note onset point
    }
}

На практике это работает ужасно, поскольку обычное аудио имеет всевозможные переходные пики выше заданного порога. Одним из решений является использование скользящего среднего уровня сигнала (т. Е. Не отмечать начало, пока среднее значение из последних n выборок не превысит пороговое значение).

short threshold = 10000;
int window_length = 100;
int running_total = 0;
// tally up the first window_length samples
for (int i = 0; i < window_length; i++)
{
    running_total += samples[i];
}
// calculate moving average
for (int i = window_length; i < samples.Length; i++)
{
    // remove oldest sample and add current
    running_total -= samples[i - window_length];
    running_total += samples[i];
    short moving_average = running_total / window_length;
    if (moving_average > threshold)
    {
        // here is one note onset point 
        int onset_point = i - (window_length / 2);
    }
}

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

Обновление: на этом рисунке показана деталь обнаружения заметки, которую я пропустил, а именно, определение окончания заметки:

alt text

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

После того как вы определили начальную и конечную точки каждой ноты, теперь вы можете анализировать каждый фрагмент данных WAV-файла для определения высот.

Обновление 2: я только что прочитал ваш обновленный вопрос. Обнаружение основного тона с помощью автокорреляции гораздо проще реализовать, чем FFT, если вы пишете свое собственное с нуля, но если вы уже извлекли и использовали предварительно созданную библиотеку FFT, вам лучше использовать ее наверняка. , После того, как вы определили начальную и конечную позиции каждой ноты (и включили некоторые отступы в начале и в конце для пропущенных частей атаки и выпуска), теперь вы можете извлечь каждый фрагмент аудиоданных и передать их функции FFT для определить высоту.

Одним из важных моментов здесь является не использование фрагмента сжатых аудиоданных, а использование фрагмента исходных неизмененных данных. Процесс сжатия искажает звук и может привести к неточному считыванию основного тона.

И последнее замечание о времени атаки на ноты: это может быть меньшей проблемой, чем вы думаете. Часто в музыке инструмент с медленной атакой (например, мягкий синтезатор) начинает ноту раньше, чем острый инструмент атаки (например, пианино), и обе ноты будут звучать так, как если бы они начинались одновременно. Если вы играете на инструментах подобным образом, алгоритм выберет одинаковое время начала для обоих типов инструментов, что хорошо с точки зрения WAV-MIDI.

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

Да, и важно: термин "сжатие" здесь не относится к сжатию в стиле MP3 .

Обновите снова: вот простая функция, которая выполняет динамическое сжатие:

public void StaticCompress(short[] samples, float param)
{
    for (int i = 0; i < samples.Length; i++)
    {
        int sign = (samples[i] < 0) ? -1 : 1;
        float norm = ABS(samples[i] / 32768); // NOT short.MaxValue
        norm = 1.0 - POW(1.0 - norm, param);
        samples[i] = 32768 * norm * sign;
    }
}

Когда param = 1.0, эта функция не будет влиять на звук. Большие значения параметра (2,0 - это хорошо, что будет возводить в квадрат нормализованную разницу между каждым сэмплом и максимальным пиковым значением), что приведет к большей компрессии и более громкому (но дрянному) звучанию. Значения ниже 1.0 вызовут эффект расширения.

Еще один, вероятно, очевидный момент: вам следует записывать музыку в маленькой неэхогенной комнате, поскольку эхо-сигналы часто улавливаются этим алгоритмом в виде фантомных нот.

Обновление: вот версия StaticCompress, которая будет компилироваться в C #, и Explicity приведёт все. Это возвращает ожидаемый результат:

public void StaticCompress(short[] samples, double param)
{
    for (int i = 0; i < samples.Length; i++)
    {
        Compress(ref samples[i], param);
    }
}

public void Compress(ref short orig, double param)
{
    double sign = 1;
    if (orig < 0)
    {
        sign = -1;
    }
    // 32768 is max abs value of a short. best practice is to pre-
    // normalize data or use peak value in place of 32768
    double norm = Math.Abs((double)orig / 32768.0);
    norm = 1.0 - Math.Pow(1.0 - norm, param);
    orig = (short)(32768.0 * norm * sign); // should round before cast,
        // but won't affect note onset detection
}

Извините, мой уровень знаний о Matlab равен 0. Если вы разместили еще один вопрос о том, почему ваша функция Matlab не работает должным образом, на нее ответят (только не я).

4 голосов
/ 17 ноября 2008

Вы должны посмотреть на MIRToolbox - он написан для Matlab и имеет встроенный детектор начала - он работает довольно хорошо Исходный код GPL, так что вы можете реализовать алгоритм на любом языке, который вам подходит. На каком языке будет использоваться ваш производственный код?

4 голосов
/ 17 ноября 2008

То, что вы хотите сделать, часто называется WAV-to-MIDI (google "wav-to-midi"). Было много попыток этого процесса, с разными результатами (заметка - одна из трудностей; с полифонией гораздо сложнее иметь дело). Я бы рекомендовал начать с тщательного поиска готовых решений и начинать работу самостоятельно, только если нет ничего приемлемого.

Другая часть процесса, в которой вы нуждаетесь, заключается в том, чтобы визуализировать MIDI-вывод в виде традиционной музыкальной партитуры, но существует множество миллиардов продуктов, которые это делают.

Другой ответ: да, я много занимался цифровой обработкой сигналов (см. Программное обеспечение на моем веб-сайте - это программный синтезатор с бесконечным голосом, написанный на VB и C), и я заинтересован в том, чтобы помочь вам с Эта проблема. Концептуально часть WAV-to-MIDI не так уж и сложна, она просто делает ее надежной на практике, что сложно. Начало записи - это просто установка порога - ошибки могут быть легко скорректированы вперед или назад во времени, чтобы компенсировать различия в атаках нот. Обнаружение основного тона на записи гораздо проще, чем в режиме реального времени, и включает в себя просто выполнение процедуры автокорреляции.

3 голосов
/ 14 марта 2012

Твердые приступы легко обнаруживаются во временной области с помощью измерения средней энергии.

СУММА от 0 до N (X ^ 2)

Сделайте это с кусками всего сигнала. Вы должны видеть пики, когда происходят вхождения (размер окна зависит от вас, мое предложение составляет 50 мс или более).

Обширные документы по обнаружению начала:

Для хардкорных инженеров:

http://www.nyu.edu/classes/bello/MIR_files/2005_BelloEtAl_IEEE_TSALP.pdf

Обычному человеку легче понять:

http://bingweb.binghamton.edu/~ahess2/Onset_Detection_Nov302011.pdf

3 голосов
/ 17 ноября 2008

эта библиотека сосредоточена вокруг звуковой маркировки:

aubio

aubio - это библиотека для звуковой маркировки. Его функции включают сегментирование звукового файла перед каждой из его атак, выполнение определения высоты тона, нажатие на удар и создание миди-потоков из живого аудио. Название aubio происходит от «audio» с опечаткой: в результатах также могут быть обнаружены несколько ошибок транскрипции.

и мне повезло с этим для обнаружения начала и определения высоты тона. Это в c, но есть оболочки swig / python.

Кроме того, у автора библиотеки есть страница с диссертацией на странице, в которой содержится отличная информация и сведения о маркировке.

0 голосов
/ 17 ноября 2008

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

...