Съдържание:

Детектор на музикални ноти: 3 стъпки
Детектор на музикални ноти: 3 стъпки

Видео: Детектор на музикални ноти: 3 стъпки

Видео: Детектор на музикални ноти: 3 стъпки
Видео: Теория на музиката за китаристи III - записване на нотите 2024, Ноември
Anonim
Image
Image

Удивете приятелите и семейството си с този проект, който открива нотата, свирена от инструмент. Този проект ще показва приблизителната честота, както и музикалната нота, свирена на електронна клавиатура, приложение за пиано или друг инструмент.

Подробности

За този проект аналоговият изход от детектора на звуков модул се изпраща към аналоговия вход A0 на Arduino Uno. Аналоговият сигнал се избира и квантува (дигитализира). Кодът за автокорелация, претегляне и настройка се използва за намиране на основна честота, използвайки първите 3 периода. След това приблизителната основна честота се сравнява с честотите в октави 3, 4 и 5, за да се определи най -близката честота на музикалната нота. Накрая познатата бележка за най -близката честота се отпечатва на екрана.

Забележка: Тази инструкция се фокусира само върху това как да изградите проекта. За повече информация относно детайлите и обосновките на дизайна, моля, посетете тази връзка: Повече информация

Консумативи

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

Стъпка 1: Конструирайте хардуера за детектора на музикални ноти

Настройте детектора за музикални ноти
Настройте детектора за музикални ноти

С помощта на Arduino Uno, свързващите проводници, макет без запояване и DEVMO сензор за микрофон с висока чувствителност за откриване на звук (или подобен) изграждат веригата, показана на това изображение

Стъпка 2: Програмирайте детектора за музикални ноти

В IDE на Arduino добавете следния код.

gistfile1.txt

/*
Име на файл/скица: MusicalNoteDetector
Версия №: v1.0 Създадено на 7 юни 2020 г.
Оригинален автор: Clyde A. Lettsome, PhD, PE, MEM
Описание: Този код/скица показва приблизителната честота, както и музикалната нота, свирена на електронна клавиатура или приложение за пиано. За този проект аналоговият изход от
детектор на звуков модул се изпраща към аналоговия вход A0 на Arduino Uno. Аналоговият сигнал се избира и квантува (дигитализира). Кодът за автокорелация, претегляне и настройка е използван за
намерете основна честота, като използвате първите 3 периода. Приблизителната основна честота се сравнява с честотите в октави 3, 4 и 5, за да се определи най -близкият мюзикъл
бележка честота. Накрая познатата бележка за най -близката честота се отпечатва на екрана.
Лиценз: Тази програма е безплатен софтуер; можете да го разпространявате и/или да го променяте съгласно условията на GNU General Public License (GPL) версия 3 или по -късно
версия по ваш избор, публикувана от Фондацията за свободен софтуер.
Бележки: Авторско право (c) 2020 от C. A. Lettsome Services, LLC
За повече информация посетете
*/
#define SAMPLES 128 // Max 128 за Arduino Uno.
#define SAMPLING_FREQUENCY 2048 // Fs = Въз основа на Nyquist, трябва да бъде 2 пъти най -високата очаквана честота.
#define OFFSETSAMPLES 40 // използвани за калабриране
#define TUNER -3 // Регулирайте, докато C3 е 130.50
период на вземане на проби от флоат;
неподписани дълги микросекунди;
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 [OFFSETSAMPLES]; // създаване на офсетов вектор
int avgOffSet; // създаване на офсетов вектор
int i, k, periodEnd, periodBegin, период, регулатор, noteLocation, октаваRange;
float maxValue, minValue;
дълга сума;
int thresh = 0;
int numOfCycles = 0;
плаващ сигналFrequency, signalFrequency2, signalFrequency3, signalFrequencyGuess, общо;
байт state_machine = 0;
int samplePerPeriod = 0;
void setup ()
{
Serial.begin (115200); // 115200 Скорост на предаване за сериен монитор
}
void loop ()
{
//*****************************************************************
// Раздел за калибриране
//*****************************************************************
Serial.println ("Калабриране. Моля, не пускайте никакви ноти по време на калибриране.");
за (i = 0; i <OFFSETSAMPLES; i ++)
{
offSet = analogRead (0); // Чете стойността от аналогов извод 0 (A0), квантува я и я записва като реален термин.
//Serial.println(offSet); // използвайте това, за да настроите модула за откриване на звук до приблизително наполовина или 512, когато не се възпроизвежда звук.
sumOffSet = sumOffSet + offSet ;
}
samplePerPeriod = 0;
maxValue = 0;
//*****************************************************************
// Подгответе се да приемете вход от A0
//*****************************************************************
avgOffSet = кръг (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 секунда за време на реакция
//*****************************************************************
// Събиране на проби от проби от A0 с период на извадка от период на вземане на проби
//*****************************************************************
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; // Период в микросекунди
за (i = 0; i <ПРИБОРИ; i ++)
{
microSeconds = micros (); // Връща броя микросекунди, откакто дъската на Arduino започна да изпълнява текущия скрипт.
X = analogRead (0); // Чете стойността от аналогов извод 0 (A0), квантува я и я записва като реален термин.
/ *оставащо време на изчакване между пробите, ако е необходимо, в секунди */
while (micros () <(microSeconds + (samplingPeriod * 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 = сума / ПРОБИ;
// Първа машина за откриване на върхови състояния
if (state_machine == 0 && i == 0)
{
thresh = autoCorr * 0,5;
състояние_машина = 1;
}
иначе ако (state_machine == 1 && i> 0 && thresh 0) // state_machine = 1, намерете 1 период за използване на първия цикъл
{
maxValue = autoCorr ;
}
иначе ако (state_machine == 1 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodBegin = i-1;
състояние_машина = 2;
numOfCycles = 1;
samplePerPeriod = (periodBegin - 0);
период = пробиPerPeriod;
регулатор = TUNER+(50.04 * exp (-0.102 * samplePerPeriod));
signalFrequency = ((SAMPLING_FREQUENCY) / (samplePerPeriod))-регулатор; // f = fs/N
}
иначе ако (state_machine == 2 && i> 0 && thresh 0) // state_machine = 2, намерете 2 периода за 1 -ви и 2 -ри цикъл
{
maxValue = autoCorr ;
}
иначе ако (state_machine == 2 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodEnd = i-1;
състояние_машина = 3;
numOfCycles = 2;
samplePerPeriod = (periodEnd - 0);
signalFrequency2 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-регулатор; // 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 ;
}
иначе ако (state_machine == 3 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodEnd = i-1;
състояние_машина = 4;
numOfCycles = 3;
samplePerPeriod = (periodEnd - 0);
signalFrequency3 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-регулатор; // f = (3*fs)/(3*N)
}
}
//*****************************************************************
// Анализ на резултатите
//*****************************************************************
if (samplePerPeriod == 0)
{
Serial.println ("Хм ….. не съм сигурен. Опитваш ли се да ме измамиш?");
}
иначе
{
// подготвяме функцията за претегляне
общо = 0;
if (signalFrequency! = 0)
{
общо = 1;
}
if (signalFrequency2! = 0)
{
общо = общо + 2;
}
if (signalFrequency3! = 0)
{
общо = общо + 3;
}
// изчисляваме честотата с помощта на функцията за претегляне
signalFrequencyGuess = ((1/общо) * signalFrequency) + ((2/общо) * signalFrequency2) + ((3/общо) * signalFrequency3); // намиране на претеглена честота
Serial.print ("Нотата, която сте пуснали е приблизително");
Serial.print (signalFrequencyGuess); // Отпечатайте предположението за честотата.
Serial.println ("Hz.");
// намиране на октавен диапазон въз основа на предположението
octaveRange = 3;
while (! (signalFrequencyGuess> = storedNoteFreq [0] -7 && signalFrequencyGuess <= storedNoteFreq [11] +7))
{
за (i = 0; i <12; i ++)
{
storedNoteFreq = 2 * storedNoteFreq ;
}
octaveRange ++;
}
// Намерете най -близката бележка
minValue = 10000000;
noteLocation = 0;
за (i = 0; i <12; i ++)
{
if (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 ("A");
}
иначе ако (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 и след това пуснете бележка от източника на музика. След няколко секунди детекторът за музикални ноти ще покаже изсвирената нота и нейната честота.

Препоръчано: