Обнаружение обнаружения записи

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

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

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

Ответ 1

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

alt text

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

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

Более простое решение - сначала использовать в своем волновом файле несколько контринтуитивно называемое сжатие (не сжатие 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-библиотеку, вам лучше использовать ее точно, После того, как вы определили начальную и конечную позиции каждой заметки (и включили некоторые дополнения в начале и конце для пропущенных частей атаки и освобождения), вы можете теперь вытащить каждый фрагмент аудиоданных и передать его функции БПФ, чтобы определить высоту тона.

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

Один последний момент, касающийся времени атаки на заметку, заключается в том, что это может быть меньше проблем, чем вы думаете. Часто в музыке инструмент с медленной атакой (например, мягкий синтезатор) начнет запись раньше, чем острый инструмент атаки (например, пианино), и обе ноты будут звучать так, как будто они начинаются в одно и то же время. Если вы играете на инструментах таким образом, алгоритм с тем же временем запуска для обоих видов инструментов, что хорошо с точки зрения WAV-to-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;
    }
}

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

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

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

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 не работает должным образом, на это будет получен ответ (только не я).

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

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

aubio

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

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

Кроме того, у автора библиотеки есть PDF-документ его диссертации на странице, в котором есть большая информация и информация о маркировке.

Ответ 5

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

SUM от 0 до N (X ^ 2)

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

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

Для инженеров Hardcore:

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

Легче для обычного человека понять:

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

Ответ 6

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