วิธีที่เราทำให้เพลงร็อก
เกริ่นนำ
JAM with Chrome เป็นโครงการเพลงบนเว็บที่ Google สร้างขึ้น JAM ใน Chrome ช่วยให้ผู้คนจากทั่วทุกมุมโลกตั้งวงดนตรีและร่วมวงกันได้แบบเรียลไทม์ภายในเบราว์เซอร์ พวกเราที่ DinahMoe รู้สึกยินดีอย่างยิ่งที่ได้เป็นส่วนหนึ่งของโครงการนี้ บทบาทของเราคือการผลิตเพลงสำหรับแอปพลิเคชัน แล้วออกแบบและพัฒนาองค์ประกอบเพลง การพัฒนานี้ประกอบด้วย 3 ส่วนหลัก ได้แก่ "เวิร์กสเตชันเพลง" ประกอบด้วยการเล่นเพลง MIDI, ซอฟต์แวร์ตัวอย่าง, เอฟเฟกต์เสียง, การกำหนดเส้นทางและการมิกซ์ ตลอดจนเครื่องมือตรรกะของดนตรีที่ควบคุมเพลงด้วยการโต้ตอบแบบเรียลไทม์ และคอมโพเนนต์การซิงค์ที่ดูแลให้ผู้เล่นทุกคนในเซสชันได้ยินเพลงในเวลาเดียวกันซึ่งเป็นข้อกำหนดเบื้องต้นสำหรับการเล่นร่วมกัน
เราเลือกใช้ Web Audio API เพื่อให้ได้ความถูกต้อง ความถูกต้อง และคุณภาพเสียงในระดับสูงสุด กรณีศึกษานี้จะพูดถึงความท้าทายบางส่วนที่เราถูกนำเสนอและวิธีที่เราแก้ปัญหาเหล่านั้น มีบทความแนะนำดีๆ จำนวนหนึ่งที่ HTML5Rocks เพื่อให้คุณได้เริ่มต้นใช้งาน Web Audio ดังนั้นเราจะข้ามไปที่ส่วนปลายสุดของสระว่ายน้ำ
การเขียนเอฟเฟกต์เสียงที่กำหนดเอง
Web Audio API มีเอฟเฟกต์ที่เป็นประโยชน์มากมายรวมอยู่ในข้อกำหนดดังกล่าว แต่เราต้องการเอฟเฟกต์ที่ซับซ้อนยิ่งขึ้นสำหรับเครื่องดนตรีใน JAM ที่มี Chrome ตัวอย่างเช่น จะมีโหนดการหน่วงเวลาดั้งเดิมใน Web Audio แต่การหน่วงเวลามีหลายประเภท ได้แก่ การหน่วงเวลาสเตอริโอ, การหน่วงเวลาเสียงปิงปอง, การเลื่อนเวลาสับเปลี่ยน และรายการจะดำเนินต่อไป โชคดีที่เครื่องมือทั้งหมดนี้สามารถสร้างใน Web Audio โดยใช้โหนดเอฟเฟกต์แบบดั้งเดิมและจินตนาการบางอย่าง
เนื่องจากเราต้องการใช้โหนดเนทีฟและเอฟเฟกต์ที่กำหนดเองของเราในแบบที่โปร่งใสที่สุดเท่าที่จะเป็นไปได้ เราจึงตัดสินใจว่าจะสร้างรูปแบบ Wrapper ที่จะบรรลุเป้าหมายนี้ โหนดดั้งเดิมใน Web Audio ใช้วิธีการเชื่อมต่อของตนเองเพื่อลิงก์โหนดเข้าด้วยกัน เราจึงต้องจำลองลักษณะการทำงานนี้ นี่คือลักษณะของแนวคิดเบื้องต้น:
var MyCustomNode = function(){
this.input = audioContext.createGain();
var output = audioContext.createGain();
this.connect = function(target){
output.connect(target);
};
};
รูปแบบนี้ทำให้เราเข้าใกล้โหนดเนทีฟเป็นอย่างมาก มาดูกันว่าจะนำสิ่งนี้ไปใช้อย่างไร
//create a couple of native nodes and our custom node
var gain = audioContext.createGain(),
customNode = new MyCustomNode(),
anotherGain = audioContext.createGain();
//connect our custom node to the native nodes and send to the output
gain.connect(customNode.input);
customNode.connect(anotherGain);
anotherGain.connect(audioContext.destination);
ความแตกต่างเพียงอย่างเดียวระหว่างโหนดที่กำหนดเองและโหนดเนทีฟคือเราต้องเชื่อมต่อกับพร็อพเพอร์ตี้อินพุตโหนดที่กำหนดเอง แน่ใจว่ามีวิธีหลบเลี่ยงเรื่องนี้ได้ แต่วิธีนี้ใกล้เพียงพอสำหรับวัตถุประสงค์ของเราแล้ว และยังพัฒนารูปแบบนี้ต่อไปเพื่อจำลองวิธียกเลิกการเชื่อมต่อของ AudioNode แบบเนทีฟ รวมทั้งเพื่อรองรับอินพุต/เอาต์พุตที่ผู้ใช้กำหนดเมื่อเชื่อมต่อ ฯลฯ ลองดูที่ข้อกำหนดเพื่อดูว่าโหนดเนทีฟทำอะไรได้บ้าง
เมื่อเรามีรูปแบบพื้นฐานสำหรับการสร้างเอฟเฟกต์ที่กำหนดเองแล้ว ขั้นตอนต่อไปคือการกำหนดลักษณะการทำงานที่กำหนดเองให้กับโหนดที่กำหนดเอง มาดูโหนดการหน่วงเวลาของ Slackback กัน
ตอบโต้แบบที่เธอตั้งใจ
ท่วงทำนองของแถบสแลปแบ็ค (Slapback Echo) เป็นเอฟเฟกต์ที่นิยมใช้กับเครื่องดนตรีหลายชนิด ตั้งแต่เสียงร้องสไตล์ยุค 50 ไปจนถึงกีตาร์โต้คลื่น เอฟเฟกต์จะใช้เสียงขาเข้าและเล่นสำเนาของเสียงโดยมีความล่าช้าเล็กน้อยประมาณ 75-250 มิลลิวินาที ทำให้รู้สึกถึงเสียงที่โดนตบหลัง ซึ่งจะเป็นชื่อ เราสามารถสร้างเอฟเฟ็กต์ดังนี้
var SlapbackDelayNode = function(){
//create the nodes we'll use
this.input = audioContext.createGain();
var output = audioContext.createGain(),
delay = audioContext.createDelay(),
feedback = audioContext.createGain(),
wetLevel = audioContext.createGain();
//set some decent values
delay.delayTime.value = 0.15; //150 ms delay
feedback.gain.value = 0.25;
wetLevel.gain.value = 0.25;
//set up the routing
this.input.connect(delay);
this.input.connect(output);
delay.connect(feedback);
delay.connect(wetLevel);
feedback.connect(delay);
wetLevel.connect(output);
this.connect = function(target){
output.connect(target);
};
};
บางคนอาจทราบอยู่แล้วว่าดีเลย์นี้อาจใช้กับการหน่วงเวลาที่นานขึ้นด้วย ดังนั้นจึงกลายเป็นการหน่วงเวลาแบบโมโนตามปกติเมื่อมีเสียงเตือน ด้านล่างนี้เป็นตัวอย่างการใช้การหน่วงเวลาเพื่อให้คุณได้ฟังเสียง
กำลังกำหนดเส้นทางเสียง
เมื่อทำงานกับเครื่องดนตรีและชิ้นส่วนดนตรีชนิดต่างๆ ในแอปพลิเคชันเสียงระดับมืออาชีพ คุณจำเป็นต้องมีระบบการกำหนดเส้นทางที่ยืดหยุ่นซึ่งจะช่วยให้คุณมิกซ์และปรับระดับเสียงได้อย่างมีประสิทธิภาพ เราได้พัฒนาระบบบัสเสียงใน JAM กับ Chrome ซึ่งคล้ายกับระบบที่ใช้ในแผ่นมิกซ์เซอร์วิส ซึ่งจะช่วยให้เราสามารถต่อเครื่องดนตรีทุกชนิดที่ต้องการเอฟเฟกต์เสียงก้องกับรถบัสหรือช่องสัญญาณทั่วไป แล้วเพิ่ม Reverb ลงในรถบัสนั้นแทนการเพิ่มเสียงก้องไปยังเครื่องดนตรีแต่ละชิ้นที่แยกกัน นี่เป็นการเพิ่มประสิทธิภาพที่สำคัญ และเราขอแนะนำว่าควรดำเนินการที่คล้ายกันทันทีที่เริ่มใช้แอปพลิเคชันที่ซับซ้อนมากขึ้น
แต่โชคดีที่การเพิ่มประสิทธิภาพของ Web Audio ทำได้ไม่ยาก โดยพื้นฐานแล้ว เราจะใช้โครงกระดูกที่เรากำหนดไว้สำหรับเอฟเฟกต์และใช้แบบเดียวกันนี้ได้
var AudioBus = function(){
this.input = audioContext.createGain();
var output = audioContext.createGain();
//create effect nodes (Convolver and Equalizer are other custom effects from the library presented at the end of the article)
var delay = new SlapbackDelayNode(),
convolver = new tuna.Convolver(),
equalizer = new tuna.Equalizer();
//route 'em
//equalizer -> delay -> convolver
this.input.connect(equalizer);
equalizer.connect(delay.input);
delay.connect(convolver);
convolver.connect(output);
this.connect = function(target){
output.connect(target);
};
};
ซึ่งจะใช้ในลักษณะนี้:
//create some native oscillators and our custom audio bus
var bus = new AudioBus(),
instrument1 = audioContext.createOscillator(),
instrument2 = audioContext.createOscillator(),
instrument3 = audioContext.createOscillator();
//connect our instruments to the same bus
instrument1.connect(bus.input);
instrument2.connect(bus.input);
instrument3.connect(bus.input);
bus.connect(audioContext.destination);
นอกจากนี้ เรายังใช้การหน่วงเวลา การปรับความถี่เสียงให้เหมาะสม และเสียงก้อง (ซึ่งเป็นผลที่ค่อนข้างแพง เมื่อเทียบกับประสิทธิภาพ) โดยมีค่าใช้จ่ายครึ่งหนึ่งเช่นเดียวกับเราใช้เอฟเฟกต์กับเครื่องดนตรีแต่ละชิ้น หากต้องการใส่เครื่องเทศเพิ่มเติมลงไปในรถบัส เราสามารถเพิ่มโหนดใหม่ 2 โหนด ได้แก่ ค่าเกนล่วงหน้าและการโพสต์กำไร ซึ่งช่วยให้เราปิดหรือเบาเสียงในรถประจำทางได้ 2 วิธี โดยแทรกล่วงหน้าไว้ก่อนเอฟเฟ็ก และใส่ PostGET ไว้ที่ท้ายห่วงโซ่ จากนั้น หากเราค่อยๆ เบาเสียงล่วงหน้า เอฟเฟกต์จะยังดังขึ้นหลังจากที่เสียงได้มาถึงด้านล่างแล้ว แต่หากเราค่อยๆ เบาลงในโพสต์เกน เสียงทั้งหมดจะปิดเสียงพร้อมกัน
จากที่นี่ไปที่ไหน
วิธีการที่ฉันอธิบายไว้ที่นี่สามารถและควรจะได้รับการพัฒนาเพิ่มเติม ควรนำสิ่งต่างๆ เช่น อินพุตและเอาต์พุตของโหนดที่กำหนดเอง และวิธีการเชื่อมต่อ ไปใช้โดยใช้การสืบทอดต้นแบบต้นแบบ รถบัสควรสร้างเอฟเฟกต์แบบไดนามิกได้โดยส่งรายการเอฟเฟกต์มาให้
เพื่อเป็นการเฉลิมฉลองการเปิดตัว JAM ด้วย Chrome เราได้ตัดสินใจที่จะทำให้เฟรมเวิร์กของเอฟเฟกต์เป็นโอเพนซอร์ส ถ้าการแนะนำสั้นๆ นี้ทำให้คุณน่าสนใจ ก็ติดตามได้เลย มีการพูดคุยกันที่นี่เกี่ยวกับการกำหนดรูปแบบให้กับรายการ Web Audio ที่กำหนดเอง มาร่วมกับเรา