ในบทสอนนี้ เราจะมาสร้าง MIDI controller / คีย์บอร์ดแบบ Continuous กัน หลักการง่ายๆ คือใช้ Capacitive sensing ควบคู่กับการสื่อสาร MIDI และซอฟต์แวร์สังเคราะห์เสียง อยากเห็นตัวอย่างเร็วๆ ดูวิดีโอสั้นๆ ด้านล่างได้เลย หรือจะดูวิดีโออธิบายยาวๆ ครึ่งชั่วโมงเพื่อเข้าใจการทำงานแบบละเอียดก็จัดไปวัยรุ่น
วิดีโออธิบายรายละเอียดการทำงาน:
1: พื้นหลัง

การเล่นโน้ตแบบต่อเนื่อง (Continuous notes) เป็นส่วนสำคัญของดนตรี Hindustani มาก ซึ่งต้องการการแสดงออกหลายแบบ เครื่องดนตรีอย่างไวโอลิน, ซิตาร์, หรือฟลูต สามารถทำได้ ส่วนคีย์บอร์ดทั่วไปเล่นได้แค่โน้ตแบบไม่ต่อเนื่อง (discrete notes) เท่านั้น ในคีย์บอร์ดระดับสูงอาจมีล้อ Pitch bend ที่สามารถดัดเสียงได้ประมาณ 2 semitones ซึ่งก็ไม่ค่อยเป็นธรรมชาติเท่าไหร่ ในตลาดมีคีย์บอร์ดแบบพิเศษอย่าง Haken Continuum Board, ROLI seaboard ที่ทำได้ดีมาก ลองไปหาข้อมูลเพิ่มเติมจากเว็บไซต์ของเครื่องดนตรีเหล่านั้นดูได้
ด้วยแรงบันดาลใจจากเครื่องดนตรีเหล่านั้น พี่เคยลองทำคีย์บอร์ดสัมผัสแบบง่ายๆ ด้วย Arduino มาก่อน โครงการเก่าใช้แผ่นสัมผัสประมาณ 14 แผ่น (ความแม่นยำต่ำ) และสร้างเสียงด้วยไลบรารี Tone ของ Arduino ซึ่งเสียงเป็นแค่คลื่นสี่เหลี่ยม (square wave) ฟังแล้วไม่เพราะเลยน้องเอ๊ย
นี่คือบทเรียนจากโปรเจกต์เก่าที่พี่พยายามปรับปรุงในโปรเจกต์นี้:
- เสียงจากไลบรารี Tone แย่มาก ดังนั้นในโปรเจกต์นี้พี่ใช้ MIDI messages เพื่อคุณภาพเสียงที่ดีขึ้น
- ความแม่นยำในการระบุตำแหน่งต่ำ เพราะแผ่นใหญ่และมีจำนวนน้อย ที่นี่พี่เพิ่มจำนวนแผ่นสัมผัสเกือบสามเท่า และลดความกว้างของแผ่นลงครึ่งหนึ่ง
- โปรเจกต์เก่าไม่ได้ใช้ข้อมูลความกด (pressure) เพราะไลบรารี Tone ควบคุมความดังไม่ได้ การใช้ MIDI เปิดโอกาสให้ทำสิ่งเหล่านี้ได้
- Capacitive sensing ไม่ใช่วิธีที่เสถียรที่สุด มันอาจถูกกระทบจากระบบกราวด์, ความชื้นที่ไม้ดูดซับ, หรือแม้แต่รองเท้าที่เราใส่ตอนเล่น แต่วิธีอื่นๆ มันซับซ้อนและ/หรือแพงเกินไป ก็ต้องอยู่กับมันไปนะตัวนี้
2: แนวคิด



ขั้นตอนการทำงานโดยรวมเป็นแบบนี้:
Sensing (การตรวจจับ):
พี่เจอสองวิธีที่พอทำได้ วิธีแรกใช้เซ็นเซอร์ Hall effect (แบบที่ Haken Continuum ใช้) ซึ่งแม่นยำมากแต่ค่อนข้างซับซ้อน ต้องมีกลไกที่ละเอียดอ่อน แต่วิธีที่พี่พบว่าสะดวกคือการใช้ Capacitive sensing ถ้าใช้วิธีนี้เราไม่ต้องมีเซ็นเซอร์เป็นชิ้นส่วนเพิ่ม แค่ต่อแผ่นโลหะเข้ากับขา Arduino ขานั้นก็กลายเป็นเซ็นเซอร์วัดความจุไฟฟ้าแล้ว มีไลบรารีสำเร็จรูปให้ใช้ด้วย โดยสรุป วิธีนี้ตรวจสอบเวลาที่แผ่นโลหะใช้ในการชาร์จจาก 0V ถึง 5V ผ่านตัวต้านทาน (Resistor) ค่าเวลานี้แทนค่าความจุไฟฟ้า (capacitance) ข้อดีอีกอย่างคือเราวัดความกด (pressure) ได้จากข้อมูลนี้ ยิ่งกดแรง พื้นที่ผิวสัมผัสของนิ้วกับแผ่นก็ยิ่งมาก ความจุไฟฟ้าก็เพิ่มขึ้น ดังนั้นเราไม่ได้แค่รู้ว่ามีอะไรมาสัมผัส แต่ยังรู้ด้วยว่า "กดแรงแค่ไหน"
Processing the data (ประมวลผลข้อมูล):
Arduino จะอ่านและประมวลผลข้อมูล จากค่าที่ตั้งไว้ มันจะคำนวณตำแหน่งสัมผัสและค่าความกด รวมทั้งปรับค่าให้เรียบ (smoothing) MIDI messages ก็คือข้อมูลแบบอนุกรม (serial) ที่เราต้องเขียนส่งออกไป Arduino จะควบคุมสัญญาณหลักสี่แบบ สองแบบแรกคือการเปิด (Note ON) และปิด (Note OFF) โน้ต อีกสองแบบคือ pitch bend และ pressure value ซึ่งจะถูกคำนวณและส่งออกไปอย่างต่อเนื่องขณะที่โน้ตกำลังเปิดอยู่
Sound Generation (สร้างเสียง):
ข้อมูลจาก Arduino จะถูกส่งไปยัง FL studio เพื่อสร้างเสียง ซึ่งต้องใช้ซอฟต์แวร์หลายตัวมาช่วยเชื่อมต่อสัญญาณ MIDI เข้าไปใน FL studio
3: เตรียมฮาร์ดแวร์




ขั้นตอนการทำสามารถทำตามจากโปรเจกต์เก่าของพี่ได้เลย
แต่มีบางจุดที่ต้องปรับเปลี่ยนเวลาทำ ความกว้างของแผ่นลดลงเหลือ 6mm (จากเดิม 12 mm) เหตุผลคือเมื่อเราสัมผัสพื้นผิวด้วยแรงกดเบาๆ พื้นที่สัมผัสจะอยู่ที่ประมาณ 8-9mm ดังนั้นเวลาสัมผัสคีย์ใดๆ นิ้วจะแตะแผ่นอย่างน้อยสองแผ่นเสมอ
ที่นี่พี่ต้องการครอบคลุม 2 ออคเทฟ และแต่ละคีย์ประกอบด้วยแผ่นอะลูมิเนียมฟอยล์สองแผ่น รวมแล้วต้องการแผ่นทั้งหมด 48 แผ่น ห้ามช็อตนะตัวนี้
Electrical Connection (การต่อวงจร):
จากรูปด้านบน จะเห็นว่าแต่ละแผ่นต่อกับขาร่วม (common pin) ขาที่ 13 และต่อกับขาแต่ละขาผ่านตัวต้านทาน ไม่มีข้อจำกัดว่าจะต้องต่อแผ่นสัมผัสกับขาแบบไหน เพราะทั้งขาแอนะล็อกและดิจิตอลรองรับ capacitive sensing ทั้งคู่ แต่น้องต้องแก้โค้ดให้ตรงกับการต่อสายของน้องเอง
หมายเหตุ:
ตอนตัดแผ่นหรือบัดกรี ต้องมั่นใจว่าแผ่นทุกแผ่นแยกจากกันทางไฟฟ้า ไม่มีใครแตะต้องใคร
4: ซอฟต์แวร์/โค้ด Arduino
- ประกาศแผ่นทั้งหมดเป็น capacitive sensor และแมปการต่อสายให้ถูกต้องในโค้ด สำหรับพี่ ขา 13 เป็นขาร่วม
CapacitiveSensor p1 = CapacitiveSensor(13,12); CapacitiveSensor p2 = CapacitiveSensor(13,11);
CapacitiveSensor p3 = CapacitiveSensor(13,10);
.
.
.
CapacitiveSensor p48 = CapacitiveSensor(13,9);2. อ่านค่าความจุไฟฟ้าจากเซ็นเซอร์ทั้งหมดเริ่มต้น ฟังก์ชัน "raw_cap()" จะอ่านค่าและเก็บไว้ในอาร์เรย์ที่ประกาศไว้ระดับ global
void raw_cap(){
raw[1]=p1.capacitiveSensor(resolution);
raw[2]=p2.capacitiveSensor(resolution);
raw[3]=p3.capacitiveSensor(resolution);
.
.
raw[48]=p48.capacitiveSensor(resolution);
}3. เมื่อได้ข้อมูลครบแล้ว ฟังก์ชัน "data_process()" จะทำงาน ฟังก์ชันนี้ไม่เพียงแต่ประมวลผลข้อมูล แต่ยังส่ง MIDI message ไปยังคอมพิวเตอร์ด้วย ขั้นตอนเป็นดังนี้
- หาคีย์ที่มีค่าสัญญาณสูงสุด (max amplitude)
- คำนวณตำแหน่งสัมผัสที่แน่นอนโดยพิจารณาคีย์ก่อนหน้าและคีย์ถัดไปจากค่าสูงสุด (นี่คือเหตุผลที่ต้องให้นิ้วสัมผัสอย่างน้อยสองคีย์ตลอดเวลา)
- เก็บค่าตำแหน่งคีย์และค่าความกดล่าสุด 30 ค่า
- ถ้าค่าความกดเกินค่าที่กำหนดไว้ (threshold) Arduino จะส่งข้อมูลเพื่อเปิดโน้ต (Note ON)
- ขณะที่โน้ตเปิดอยู่ Arduino จะส่งค่าการดัดเสียง (pitch bend) และค่าความกด (pressure) อย่างต่อเนื่อง
- ถ้าปล่อยคีย์ (Key releases) มันจะส่งสัญญาณเพื่อปิดโน้ต (Note OFF)
โค้ดนี้ยังมีฟีเจอร์ "snap" ตำแหน่งคีย์ด้วย เช่น ถ้าน้องสัมผัสที่ตำแหน่ง 7.25 (ขวาเล็กน้อยของคีย์ 7) มันจะเล่นเฉพาะคีย์ 7 (โน้ตบริสุทธิ์) และระหว่างที่สัมผัสอยู่นั้น ค่านี้จะเป็นค่าฐานสำหรับการสไลด์ ฟีเจอร์นี้ทำให้การเล่นโน้ตบริสุทธิ์ทำได้ง่าย ถ้าไม่มีฟีเจอร์นี้ การเล่นโน้ตบริสุทธิ์จะยากมากๆ
โค้ดเต็มสามารถดาวน์โหลดได้ ถ้าน้องวางแผนจะทำของคล้ายๆ กัน น้องอาจต้องใช้เวลาปรับแต่งโค้ดและค่าต่างๆ (เช่น resolution และ touch threshold) ไม่น้อยเลย สู้งานนะน้อง
สำหรับความเข้าใจเกี่ยวกับ MIDI message น้องสามารถหาข้อมูลเพิ่มเติมได้จากแหล่งข้อมูลทั่วไป
Musical Instrument Digital Interface (MIDI)
โปรเจคนี้จะเปลี่ยนฮาร์ดแวร์อินพุตพื้นฐาน ให้กลายเป็นเครื่องดนตรีระดับโปรหรือคอนโทรลเลอร์ในสตูดิโอเลยทีเดียว
- Continuous Control (CC): เฟิร์มแวร์จะแปลงค่าจากเซนเซอร์แบบ capacitive ให้อยู่ในช่วงมาตรฐาน MIDI 7-bit (0-127) เพื่อส่งเป็นข้อความ pitch bend และ pressure (aftertouch)
- USB-MIDI Class Compliance: ด้วยการใช้บอร์ดอย่าง Arduino Pro Micro หรือ Leonardo (ATmega32U4) อุปกรณ์ของเราจะปรากฏเป็น MIDI keyboard แบบ "Plug-and-Play" ให้กับคอม Windows, Mac, หรือ Linux ทุกเครื่องเลย ไม่ต้องพึ่ง serial-to-MIDI bridge ให้วุ่นวายในบางการตั้งค่า
5: การสร้างเสียง (Sound Generation)
ต้องมีซอฟต์แวร์ 3 ตัวนี้ถึงจะได้ยินเสียงออกมานะน้อง:
1. Hairless MIDI: ตัวนี้คือสะพานเชื่อม serial ไปหา MIDI ข้อมูลอะไรที่อาร์ดุยโน่ส่งออกมาก็จะถูกจับไว้โดยซอฟต์แวร์นี้
2. LoopMIDI: ซอฟต์แวร์ตัวนี้จะมาจับข้อมูลจาก HairlessMIDI อีกที แล้วทำตัวเป็นอุปกรณ์ MIDI ให้กับ FL studio (หรือ DAW ตัวอื่นที่น้องใช้)
3. FL studio: ในตั้งค่าของ FL studio น้องอาจต้องเลือก LoopMIDI เป็นอุปกรณ์นะ โค้ดนี้โดยดีฟอลต์จะให้ค่า pitch bend อยู่ในช่วง +8 ถึง -8 semitones (ค่าเริ่มต้นในซอฟต์แวร์มักเป็น +2 ถึง -2) ตรงนี้ต้องไปตั้งค่าเองในเครื่องดนตรี (instrument) ที่เลือกด้วย นอกจากนั้นก็ต้องไป map ค่า pressure ให้ควบคุมความดัง (volume) อีกที ตั้งค่าให้ดีนะจะได้ไม่เพี้ยน
การใช้งานในสตูดิโอ (Studio Integration)
- DAW Compatibility: ใช้งานร่วมกับ DAW ตัวดังอย่าง Ableton Live, FL Studio, หรือ Logic Pro ได้ลื่นไหลมาก
- Latency Optimization: โค้ดถูกออกแบบมาให้โพลข้อมูลแบบ serial ด้วยความเร็วสูง เพื่อลด latency ให้ต่ำสุด เวลาแสดงสดจะได้ไม่กระตุก ต้องลื่นปรื๊ดๆ
6: ปัญหาที่พบบ่อย (Common Issues)
นี่คือลิสต์ปัญหาที่พี่เจอตอนทำโปรเจค รับรองว่ามีประโยชน์แน่นอน
- ปัญหาคลาสสิคของ capacitive sensing ก็คือเรื่องการกราวด์นั่นแหละ ความไวจะเพิ่มขึ้นถ้าผู้ใช้สัมผัสกราวด์ด้วยเท้าเปล่า (จัดไปวัยรุ่น) หรือถ้าเสียบแล็ปท็อปเข้ากับปลั๊กไฟ แต่ว่าการเปิดชาร์จเจอร์อาจเพิ่มสัญญาณรบกวน (noise) เข้ามาได้ ดังนั้น ถ้าน้องตั้งค่า threshold ไว้สำหรับสภาวะหนึ่ง มันอาจจะใช้ไม่ได้กับอีกสภาวะก็ได้ ต้องทดลองเยอะๆ
- การเชื่อมต่อระหว่างแผ่นอลูมิเนียมฟอยล์เป็นจุดอ่อนและหลุดง่ายมาก บางทีอุปกรณ์ทำงานแปลกๆ ก็เพราะจุดต่อนี้หลุดนี่แหละ ตรวจสอบให้ดี
- การสัมผัสโดนแผ่นโลหะ, สายไฟ หรือขา PIN โดยตรงอาจให้ข้อมูลที่ผิดเพี้ยนไปเลย และยังทำให้อัตราการสุ่มตัวอย่าง (sampling rate) ตกอีก เวลาเล่น ควรสัมผัสเฉพาะส่วนที่หุ้มด้วยพลาสติกเท่านั้น โลหะทุกจุดที่โผล่ออกมาต้องหุ้มฉนวนให้มิดชิด ป้องกันการสัมผัสโดยไม่ได้ตั้งใจ ห้ามช็อตนะตัวนี้!
- ถ้าน้องติดอลูมิเนียมฟอยล์ลงบนบล็อกไม้ด้วยกาวน้ำ (water-based adhesive) มันอาจใช้เวลาหลายชั่วโมงหรือเป็นวันถึงจะแห้งสนิท ถ้ายังเปียกชื้นอยู่ มันจะให้ผลลัพธ์ผิดเพี้ยน เพราะแผ่นฟอยล์จะเชื่อมต่อกันผ่านทางช่องน้ำนั่นเอง สู้งานนะน้อง