Оглавление:

Детектор музыкальных нот: 3 шага
Детектор музыкальных нот: 3 шага

Видео: Детектор музыкальных нот: 3 шага

Видео: Детектор музыкальных нот: 3 шага
Видео: 😱Хакерская SDR Прослушка На Xiaomi 🔥 2024, Ноябрь
Anonim
Image
Image

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

Подробности

В этом проекте аналоговый выход детектора звукового модуля отправляется на аналоговый вход A0 Arduino Uno. Аналоговый сигнал дискретизируется и квантуется (оцифровывается). Код автокорреляции, взвешивания и настройки используется для нахождения основной частоты с использованием первых 3 периодов. Затем приблизительная основная частота сравнивается с частотами в диапазоне октав 3, 4 и 5 для определения ближайшей частоты музыкальной ноты. Наконец, на экране печатается предполагаемое примечание для ближайшей частоты.

Примечание. В этом руководстве рассказывается только о том, как построить проект. Для получения дополнительной информации о деталях и обоснованиях дизайна перейдите по этой ссылке: Подробнее

Запасы

  • (1) Arduino Uno (или Genuino Uno)
  • (1) Совместимость с модулем обнаружения звука высокой чувствительности датчика микрофона DEVMO
  • (1) Макетная плата без пайки
  • (1) Кабель USB-A - B
  • Провода перемычки
  • Музыкальный источник (фортепиано, клавиатура или приложение paino с динамиками)
  • (1) Компьютер или ноутбук

Шаг 1. Создайте оборудование для детектора музыкальных нот

Настройка детектора музыкальных нот
Настройка детектора музыкальных нот

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

Шаг 2: запрограммируйте детектор музыкальных нот

В IDE Arduino добавьте следующий код.

gistfile1.txt

/*
Имя файла / эскиза: MusicalNoteDetector
Номер версии: v1.0 Создано 7 июня 2020 г.
Автор оригинала: Клайд А. Леттсом, PhD, PE, MEM
Описание: этот код / эскиз отображает приблизительную частоту, а также музыкальную ноту, сыгранную на электронной клавиатуре или в приложении для фортепиано. Для этого проекта аналоговый выход из
Звуковой модуль детектора отправляется на аналоговый вход A0 Arduino Uno. Аналоговый сигнал дискретизируется и квантуется (оцифровывается). Код автокорреляции, взвешивания и настройки используется для
найти основную частоту, используя первые 3 периода. Затем приблизительная основная частота сравнивается с частотами в диапазоне 3, 4 и 5 октав для определения ближайшего музыкального
обратите внимание на частоту. Наконец, на экране печатается предполагаемое примечание для ближайшей частоты.
Лицензия: Эта программа является бесплатным программным обеспечением; вы можете распространять и / или изменять его в соответствии с условиями Стандартной общественной лицензии GNU (GPL) версии 3 или любой более поздней.
версия по вашему выбору, опубликованная Free Software Foundation.
Примечания: Copyright (c) 2020 by C. A. Lettsome Services, LLC
Для получения дополнительной информации посетите
*/
#define SAMPLES 128 // Макс 128 для Arduino Uno.
#define SAMPLING_FREQUENCY 2048 // Fs = на основе Найквиста, должно быть в 2 раза больше максимальной ожидаемой частоты.
#define OFFSETSAMPLES 40 // используется для калибровки
#define TUNER -3 // Регулируйте, пока C3 не станет 130,50
float samplingPeriod;
беззнаковые длинные микросекунды;
int X [ОБРАЗЦЫ]; // создаем вектор размера SAMPLES для хранения реальных значений
float autoCorr [ОБРАЗЦЫ]; // создаем вектор размера SAMPLES для хранения мнимых значений
float storedNoteFreq [12] = {130,81, 138,59, 146,83, 155,56, 164,81, 174,61, 185, 196, 207,65, 220, 233,08, 246,94};
int sumOffSet = 0;
int offSet [СМЕЩЕНИЯ]; // создаем вектор смещения
int avgOffSet; // создаем вектор смещения
int i, k, periodEnd, periodBegin, period, adjuster, noteLocation, octaveRange;
float maxValue, minValue;
длинная сумма;
int thresh = 0;
int numOfCycles = 0;
float signalFrequency, signalFrequency2, signalFrequency3, signalFrequencyGuess, total;
байт state_machine = 0;
int samplesPerPeriod = 0;
установка void ()
{
Serial.begin (115200); // 115200 бод для последовательного монитора
}
пустой цикл ()
{
//*****************************************************************
// Раздел калибровки
//*****************************************************************
Serial.println («Калибровка. Пожалуйста, не играйте никаких нот во время калибровки.»);
for (i = 0; i <OFFSETSAMPLES; i ++)
{
offSet = analogRead (0); // Считывает значение с аналогового вывода 0 (A0), квантует его и сохраняет как действительный член.
//Serial.println(offSet); // используйте это, чтобы настроить модуль обнаружения звука примерно на половину или 512, когда звук не воспроизводится.
sumOffSet = sumOffSet + offSet [я];
}
samplesPerPeriod = 0;
maxValue = 0;
//*****************************************************************
// Готовимся принять ввод от A0
//*****************************************************************
avgOffSet = round (sumOffSet / OFFSETSAMPLES);
Serial.println («Обратный отсчет»);
задержка (1000); // пауза на 1 секунду
Serial.println («3»);
задержка (1000); // пауза на 1 секунду
Serial.println («2»);
задержка (1000); // пауза на 1
Serial.println («1»);
задержка (1000); // пауза на 1 секунду
Serial.println («Сыграй свою ноту!»);
задержка (250); // пауза на 1/4 секунды на время реакции
//*****************************************************************
// Собираем SAMPLES выборки из A0 с периодом выборки samplingPeriod
//*****************************************************************
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; // Период в микросекундах
для (i = 0; i <ОБРАЗЦЫ; i ++)
{
микросекунды = микросекунды (); // Возвращает количество микросекунд, прошедших с того момента, как плата Arduino начала запускать текущий скрипт.
X = analogRead (0); // Считывает значение с аналогового вывода 0 (A0), квантует его и сохраняет как действительный член.
/ * оставшееся время ожидания между выборками, если необходимо, в секундах * /
а (микросекунды () <(микросекунды + (период выборки * 1000000)))
{
// ничего не делаем, просто ждем
}
}
//*****************************************************************
// Автокорреляционная функция
//*****************************************************************
for (i = 0; i <SAMPLES; i ++) // i = задержка
{
сумма = 0;
for (k = 0; k <SAMPLES - i; k ++) // Сопоставить сигнал с задержанным сигналом
{
сумма = сумма + (((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)); // X [k] - это сигнал, а X [k + i] - это отложенная версия
}
autoCorr = сумма / ОБРАЗЦЫ;
// Конечный автомат первого обнаружения пика
если (state_machine == 0 && i == 0)
{
порог = autoCorr * 0,5;
state_machine = 1;
}
else if (state_machine == 1 && i> 0 && thresh 0) // state_machine = 1, найти 1 период для использования первого цикла
{
maxValue = autoCorr ;
}
иначе if (state_machine == 1 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodBegin = i-1;
state_machine = 2;
numOfCycles = 1;
samplesPerPeriod = (periodBegin - 0);
период = samplesPerPeriod;
регулятор = TUNER + (50.04 * exp (-0.102 * samplesPerPeriod));
signalFrequency = ((SAMPLING_FREQUENCY) / (samplesPerPeriod)) - регулятор; // f = fs / N
}
else if (state_machine == 2 && i> 0 && thresh 0) // state_machine = 2, найти 2 периода для 1-го и 2-го цикла
{
maxValue = autoCorr ;
}
иначе if (state_machine == 2 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodEnd = i-1;
state_machine = 3;
numOfCycles = 2;
samplesPerPeriod = (periodEnd - 0);
signalFrequency2 = ((numOfCycles * SAMPLING_FREQUENCY) / (samplesPerPeriod)) - регулятор; // f = (2 * fs) / (2 * N)
maxValue = 0;
}
else if (state_machine == 3 && i> 0 && thresh 0) // state_machine = 3, найти 3 периода для 1-го, 2-го и 3-го цикла
{
maxValue = autoCorr ;
}
иначе if (state_machine == 3 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodEnd = i-1;
state_machine = 4;
numOfCycles = 3;
samplesPerPeriod = (periodEnd - 0);
signalFrequency3 = ((numOfCycles * SAMPLING_FREQUENCY) / (samplesPerPeriod)) - регулятор; // f = (3 * fs) / (3 * N)
}
}
//*****************************************************************
// Анализ результатов
//*****************************************************************
если (samplesPerPeriod == 0)
{
Serial.println («Хм….. я не уверен. Вы пытаетесь меня обмануть?»);
}
еще
{
// подготавливаем весовую функцию
всего = 0;
если (частота сигнала! = 0)
{
всего = 1;
}
если (signalFrequency2! = 0)
{
итого = всего + 2;
}
если (signalFrequency3! = 0)
{
итого = всего + 3;
}
// вычисляем частоту с помощью весовой функции
signalFrequencyGuess = ((1 / всего) * signalFrequency) + ((2 / total) * signalFrequency2) + ((3 / total) * signalFrequency3); // находим взвешенную частоту
Serial.print («Сыгранная вами нота примерно равна»);
Serial.print (signalFrequencyGuess); // Распечатываем предположение о частоте.
Serial.println («Гц»);
// находим диапазон октав на основе предположения
octaveRange = 3;
while (! (signalFrequencyGuess> = storedNoteFreq [0] -7 && signalFrequencyGuess <= storedNoteFreq [11] +7))
{
для (я = 0; я <12; я ++)
{
storedNoteFreq = 2 * storedNoteFreq ;
}
octaveRange ++;
}
// Находим ближайшую заметку
minValue = 10000000;
noteLocation = 0;
для (я = 0; я <12; я ++)
{
если (minValue> abs (signalFrequencyGuess-storedNoteFreq ))
{
minValue = abs (signalFrequencyGuess-storedNoteFreq );
noteLocation = i;
}
}
// Распечатываем заметку
Serial.print («Думаю, ты играл»);
если (noteLocation == 0)
{
Serial.print ("C");
}
иначе, если (noteLocation == 1)
{
Serial.print («C #»);
}
иначе, если (noteLocation == 2)
{
Serial.print ("D");
}
иначе, если (noteLocation == 3)
{
Serial.print ("D #");
}
иначе, если (noteLocation == 4)
{
Serial.print («E»);
}
иначе, если (noteLocation == 5)
{
Serial.print («F»);
}
иначе, если (noteLocation == 6)
{
Serial.print ("F #");
}
иначе, если (noteLocation == 7)
{
Serial.print ("G");
}
иначе, если (noteLocation == 8)
{
Serial.print ("G #");
}
иначе, если (noteLocation == 9)
{
Serial.print («А»);
}
иначе, если (noteLocation == 10)
{
Serial.print ("A #");
}
иначе, если (noteLocation == 11)
{
Serial.print («B»);
}
Serial.println (octaveRange);
}
//*****************************************************************
//Остановись здесь. Нажмите кнопку сброса на Arduino, чтобы перезапустить
//*****************************************************************
в то время как (1);
}

просмотреть rawgistfile1.txt, размещенный на ❤ на GitHub

Шаг 3: Настройте Детектор музыкальных нот

Подключите Arduino Uno к ПК с кодом, написанным или загруженным в Arduino IDE. Скомпилируйте и загрузите код в Arduino. Разместите схему рядом с источником музыки. Примечание. Во вводном видео я использую приложение, установленное на планшете, в сочетании с динамиками ПК в качестве источника музыки. Нажмите кнопку сброса на плате Arduino, а затем сыграйте ноту на источнике музыки. Через несколько секунд детектор музыкальных нот отобразит сыгранную ноту и ее частоту.

Рекомендуемые: