كاشف النوتة الموسيقية: 3 خطوات
كاشف النوتة الموسيقية: 3 خطوات
Anonim
Image
Image

أدهش أصدقائك وعائلتك بهذا المشروع الذي يكتشف النوتة الموسيقية التي تعزف بواسطة آلة موسيقية. سيعرض هذا المشروع التردد التقريبي بالإضافة إلى النوتة الموسيقية التي يتم تشغيلها على لوحة مفاتيح إلكترونية أو تطبيق بيانو أو أي أداة أخرى.

تفاصيل

بالنسبة لهذا المشروع ، يتم إرسال الإخراج التناظري من كاشف وحدة الصوت إلى الإدخال التناظري A0 في Arduino Uno. يتم أخذ عينات من الإشارة التناظرية وتحديدها (رقمنة). يتم استخدام رمز الارتباط التلقائي والوزن والضبط للعثور على التردد الأساسي باستخدام الفترات الثلاث الأولى. ثم تتم مقارنة التردد الأساسي التقريبي بالترددات في نطاق الأوكتافات 3 و 4 و 5 لتحديد أقرب تردد نوتة موسيقية. أخيرًا ، تتم طباعة الملاحظة التخمينية الخاصة بأقرب تردد على الشاشة.

ملاحظة: يركز هذا التوجيه فقط على كيفية إنشاء المشروع. لمزيد من المعلومات حول التفاصيل ومبررات التصميم ، يرجى زيارة هذا الرابط: مزيد من المعلومات

اللوازم

  • (1) Arduino Uno (أو Genuino Uno)
  • (1) جهاز استشعار ميكروفون DEVMO عالي الحساسية متوافق مع وحدة الكشف عن الصوت
  • (1) لوح توصيل غير ملحوم
  • (1) كابل USB-A إلى B
  • أسلاك العبور
  • مصدر موسيقي (بيانو أو لوحة مفاتيح أو تطبيق مؤلم مع مكبرات صوت)
  • (1) كمبيوتر أو كمبيوتر محمول

الخطوة 1: قم ببناء جهاز كاشف النوتة الموسيقية

قم بإعداد كاشف النوتة الموسيقية
قم بإعداد كاشف النوتة الموسيقية

باستخدام Arduino Uno ، وأسلاك التوصيل ، ولوح التجارب غير الملحوم ، ووحدة الكشف عن الصوت عالية الحساسية لمستشعر الميكروفون DEVMO (أو ما شابه) ، قم ببناء الدائرة الموضحة في هذه الصورة

الخطوة 2: برمجة كاشف النوتة الموسيقية

في Arduino IDE ، أضف الكود التالي.

gistfile1.txt

/*
اسم الملف / الرسم: MusicalNoteDetector
رقم الإصدار: v1.0 تم إنشاؤه في 7 يونيو 2020
المؤلف الأصلي: كلايد أ. Lettsome ، دكتوراه ، PE ، MEM
الوصف: يعرض هذا الرمز / الرسم التخطيطي التردد التقريبي بالإضافة إلى النوتة الموسيقية التي يتم تشغيلها على لوحة مفاتيح إلكترونية أو تطبيق بيانو. بالنسبة لهذا المشروع ، فإن الإخراج التناظري من ملف
يتم إرسال كاشف وحدة الصوت إلى الإدخال التناظري A0 في Arduino Uno. يتم أخذ عينات من الإشارة التناظرية وتحديدها (رقمنة). يتم استخدام رمز الارتباط التلقائي والوزن والضبط لـ
أوجد التردد الأساسي باستخدام أول 3 فترات. ثم تتم مقارنة التردد الأساسي التقريبي بالترددات في نطاق الأوكتاف 3 و 4 و 5 لتحديد أقرب موسيقى
تردد الملاحظة. أخيرًا ، تتم طباعة الملاحظة التخمينية الخاصة بأقرب تردد على الشاشة.
الترخيص: هذا البرنامج مجاني ؛ يمكنك إعادة توزيعه و / أو تعديله بموجب شروط رخصة جنو العمومية (GPL) الإصدار 3 ، أو أي إصدار لاحق.
نسخة من اختيارك ، كما نشرتها مؤسسة البرمجيات الحرة.
ملاحظات: حقوق الطبع والنشر (c) لعام 2020 لشركة C. A. Lettsome Services، LLC
لمزيد من المعلومات ، قم بزيارة
*/
#define SAMPLES 128 // Max 128 for Arduino Uno.
#define SAMPLING_FREQUENCY 2048 // Fs = استنادًا إلى Nyquist ، يجب أن يكون أعلى تردد متوقع مرتين.
#define OFFSETSAMPLES 40 // المستخدمة لأغراض المسيرة
#define TUNER -3 // اضبط حتى يصبح C3 130.50
أخذ العينات الطافية
ميكرو ثانية طويلة بدون توقيع ؛
int X [عينات] ؛ // إنشاء متجه من عينات الحجم للاحتفاظ بالقيم الحقيقية
تعويم autoCorr [عينات] ؛ // إنشاء متجه من عينات الحجم للاحتفاظ بالقيم التخيلية
float storeNoteFreq [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، period، Adjuster، noteLocation، octaveRange؛
تعويم maxValue ، minValue ؛
مبلغ طويل
عتبة int = 0 ؛
عدد int numOfCycles = 0 ؛
إشارة تعويم التردد ، تردد الإشارة 2 ، تردد الإشارة 3 ، تردد الإشارة ، المجموع ؛
البايت state_machine = 0 ؛
عينات عدد صحيح PerPeriod = 0 ؛
الإعداد باطل()
{
Serial.begin (115200) ؛ // 115200 معدل الباود للمراقب التسلسلي
}
حلقة فارغة()
{
//*****************************************************************
// قسم المعايرة
//*****************************************************************
Serial.println ("Calabrating. من فضلك لا تلعب أي نوتات أثناء calabration.") ؛
لـ (i = 0 ؛ i <OFFSETSAMPLES ؛ i ++)
{
offSet = analogRead (0) ، // يقرأ القيمة من الرقم التناظري 0 (A0) ، قم بتثبيته وحفظه كمصطلح حقيقي.
//Serial.println(offSet) ؛ // استخدم هذا لضبط وحدة الكشف عن الصوت إلى النصف تقريبًا أو 512 عند عدم تشغيل أي صوت.
sumOffSet = sumOffSet + offSet ،
}
العيناتPerPeriod = 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 ثانية لوقت رد الفعل
//*****************************************************************
// جمع عينات عينات من A0 مع فترة عينة من فترة أخذ العينات
//*****************************************************************
samplingPeriod = 1.0 / SAMPLING_FREQUENCY ؛ // الفترة بالميكرو ثانية
لـ (i = 0 ؛ i <SAMPLES ؛ i ++)
{
ميكرو ثانية = ميكرو () ، // يعرض عدد الميكروثانية منذ أن بدأت لوحة Arduino في تشغيل البرنامج النصي الحالي.
X = analogRead (0) ، // يقرأ القيمة من الرقم التناظري 0 (A0) ، قم بتثبيته وحفظه كمصطلح حقيقي.
/ * وقت الانتظار المتبقي بين العينات إذا لزم الأمر بالثواني * /
بينما (ميكرو () <(ميكرو ثانية + (فترة أخذ العينات * 1000000)))
{
// لا تفعل شيئًا فقط انتظر
}
}
//*****************************************************************
// وظيفة الارتباط التلقائي
//*****************************************************************
لـ (i = 0 ؛ i <SAMPLES ؛ i ++) // i = تأخير
{
المجموع = 0 ؛
لـ (k = 0 ؛ k <SAMPLES - i ؛ k ++) // تطابق الإشارة مع الإشارة المتأخرة
{
sum = sum + (((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)) ؛ // X [k] هي الإشارة و X [k + i] هي النسخة المتأخرة
}
autoCorr = sum / SAMPLES ؛
// أول آلة كشف الذروة
إذا (state_machine == 0 && i == 0)
{
عتبة = autoCorr * 0.5 ؛
آلة_الولاية = 1 ؛
}
وإلا إذا (state_machine == 1 && i> 0 && thresh 0) // state_machine = 1 ، فابحث عن فترة واحدة لاستخدام الدورة الأولى
{
maxValue = autoCorr ،
}
else 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 ؛
عدد الدورات = 1 ؛
samplePerPeriod = (periodBegin - 0) ؛
فترة = عيناتPerPeriod ؛
الضابط = TUNER + (50.04 * exp (-0.102 * samplePerPeriod)) ؛
تردد الإشارة = ((SAMPLING_FREQUENCY) / (samplePerPeriod)) - الضابط ؛ // f = fs / N
}
وإلا إذا (state_machine == 2 && i> 0 && thresh 0) // state_machine = 2 ، فابحث عن فترتين للدورة الأولى والثانية
{
maxValue = autoCorr ،
}
else 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 ؛
عدد الدورات = 2 ؛
samplePerPeriod = (periodEnd - 0) ؛
signalFrequency2 = ((عدد الدورات * SAMPLING_FREQUENCY) / (samplePerPeriod)) - الضابط ؛ // f = (2 * fs) / (2 * N)
maxValue = 0 ؛
}
وإلا إذا (state_machine == 3 && i> 0 && thresh 0) // state_machine = 3 ، فابحث عن 3 فترات للدورة الأولى والثانية والثالثة
{
maxValue = autoCorr ،
}
else if (state_machine == 3 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodEnd = i-1 ؛
آلة_الولاية = 4 ؛
عدد الدورات = 3 ؛
samplePerPeriod = (periodEnd - 0) ؛
signalFrequency3 = ((عدد الدورات * SAMPLING_FREQUENCY) / (samplePerPeriod)) - الضابط ؛ // f = (3 * fs) / (3 * N)
}
}
//*****************************************************************
// تحليل النتيجة
//*****************************************************************
إذا (عينات في الفترة == 0)
{
Serial.println ("هم…. لست متأكدًا. هل تحاول خداعي؟") ؛
}
آخر
{
// تحضير وظيفة الترجيح
المجموع = 0 ؛
إذا (تردد الإشارة! = 0)
{
المجموع = 1 ؛
}
إذا (signalFrequency2! = 0)
{
المجموع = المجموع + 2 ؛
}
إذا (signalFrequency3! = 0)
{
المجموع = المجموع + 3 ؛
}
// احسب التردد باستخدام دالة الترجيح
signalFrequencyGuess = ((1 / total) * signalFrequency) + ((2 / total) * signalFrequency2) + ((3 / total) * signalFrequency3) ؛ // ابحث عن تردد مرجح
Serial.print ("الملاحظة التي قمت بتشغيلها تقريبًا") ؛
Serial.print (signalFrequencyGuess) ؛ // طباعة تخمين التردد.
Serial.println ("هرتز.") ؛
// ابحث عن نطاق الأوكتاف بناءً على التخمين
octaveRange = 3 ؛
while (! (signalFrequencyGuess> = storeNoteFreq [0] -7 && signalFrequencyGuess <= storeNoteFreq [11] +7))
{
لـ (i = 0 ؛ i <12 ؛ i ++)
{
storeNoteFreq = 2 * storeNoteFreq ؛
}
octaveRange ++ ؛
}
// ابحث عن أقرب ملاحظة
minValue = 10000000 ؛
noteLocation = 0 ؛
لـ (i = 0 ؛ i <12 ؛ i ++)
{
إذا (minValue> abs (signalFrequencyGuess-storageNoteFreq ))
{
minValue = abs (signalFrequencyGuess-storeNoteFreq ) ،
noteLocation = أنا ؛
}
}
// اطبع الملاحظة
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 ثم قم بتشغيل ملاحظة على مصدر الموسيقى. بعد بضع ثوانٍ ، سيعرض كاشف النوتة الموسيقية النوتة الموسيقية وترددها.