การอัปเดตเสียงในเว็บใน Chrome 49

คริส วิลสัน
Chris Wilson

Chrome ได้ปรับปรุงการรองรับ Web Audio API อย่างต่อเนื่องและเงียบ ใน Chrome 49 (เบต้าตั้งแต่เดือนกุมภาพันธ์ 2016 และคาดว่าจะใช้งานได้เสถียรในเดือนมีนาคม 2016) เราได้ปรับปรุงหลายฟีเจอร์เพื่อติดตามข้อกำหนด และเพิ่มโหนดใหม่ 1 โหนด

decodeAudioData() จะส่งกลับคำสัญญา

ตอนนี้เมธอด decodeAudioData() ใน AudioContext จะแสดง Promise ซึ่งเป็นการเปิดใช้การจัดการรูปแบบแบบอะซิงโครนัสที่อิงตาม Promise เมธอด decodeAudioData() จะมีฟังก์ชันเรียกกลับ "สำเร็จและข้อผิดพลาด" เป็นพารามิเตอร์เสมอ ดังนี้

context.decodeAudioData( arraybufferData, onSuccess, onError);

แต่ตอนนี้ คุณสามารถใช้เมธอด Promise แบบมาตรฐานเพื่อจัดการกับลักษณะแบบอะซิงโครนัสของการถอดรหัสข้อมูลเสียงแทน ดังนี้

context.decodeAudioData( arraybufferData ).then(
        (buffer) => { /* store the buffer */ },
        (reason) => { console.log("decode failed! " + reason) });

แม้ในตัวอย่างเดียว วิธีนี้ดูมีรายละเอียดมากกว่า แต่คำสัญญาจะทำให้การเขียนโปรแกรมแบบอะซิงโครนัสง่ายและสอดคล้องกันมากกว่า ระบบยังคงรองรับฟังก์ชันเรียกกลับ "สำเร็จ" และ "ข้อผิดพลาด" ตามข้อกำหนด

ออฟไลน์AudioContext สนับสนุนถูกระงับ() และกลับมาทำงานอีกครั้ง() แล้ว

เมื่อดูคร่าวๆ อาจฟังดูแปลกๆ ที่จะมีคำว่า suspended() ใน OfflineAudioContext สุดท้ายแล้วก็มีการเพิ่ม suspend() ลงใน AudioContext เพื่อให้สามารถใส่ฮาร์ดแวร์เสียงเข้าสู่โหมดสแตนด์บาย ซึ่งดูเหมือนจะไม่มีประโยชน์ในสถานการณ์เมื่อคุณแสดงผลบัฟเฟอร์ (ซึ่งแน่นอนว่า OfflineAudioContext มีไว้สำหรับ) อย่างไรก็ตาม จุดประสงค์ของฟีเจอร์นี้คือสามารถสร้าง "คะแนน" ได้ทีละส่วนเท่านั้น เพื่อลดการใช้หน่วยความจำให้เหลือน้อยที่สุด คุณยังสร้างโหนดเพิ่มได้เมื่อ ระงับในระหว่างการแสดงผล

เช่น Moonlight Sonata ของ Beethoven ได้มีโน้ตประมาณ 6,500 อัน "หมายเหตุ" แต่ละรายการอาจถอดรหัสไปยังโหนดกราฟเสียงอย่างน้อย 2 โหนด (เช่น AudioBuffer และโหนด Gain) หากคุณต้องการแสดงผลเวลาทั้ง 7 นาทีครึ่งลงในบัฟเฟอร์ด้วย OfflineAudioContext คุณอาจไม่ต้องสร้างโหนดเหล่านั้นทั้งหมดพร้อมกัน แต่คุณสามารถสร้าง เป็นส่วนๆ ได้ดังนี้

var context = new OfflineAudioContext(2, length, sampleRate);
scheduleNextBlock();
context.startRendering().then( (buffer) => { /* store the buffer */ } );

function scheduleNextBlock() {
    // create any notes for the next blockSize number of seconds here
    // ...

    // make sure to tell the context to suspend again after this block;
    context.suspend(context.currentTime + blockSize).then( scheduleNextBlock );

    context.resume();
}

วิธีนี้จะช่วยลดจำนวนโหนดที่ต้องสร้างไว้ล่วงหน้าเมื่อเริ่มต้นการแสดงผลและลดความต้องการหน่วยความจำ

IIRFilterNode

ข้อกำหนดนี้ได้เพิ่มโหนดสำหรับผู้รักเสียงเพลงที่ต้องการสร้างการตอบสนองแบบไม่มีที่สิ้นสุดซึ่งระบุได้แม่นยำด้วยตนเอง: IIRFilterNode ตัวกรองนี้ช่วยเสริม BiquadFilterNode แต่อนุญาตข้อมูลจำเพาะโดยสมบูรณ์ของพารามิเตอร์การตอบสนองของตัวกรอง (แทนที่จะใช้ AudioParams ที่ใช้งานง่ายของ BiquadFilterNode สำหรับประเภท ความถี่ Q และอื่นๆ) IIRFilterNode อนุญาตข้อกำหนดเฉพาะของตัวกรองที่ไม่สามารถสร้างได้มาก่อน เช่น ตัวกรองแบบเรียงลำดับเดียว อย่างไรก็ตาม การใช้ IIRFilterNode จำเป็นต้องมีความรู้เชิงลึกเกี่ยวกับวิธีการทํางานของตัวกรอง IIR และยังจัดตารางเวลาไม่ได้อย่าง BiquadFilterNodes อีกด้วย

การเปลี่ยนแปลงก่อนหน้า

นอกจากนี้ เราขอพูดถึงการปรับปรุง 2 อย่างที่ได้ดำเนินการไปแล้วก่อนหน้านี้ ใน Chrome 48 นั้น การทำงานอัตโนมัติของโหนด BiquadFilter เริ่มทำงานที่อัตราเสียง แม้ว่า API นี้จะไม่มีการเปลี่ยนแปลงใดๆ เลย แต่หมายความว่าการกวาดตัวกรองจะทำงานได้ราบรื่นยิ่งขึ้น นอกจากนี้ใน Chrome 48 เราได้เพิ่มการทำเชนกับเมธอด AudioNode.connect() โดยแสดงผลโหนดที่กำลังเชื่อมต่ออยู่ ซึ่งจะช่วยให้สร้างเชนโหนดได้ง่ายขึ้น ดังเช่นในตัวอย่างนี้

sourceNode.connect(gainNode).connect(filterNode).connect(context.destination);

จบแล้ว มาลุยกันต่อเลย!