ภาพรวมโปรเจกต์
"Sync-Harmonizer Polyphonic Engine" เป็นโปรเจกต์เสียงระดับเทพ ที่ทำลายกำแพง "เล่นโน้ตได้ทีละตัว" ของฟังก์ชัน tone() มาตรฐานบน Arduino ให้แหลกกระจาย! โดยการคว้า ไลบรารี MusicWithoutDelay มาใช้ร่วมกับ ไลบรารี Tone ที่ขับเคลื่อนด้วยฮาร์ดแวร์ไทเมอร์ ระบบนี้ทำให้ Arduino Uno ของเราสามารถเล่นเมโลดี้สองเสียงพร้อมกันได้แบบชิลๆ มันใช้รูปแบบ RTTL (Ring Tone Transfer Language)—ที่โด่งดังจากมือถือโนเกียรุ่นเก๋า—เพื่อเก็บโน้ตเพลงซับซ้อนไว้ในหน่วยความจำ และเล่นมันออกมาได้โดย ไม่บล็อกการทำงานของโค้ดหลักแม้แต่วินาทีเดียว นี่เป็นการศึกษาที่สำคัญในเรื่อง เสียงแบบขับเคลื่อนด้วยอินเตอร์รัปต์, ลอจิกของสเตทแมชชีน และ การมอดูเลตความถี่
วิดีโอ
ดาวน์โหลดไลบรารี
โปรเจกต์นี้เป็นตัวอย่างการใช้งานไลบรารี MusicWithoutDelay ที่พี่เขียนขึ้นมา
นอกจากนี้คุณยังต้องมีไลบรารี Tone อันเลื่องชื่อของ Bhagman ด้วย
ทำไมต้องทำ?
- พี่สร้างไลบรารีนี้ขึ้นมาเพราะว่า... มันไม่มีวิธีที่จะเล่นเพลงสไตล์ 8-bit คลาสสิก ในขณะที่สเก็ตช์หลักของคุณกำลังรันอยู่ แถมการอ่านไฟล์เพลงของคนอื่นก็ยากและวุ่นวายอีกต่างหาก
- พี่อยากเล่นโน้ตมากกว่าหนึ่งตัวพร้อมกันไงล่ะ หลังจากค้นคว้ามากมาย พี่ก็ได้ความสามารถนี้มาด้วยไลบรารี Tone ของ Bhagman น่าเสียดายที่จำนวนโน้ตที่เล่นพร้อมกันได้ ขึ้นอยู่กับว่าบอร์ดของคุณมีไทเมอร์กี่ตัว (ใช้ Timer0 ไม่ได้เพราะ millis() ใช้มันอยู่) ดังนั้น Arduino Uno เล่นได้สูงสุด 2 โน้ตพร้อมกัน
เพราะไม่มีใครสร้างไลบรารีเพื่อทำให้การเล่นและอ่านเพลงง่ายขึ้น พี่เลยตัดสินใจสร้างไลบรารีของตัวเองซะเลย
มันทำงานยังไง?
มันใช้ไลบรารี MusicWithoutDelay ของพี่เพื่อแปลงเพลงให้เป็นค่าความยาวเวลา (duration) ที่อ่านง่าย แล้วส่งให้ไลบรารี Tone ของ Bhagman เล่นต่อ
ไฟล์เพลงใช้รูปแบบ RTTL (Ring Tone Transfer Language) อันโด่งดัง ที่มือถือโนเกียรุ่นเก่าใช้สำหรับริงโทน
- อยากรู้วิธีอ่านและเขียนเพลงของตัวเองมั้ย? ไปศึกษาเรื่อง RTTL ได้เลย
- RTTL เป็นภาษาที่เข้าใจง่ายมากๆ ทั้งสำหรับนักดนตรีและมือใหม่หัดเล่น
ไฟล์เพลงเหล่านี้จะถูกเก็บไว้ในตัวแปรพอยน์เตอร์แบบ char ที่คุณเขียนก่อนฟังก์ชัน setup() จากนั้นไลบรารีของพี่จะรับไฟล์เพลงมาและแปลงมันเป็นมิลลิวินาที จำสเก็ตช์ BlinkWithoutDelay ได้มั้ย? ไลบรารีของพี่ใช้เทคนิคคล้ายๆ กันนั่นแหละในการเล่นโน้ต
ลงลึกเรื่องเทคนิค
- ความท้าทายของเสียงประสาน (การจัดสรร Timer):
- ข้อจำกัดของ Hardware Timer: การสร้างพัลส์สำหรับความถี่เฉพาะเจาะจงต้องการจับเวลาที่แม่นยำ Arduino Uno (ATmega328P) มี Timer อยู่สามตัว: Timer0 (8-bit), Timer1 (16-bit), และ Timer2 (8-bit)
- การจัดการทรัพยากร: เนื่องจาก Timer0 ถูกจองไว้ให้
millis()และdelay()อยู่แล้ว ไลบรารี่Toneเลยใช้ Timer1 กับ Timer2 ในการขับขาพินเอาต์พุตสองช่องที่เป็นอิสระต่อกัน โปรเจคนี้จัดการทรัพยากรฮาร์ดแวร์สองตัวนี้เพื่อเล่นโน้ตประสานหรือไลน์เบส/เมโลดี้แยกกันได้พร้อมกัน
- ตรรกะแบบ "Blink-Without-Delay" ที่ไม่บล็อกการทำงาน:
- เครื่องเล่นเพลงทั่วไปใช้
delay()รอระหว่างโน้ต ซึ่งจะทำให้โปรเซสเซอร์หยุดนิ่ง ไลบรารี่ MusicWithoutDelay ใช้หลักการ State Machine มันจะตรวจสอบเวลาปัจจุบันเทียบกับnextNoteTimeในทุกๆ รอบของloop()ถ้าเวลาผ่านไปแล้ว มันก็จะอัปเดตความถี่ (Hz) และเลื่อนไปอ่านตัวอักษรถัดไปในสตริง RTTL - สถาปัตยกรรมแบบนี้ทำให้ระบบสามารถอ่านเซนเซอร์ อัปเดตไฟ RGB LED หรือตอบสนองต่ออินเตอร์รัปต์จากปุ่มได้ ขณะที่เพลงยังคงเล่นต่อด้วยความแม่นยำไร้การกระตุก
- เครื่องเล่นเพลงทั่วไปใช้
- การแยกวิเคราะห์ RTTL (Ring Tone Transfer Language):
- โครงสร้างโปรโตคอล: สตริง RTTL ประกอบด้วยสามส่วน: ชื่อ, การตั้งค่า (กำหนดค่าดีฟอลต์ของความยาวโน้ต
d, ระดับเสียงo, และ BPMb), และ ข้อมูลโน้ต - คณิตศาสตร์ในการแยกวิเคราะห์: ไลบรารี่จะแปลงระดับเสียง (octave) และชื่อโน้ตให้เป็นดัชนีของความถี่ ตัวอย่างเช่น โน้ต
4c(Middle C) จะถูกแปลงเป็น 261.63Hz ความยาวของโน้ตคำนวณจากสูตร: $Duration (ms) = (60000 / BPM) \times (4 / NoteValue)$
- โครงสร้างโปรโตคอล: สตริง RTTL ประกอบด้วยสามส่วน: ชื่อ, การตั้งค่า (กำหนดค่าดีฟอลต์ของความยาวโน้ต
- การตอบสนองด้วยภาพแบบ Synesthetic:
- โปรเจคนี้ผนวก RGB LED ที่ถูกโปรแกรมให้ทำงานประสานกับความถี่ที่กำลังเล่นอยู่ ด้วยการแมปช่วงความถี่ (31Hz ถึง 4978Hz) เข้ากับสเปกตรัมสี (โดยใช้ PWM) อุปกรณ์จะให้การแสดงผลทางภาพของเสียงประสาน สร้างเอฟเฟกต์ "Color-Organ" ได้อย่างมีประสิทธิภาพ
วิศวกรรมและการทำงาน
- เครื่องยนต์ "เล่นย้อนเวลา": ไม่เหมือนเครื่องเล่นเพลงแบบตายตัว ไลบรารี่ MusicWithoutDelay ช่วยให้การเล่นเป็นแบบอินเตอร์แอคทีฟได้ เพราะมันใช้พอยน์เตอร์ชี้ไปยังสตริง RTTL ระบบจึงสามารถ ย้อนเมโลดี้ ได้แบบเรียลไทม์ หรือ ข้ามไปยังส่วนเฉพาะ (เช่น ท่อน verse/chorus) ได้ด้วยการจัดการดัชนีของสตริง
- การเชื่อมต่อกับลำโพงเรโซแนนซ์: ใช้ตัวต้านทาน (Resistor) 220 โอห์มต่ออนุกรมกับลำโพง 8 โอห์มเพื่อจำกัดกระแสที่ดึงมาจากพินดิจิตอลของ Arduino (ให้อยู่ต่ำกว่า 40mA อย่างปลอดภัย) สำหรับเสียงที่ดังขึ้น ผู้พัฒนาขอแนะนำให้ใช้ LM386 audio amplifier หรือไดรเวอร์แบบ MOSFET เพื่อป้องกันความเครียดจากความร้อนบนชิป ATmega328P
- การควบคุมอินเตอร์เฟซ: ปุ่มกดสามปุ่มถูกโปรแกรมไว้สำหรับ:
- เล่น/หยุดชั่วคราว: หยุดการทำงานของอินเตอร์รัปต์จาก Timer
- เลือกเพลง: วนลูปผ่านรายการพอยน์เตอร์ RTTL ที่เก็บไว้ใน Flash memory
- โหมดย้อนกลับ: สลับตรรกะการเพิ่ม/ลดของตัวแยกวิเคราะห์
- การประยุกต์ใช้ในอุตสาหกรรม: นอกเหนือจากเพลง 8-bit แล้ว เทคนิคเสียงประสานนี้มีความสำคัญมากสำหรับ ระบบสัญญาณเตือนภัยในอุตสาหกรรม ที่จำเป็นต้องสร้างสัญญาณ "เร่งด่วน" ที่มีโทนเสียงหลายแบบที่แตกต่างกัน ขณะที่ยังคงต้องเฝ้าติดตามเซนเซอร์วัดอุณหภูมิหรือความดันเพื่อรับข้อมูลด้านความปลอดภัยที่สำคัญ
ข้อดี
- เล่นโน้ตหลายตัวพร้อมกันได้ (จัดไปวัยรุ่น!)
- รันงานอื่นๆ อย่าง Serial monitor ไปด้วยในพื้นหลังได้ (มัลติทาสกิ้งแบบไม่สะดุด)
- เล่นเพลงย้อนหลังหรือเดินหน้าได้ (Rewind/Forward แบบกดเล่น)
- หยุด/เล่นเพลงได้ตามใจ (Pause/Play)
- ข้ามไปยังท่อนเฉพาะในเพลงได้ (Skip to section)
- เลือกเพลงใหม่ได้เมื่อไหร่ก็ได้
- อีกเพียบรออยู่ข้างหน้า :D
อัพเกรดประสบการณ์เสียงในโปรเจคต์ของคุณ: ทำนองประสานเสียง พร้อมทำงานหลายอย่างแบบไม่บล็อก (non-blocking)! สู้งานนะน้อง!