Распознавание высоты звука музыкальных нот на смартфоне - PullRequest
21 голосов
/ 22 сентября 2009

При ограниченных ресурсах, таких как более медленные процессоры, размер кода и оперативная память, как лучше всего определить высоту музыкальной ноты, аналогично тому, что будет делать электронный или программный тюнер?

Должен ли я использовать:

  • Kiss FFT
  • FFTW
  • Дискретное вейвлет-преобразование
  • автокорреляция
  • анализ пересечения нуля
  • октавные фильтры

другой

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

Ответы [ 5 ]

14 голосов
/ 28 ноября 2009

Если вам не нужна такая большая точность, БПФ может быть достаточно. Окно Сначала блок аудио, чтобы вы получили четко определенные пики, а затем найдите первый значимый пик.

Ширина корзины = частота дискретизации / размер БПФ:

Основы в диапазоне от 20 Гц до 7 кГц, поэтому будет достаточно частоты дискретизации 14 кГц. Следующая «стандартная» частота дискретизации составляет 22050 Гц.

Размер БПФ определяется требуемой точностью. Выход БПФ линейный по частоте, а музыкальные тоны - логарифмические по частоте, поэтому наихудшая точность будет на низких частотах. Для 20% полутона при 20 Гц вам нужна ширина 1,2 Гц , что означает длину БПФ 18545 . Следующая степень двойки равна 2 15 = 32768. Это 1,5 секунды данных и для расчета процессора моего ноутбука 3 мс.

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

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

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

Я написал несколько различных методов в Python для сравнения.

13 голосов
/ 22 сентября 2009

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

В моем приложении (программном синтезаторе, который работает на смартфонах) я использую записи отдельных инструментальных нот в качестве сырья для волнового синтеза, и для создания нот с определенной высотой мне нужно знать основную высоту звука. запись с точностью до 1/1000 от полутона (мне действительно нужна только точность 1/100, но я об этом не знаю). Подход с пересечением нуля намного слишком неточен для этого, а подходы на основе БПФ либо слишком неточны, либо слишком медленны (или иногда оба).

Лучший подход, который я нашел в этом случае, это использовать автокорреляцию. С автокорреляцией вы в основном угадываете высоту тона, а затем измеряете автокорреляцию вашего образца на соответствующей длине волны. Просматривая диапазон вероятных высот (скажем, от A = 55 Гц до A = 880 Гц) полутонами, я определяю наиболее коррелированную высоту, а затем выполняю более мелкозернистое сканирование в окрестности этой высоты, чтобы получить более точное значение.

Лучший для вас подход полностью зависит от того, для чего вы пытаетесь его использовать.

6 голосов
/ 22 сентября 2009

Я не знаком со всеми упомянутыми вами методами, но то, что вы выберете, должно зависеть в первую очередь от характера ваших входных данных. Вы анализируете чистые тона или в вашем источнике есть несколько заметок? Является ли речь особенностью вашего вклада? Существуют ли какие-либо ограничения на продолжительность выборки входных данных? Вы в состоянии обменять некоторую точность на скорость?

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

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

Измерение точек пересечения нуля является простым и понятным, но столкнется с проблемами, если в сигнале присутствует несколько сигналов.

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

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

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

5 голосов
/ 22 сентября 2009

Пересечение нуля не будет работать, потому что типичный звук имеет гармоники и пересечения нуля намного больше, чем базовая частота.

Что-то, с чем я экспериментировал (как домашний проект), было:

  1. Сэмплируйте звук с АЦП на любой частоте дискретизации.
  2. Обнаружение уровней краткосрочных положительных и отрицательных пиков формы сигнала (скользящее окно или аналогичное). То есть детектор конвертов.
  3. Создайте прямоугольную волну, которая повышается, когда форма волны находится в пределах 90% (или около того) положительной огибающей, и понижается, когда форма волны находится в пределах 90% отрицательной огибающей. То есть следящая прямоугольная волна с гистерезисом.
  4. Измерьте частоту этой прямоугольной волны с помощью прямого подсчета времени / времени, используя столько сэмплов, сколько необходимо для получения требуемой точности.

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

5 голосов
/ 22 сентября 2009

В моем проекте danstuner я взял код от Audacity . По сути, потребовалось БПФ, а затем нашли пиковую мощность, поместив кубическую кривую на БПФ и найдя пик этой кривой. Работает довольно хорошо, хотя мне пришлось остерегаться октавных прыжков.

См. Spectrum.cpp .

...