สารบัญ:

เครื่องตรวจจับโน้ตดนตรี: 3 ขั้นตอน
เครื่องตรวจจับโน้ตดนตรี: 3 ขั้นตอน

วีดีโอ: เครื่องตรวจจับโน้ตดนตรี: 3 ขั้นตอน

วีดีโอ: เครื่องตรวจจับโน้ตดนตรี: 3 ขั้นตอน
วีดีโอ: อัตราจังหวะโน้ตดนตรี เรียนลัดง่ายๆ 2024, พฤศจิกายน
Anonim
Image
Image

ตะลึงพรึงเพริดเพื่อนและครอบครัวของคุณด้วยโปรเจ็กต์นี้ที่ตรวจจับโน้ตที่เล่นโดยเครื่องดนตรี โครงงานนี้จะแสดงความถี่โดยประมาณรวมถึงโน้ตดนตรีที่เล่นบนคีย์บอร์ดอิเล็กทรอนิกส์ แอพเปียโน หรือเครื่องดนตรีอื่นๆ

รายละเอียด

สำหรับโครงการนี้ เอาต์พุตแอนะล็อกจากเครื่องตรวจจับโมดูลเสียงจะถูกส่งไปยังอินพุตอนาล็อก A0 ของ Arduino Uno สัญญาณแอนะล็อกจะถูกสุ่มตัวอย่างและหาปริมาณ (ดิจิทัล) รหัสความสัมพันธ์อัตโนมัติ การถ่วงน้ำหนัก และการปรับใช้เพื่อค้นหาความถี่พื้นฐานโดยใช้ 3 ช่วงเวลาแรก จากนั้น ความถี่พื้นฐานโดยประมาณจะถูกเปรียบเทียบกับความถี่ในช่วงอ็อกเทฟ 3, 4 และ 5 เพื่อกำหนดความถี่โน้ตดนตรีที่ใกล้ที่สุด ในที่สุดโน้ตที่คาดเดาสำหรับความถี่ที่ใกล้เคียงที่สุดจะถูกพิมพ์ไปที่หน้าจอ

หมายเหตุ: คำแนะนำนี้เน้นเฉพาะวิธีการสร้างโครงการ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับรายละเอียดและเหตุผลในการออกแบบ โปรดไปที่ลิงก์นี้: ข้อมูลเพิ่มเติม

เสบียง

  • (1) Arduino Uno (หรือ Genuino Uno)
  • (1) DEVMO ไมโครโฟน เซนเซอร์ ความไวสูง โมดูลตรวจจับเสียง เข้ากันได้
  • (1) เขียงหั่นขนม Solderless
  • (1) สาย USB-A เป็น B
  • สายจัมเปอร์
  • แหล่งดนตรี (แอพเปียโน คีย์บอร์ด หรือแอพ paino พร้อมลำโพง)
  • (1) คอมพิวเตอร์หรือแล็ปท็อป

ขั้นตอนที่ 1: สร้างฮาร์ดแวร์สำหรับตัวตรวจจับโน้ตดนตรี

ตั้งค่าตัวตรวจจับโน้ตดนตรี
ตั้งค่าตัวตรวจจับโน้ตดนตรี

การใช้ Arduino Uno, สายเชื่อมต่อ, เขียงหั่นขนมแบบไม่มีบัดกรี และ DEVMO Microphone Sensor โมดูลตรวจจับเสียงความไวสูง (หรือที่คล้ายกัน) สร้างวงจรที่แสดงในภาพนี้

ขั้นตอนที่ 2: ตั้งโปรแกรมตัวตรวจจับโน้ตดนตรี

ใน Arduino IDE ให้เพิ่มโค้ดต่อไปนี้

gistfile1.txt

/*
ชื่อไฟล์/ร่าง: MusicalNoteDetector
หมายเลขเวอร์ชัน: v1.0 สร้างเมื่อ 7 มิถุนายน 2020
ผู้เขียนต้นฉบับ: Clyde A. Lettsome, PhD, PE, MEM
คำอธิบาย: รหัส/ร่างนี้แสดงความถี่โดยประมาณรวมถึงโน้ตดนตรีที่เล่นบนคีย์บอร์ดอิเล็กทรอนิกส์หรือแอปเปียโน สำหรับโปรเจ็กต์นี้ เอาต์พุตแอนะล็อกจาก
เครื่องตรวจจับโมดูลเสียงจะถูกส่งไปยังอินพุตอนาล็อก A0 ของ Arduino Uno สัญญาณแอนะล็อกจะถูกสุ่มตัวอย่างและหาปริมาณ (ดิจิทัล) ใช้รหัส Autocorrelation, weighting และ tuning เพื่อ
หาความถี่พื้นฐานโดยใช้ 3 ช่วงเวลาแรก จากนั้น ความถี่พื้นฐานโดยประมาณจะถูกเปรียบเทียบกับความถี่ในช่วงอ็อกเทฟ 3, 4 และ 5 เพื่อกำหนดดนตรีที่ใกล้เคียงที่สุด
บันทึกความถี่ ในที่สุดโน้ตที่คาดเดาสำหรับความถี่ที่ใกล้เคียงที่สุดจะถูกพิมพ์ไปที่หน้าจอ
ใบอนุญาต: โปรแกรมนี้เป็นซอฟต์แวร์ฟรี คุณสามารถแจกจ่ายซ้ำและ/หรือแก้ไขได้ภายใต้เงื่อนไขของ GNU General Public License (GPL) เวอร์ชัน 3 หรือเวอร์ชันที่ใหม่กว่า
เวอร์ชันที่คุณเลือกตามที่เผยแพร่โดย Free Software Foundation
หมายเหตุ: ลิขสิทธิ์ (c) 2020 โดย C. A. Lettsome Services, LLC
สำหรับข้อมูลเพิ่มเติม โปรดไปที่
*/
#define SAMPLES 128 // สูงสุด 128 สำหรับ Arduino Uno
#define SAMPLING_FREQUENCY 2048 //Fs = ขึ้นอยู่กับ Nyquist ต้องเป็น 2 เท่าของความถี่ที่คาดไว้สูงสุด
#define OFFSETSAMPLES 40 // ใช้เพื่อวัตถุประสงค์ในการสอบเทียบ
#define TUNER -3 //ปรับจนกระทั่ง C3 เป็น 130.50
การสุ่มตัวอย่างลอยตัวระยะเวลา;
microSeconds แบบยาวที่ไม่ได้ลงนาม
int X[ตัวอย่าง]; //สร้างเวกเตอร์ขนาด SAMPLES เพื่อเก็บค่าจริง
float autoCorr[ตัวอย่าง]; //สร้างเวกเตอร์ขนาด SAMPLES เพื่อเก็บค่าจินตภาพ
float ที่เก็บไว้NoteFreq[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]; //สร้าง offset vector
int avgOffSet; //สร้าง offset vector
int i, k, periodEnd, periodBegin, period, adjuster, noteLocation, octaveRange;
ลอย maxValue, minValue;
ผลรวมยาว;
int นวดข้าว = 0;
int numOfCycles = 0;
สัญญาณลอยความถี่, สัญญาณความถี่2, สัญญาณความถี่3, สัญญาณความถี่Guess, รวม;
ไบต์ state_machine = 0;
ตัวอย่าง int ช่วงเวลา = 0;
การตั้งค่าเป็นโมฆะ ()
{
Serial.begin(115200); //115200 อัตราบอดสำหรับ Serial Monitor
}
วงเป็นโมฆะ ()
{
//*****************************************************************
//ส่วนสอบเทียบ
//*****************************************************************
Serial.println("กำลังสอบเทียบ กรุณาอย่าเล่นโน้ตใดๆ ในระหว่างการสอบเทียบ");
สำหรับ (i = 0; i < OFFSETSAMPLES; i++)
{
offSet = analogRead(0); // อ่านค่าจากพินอะนาล็อก 0 (A0) หาปริมาณและบันทึกเป็นเทอมจริง
//Serial.println(ออฟเซ็ต); // ใช้สิ่งนี้เพื่อปรับโมดูลการตรวจจับเสียงเป็นประมาณครึ่งหนึ่งหรือ 512 เมื่อไม่มีเสียงเล่น
sumOffSet = sumOffSet + offSet;
}
ตัวอย่างPerPeriod = 0;
ค่าสูงสุด = 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 วินาทีสำหรับเวลาตอบสนอง
//*****************************************************************
// รวบรวมตัวอย่าง SAMPLES จาก A0 พร้อมช่วงตัวอย่างของแซมปลิ้ง
//*****************************************************************
ช่วงสุ่มตัวอย่าง = 1.0 / SAMPLING_FREQUENCY; //ระยะเวลาในหน่วยไมโครวินาที
สำหรับ (i = 0; i < ตัวอย่าง; i++)
{
ไมโครวินาที = ไมโคร (); //ส่งคืนจำนวนไมโครวินาทีตั้งแต่บอร์ด Arduino เริ่มรันสคริปต์ปัจจุบัน
X = analogRead(0); // อ่านค่าจากพินอะนาล็อก 0 (A0) หาปริมาณและบันทึกเป็นเทอมจริง
/*เวลารอที่เหลือระหว่างตัวอย่างถ้าจำเป็นเป็นวินาที */
ในขณะที่ (micros() < (microSeconds + (samplingPeriod * 1000000)))
{
//ไม่ต้องทำอะไรรอก่อน
}
}
//*****************************************************************
//ฟังก์ชันสหสัมพันธ์อัตโนมัติ
//*****************************************************************
สำหรับ (i = 0; i < ตัวอย่าง; i++) //i=delay
{
ผลรวม = 0;
สำหรับ (k = 0; k < SAMPLES - i; k++) // จับคู่สัญญาณกับสัญญาณล่าช้า
{
ผลรวม = ผลรวม + (((X[k]) - avgOffSet) * ((X[k + i]) - avgOffSet)); //X[k] คือสัญญาณ และ X[k+i] คือเวอร์ชันที่ล่าช้า
}
autoCorr = ผลรวม / ตัวอย่าง;
// เครื่องตรวจสถานะ Peak Detect ครั้งแรก
ถ้า (state_machine==0 && i == 0)
{
thresh = 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;
ตัวอย่างPerPeriod = (periodBegin - 0);
ระยะเวลา = ตัวอย่างระยะเวลา;
ตัวปรับ = TUNER+(50.04 * exp(-0.102 * ตัวอย่างPerPeriod));
signalFrequency = ((SAMPLING_FREQUENCY) / (samplesPeriod)) - ตัวปรับ; // 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;
samplePerPeriod = (periodEnd - 0);
signalFrequency2 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplesPerPeriod)) - ตัวปรับ; // f = (2*fs)/(2*N)
ค่าสูงสุด = 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;
samplePerPeriod = (periodEnd - 0);
signalFrequency3 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplesPerPeriod)) - ตัวปรับ; // f = (3*fs)/(3*N)
}
}
//*****************************************************************
//การวิเคราะห์ผลลัพธ์
//*****************************************************************
ถ้า (samplesPerPeriod == 0)
{
Serial.println("อืม….. ฉันไม่แน่ใจ คุณกำลังพยายามหลอกฉันอยู่หรือเปล่า?");
}
อื่น
{
//เตรียมฟังก์ชั่นการถ่วงน้ำหนัก
รวม = 0;
ถ้า (สัญญาณความถี่ !=0)
{
รวม = 1;
}
ถ้า(สัญญาณความถี่2 !=0)
{
รวม = รวม + 2;
}
ถ้า (สัญญาณความถี่3 !=0)
{
รวม = รวม + 3;
}
//คำนวณความถี่โดยใช้ฟังก์ชันการถ่วงน้ำหนัก
signalFrequencyGuess = ((1/ทั้งหมด) * signalFrequency) + ((2/รวม) * signalFrequency2) + ((3/ทั้งหมด) * signalFrequency3); // ค้นหาความถี่ถ่วงน้ำหนัก
Serial.print("โน้ตที่คุณเล่นอยู่ประมาณ ");
Serial.print(สัญญาณความถี่Guess); //พิมพ์ความถี่เดา
Serial.println("Hz.");
// ค้นหาช่วงอ็อกเทฟตามการเดา
อ็อกเทฟเรนจ์=3;
ในขณะที่ (!(signalFrequencyGuess >= เก็บไว้NoteFreq[0]-7 && signalFrequencyGuess <= เก็บไว้NoteFreq[11]+7))
{
สำหรับ(i = 0; i < 12; i++)
{
storeNoteFreq = 2 * ที่เก็บไว้NoteFreq;
}
อ็อกเทฟเรนจ์++;
}
// ค้นหาโน้ตที่ใกล้ที่สุด
ค่าต่ำสุด = 10000000;
noteLocation = 0;
สำหรับ (i = 0; i < 12; i++)
{
if(minValue> abs(signalFrequencyGuess-storedNoteFreq))
{
minValue = เอบีเอส (signalFrequencyGuess-storedNoteFreq);
noteLocation = ผม;
}
}
//พิมพ์โน้ต
Serial.print("ฉันคิดว่าคุณเล่น");
ถ้า(noteLocation==0)
{
Serial.print ("C");
}
อื่น if(noteLocation==1)
{
Serial.print("C#");
}
อื่น if(noteLocation==2)
{
Serial.print ("D");
}
อื่น ๆ ถ้า (noteLocation==3)
{
Serial.print("D#");
}
อื่น ๆ ถ้า (noteLocation==4)
{
Serial.print("E");
}
อื่น ๆ ถ้า (noteLocation==5)
{
Serial.print ("F");
}
อื่น if(noteLocation==6)
{
Serial.print("F#");
}
อื่น ๆ ถ้า (noteLocation==7)
{
Serial.print ("G");
}
อื่น ๆ ถ้า (noteLocation==8)
{
Serial.print("G#");
}
อื่น if(noteLocation==9)
{
Serial.print ("A");
}
อื่น if(noteLocation==10)
{
Serial.print("A#");
}
อื่น if(noteLocation==11)
{
Serial.print ("B");
}
Serial.println (ช่วงแปดเสียง);
}
//*****************************************************************
//หยุดตรงนี้. กดปุ่มรีเซ็ตบน Arduino เพื่อรีสตาร์ท
//*****************************************************************
ในขณะที่ (1);
}

ดู rawgistfile1.txt ที่โฮสต์ด้วย ❤ โดย GitHub

ขั้นตอนที่ 3: ตั้งค่าตัวตรวจจับโน้ตดนตรี

เชื่อมต่อ Arduino Uno กับพีซีด้วยรหัสที่เขียนหรือโหลดใน Arduino IDE รวบรวมและอัปโหลดรหัสไปยัง Arduino วางวงจรไว้ใกล้กับแหล่งดนตรี หมายเหตุ: ในวิดีโอแนะนำ ฉันใช้แอพที่ติดตั้งบนแท็บเล็ตร่วมกับลำโพง PC เป็นแหล่งเพลงของฉัน กดปุ่มรีเซ็ตบนบอร์ด Arduino แล้วเล่นโน้ตบนแหล่งเพลง หลังจากนั้นไม่กี่วินาที Musical Note Detector จะแสดงโน้ตที่เล่นและความถี่

แนะนำ: