เริ่มต้นใช้งาน Web Audio API

ก่อนองค์ประกอบ HTML5 <audio> ต้องมี Flash หรือปลั๊กอินอื่น เพื่อทลายกำแพงอินเทอร์เน็ต ขณะที่เสียงบนเว็บไม่ได้ให้บริการอีกต่อไป ต้องใช้ปลั๊กอิน แท็กเสียงมีข้อจำกัดที่สำคัญสำหรับ การนำเกมที่ซับซ้อนและแอปพลิเคชันแบบอินเทอร์แอกทีฟมาใช้

Web Audio API คือ JavaScript API ระดับสูงสำหรับการประมวลผลและ โดยการสังเคราะห์เสียงในเว็บแอปพลิเคชัน เป้าหมายของ API นี้คือ ประกอบด้วยความสามารถที่พบในเครื่องมือเสียงในเกมสมัยใหม่ และ งานผสม การประมวลผล และการกรองงานที่พบในเดสก์ท็อปสมัยใหม่ แอปพลิเคชันการผลิตเสียง ตามด้วยบทแนะนำสั้นๆ เกี่ยวกับ โดยใช้ API ที่มีประสิทธิภาพนี้

เริ่มต้นใช้งาน AudioContext

AudioContext มีไว้เพื่อจัดการและเล่นเสียงทั้งหมด เพื่อผลิต เสียงโดยใช้ Web Audio API ให้สร้างแหล่งที่มาของเสียงอย่างน้อย 1 รายการ และเชื่อมต่อกับอุปกรณ์ปลายทางเสียงที่ให้บริการโดย AudioContext อินสแตนซ์ การเชื่อมต่อนี้ไม่จำเป็นต้องเป็นการเชื่อมต่อโดยตรง และสามารถเชื่อมต่อได้ AudioNodes ระดับกลางที่ทำหน้าที่เป็นการประมวลผลข้อมูล สำหรับสัญญาณเสียง การกำหนดเส้นทางนี้จะอธิบายไว้ใน ในข้อกำหนด Web Audio

อินสแตนซ์เดียวของ AudioContext จะรองรับอินพุตเสียงหลายรายการได้ และกราฟเสียงที่ซับซ้อน ดังนั้นเราต้องการเพียง 1 ประเภทเท่านั้นสำหรับ แอปพลิเคชันเสียงที่เราสร้างขึ้น

ข้อมูลโค้ดต่อไปนี้สร้าง AudioContext

var context;
window.addEventListener('load', init, false);
function init() {
    try {
    context = new AudioContext();
    }
    catch(e) {
    alert('Web Audio API is not supported in this browser');
    }
}

สำหรับเบราว์เซอร์ที่ใช้ WebKit รุ่นเก่า ให้ใช้คำนำหน้า webkit เช่น webkitAudioContext

ฟังก์ชันการทำงานของ Web Audio API ที่น่าสนใจหลายอย่าง เช่น การสร้าง AudioNode และการถอดรหัสข้อมูลไฟล์เสียงเป็นเมธอดของ AudioContext

กำลังโหลดเสียง

Web Audio API ใช้ AudioBuffers มีความยาวสั้นถึงปานกลาง เสียง วิธีพื้นฐานคือการใช้ XMLHttpRequest สำหรับ กำลังดึงข้อมูลไฟล์เสียง

API รองรับการโหลดข้อมูลไฟล์เสียงในหลายรูปแบบ เช่น WAV, MP3, AAC, OGG และอื่นๆ การสนับสนุนเบราว์เซอร์สำหรับ รูปแบบเสียงจะแตกต่างกันไป

ตัวอย่างต่อไปนี้แสดงการโหลดตัวอย่างเสียง

var dogBarkingBuffer = null;
var context = new AudioContext();

function loadDogSound(url) {
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.responseType = 'arraybuffer';

    // Decode asynchronously
    request.onload = function() {
    context.decodeAudioData(request.response, function(buffer) {
        dogBarkingBuffer = buffer;
    }, onError);
    }
    request.send();
}

ข้อมูลไฟล์เสียงเป็นไบนารี (ไม่ใช่ข้อความ) เราจึงตั้งค่า responseType ของคำขอไปยัง 'arraybuffer' สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ ArrayBuffers ดูบทความเกี่ยวกับ XHR2 นี้

เมื่อได้รับข้อมูลไฟล์เสียง (ไม่ได้เข้ารหัส) แล้ว คุณสามารถเก็บไฟล์ดังกล่าวไว้ เพื่อถอดรหัสในภายหลัง หรือสามารถถอดรหัสได้ทันทีโดยใช้ เมธอด decodeAudioData() ของ AudioContext เมธอดนี้จะ ArrayBuffer ของข้อมูลไฟล์เสียงที่จัดเก็บใน request.response และ จะถอดรหัสแบบอะซิงโครนัส (ไม่บล็อกการเรียกใช้ JavaScript หลัก) ชุดข้อความ)

เมื่อ decodeAudioData() ทำงานเสร็จแล้ว จะมีการเรียกฟังก์ชัน Callback ซึ่ง ให้ข้อมูลเสียง PCM ที่ถอดรหัสเป็น AudioBuffer

กำลังเล่นเสียง

วันที่ กราฟเสียงแบบง่ายๆ
กราฟเสียงแบบง่ายๆ

เมื่อโหลด AudioBuffers อย่างน้อย 1 รายการแล้ว เราก็พร้อมเล่น เสียง สมมติว่าเราเพิ่งโหลด AudioBuffer พร้อมเสียง ของสุนัขเห่าและการโหลดเสร็จสิ้นแล้ว จากนั้นเราก็จะได้เล่น บัฟเฟอร์นี้ด้วยโค้ดต่อไปนี้

var context = new AudioContext();

function playSound(buffer) {
    var source = context.createBufferSource(); // creates a sound source
    source.buffer = buffer;                    // tell the source which sound to play
    source.connect(context.destination);       // connect the source to the context's destination (the speakers)
    source.noteOn(0);                          // play the source now
}

สามารถเรียกฟังก์ชัน playSound() นี้ทุกครั้งที่มีคนกดปุ่ม หรือ คลิกสิ่งต่างๆ ด้วยเมาส์

ฟังก์ชัน noteOn(time) ช่วยให้กำหนดเวลาเสียงที่แม่นยำได้ง่ายๆ การเล่นสำหรับเกมและแอปพลิเคชันต่างๆ ที่ต้องใช้เวลา แต่หากต้องการ การตั้งเวลานี้ทำงานอย่างถูกต้อง ตรวจสอบว่าบัฟเฟอร์เสียงของคุณ ที่โหลดไว้ล่วงหน้า

การดึง Web Audio API

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

ต่อไปนี้เป็นตัวอย่างวิธีใช้ชั้นเรียน BufferLoader มาสร้าง AudioBuffers 2 รายการกัน และทันทีที่โหลดเสร็จ คราวนี้เรามาเล่นพร้อมกัน

window.onload = init;
var context;
var bufferLoader;

function init() {
    context = new AudioContext();

    bufferLoader = new BufferLoader(
    context,
    [
        '../sounds/hyper-reality/br-jam-loop.wav',
        '../sounds/hyper-reality/laughter.wav',
    ],
    finishedLoading
    );

    bufferLoader.load();
}

function finishedLoading(bufferList) {
    // Create two sources and play them both together.
    var source1 = context.createBufferSource();
    var source2 = context.createBufferSource();
    source1.buffer = bufferList[0];
    source2.buffer = bufferList[1];

    source1.connect(context.destination);
    source2.connect(context.destination);
    source1.noteOn(0);
    source2.noteOn(0);
}

การรับมือกับเวลา: การเล่นเสียงตามจังหวะ

Web Audio API ช่วยให้นักพัฒนาซอฟต์แวร์กำหนดเวลาการเล่นได้อย่างแม่นยำ ถึง สาธิตวิธีการนี้ เรามาสร้างแทร็กจังหวะง่ายๆ กัน บางที รูปแบบกลองชุดที่รู้จักกันอย่างแพร่หลายมีดังนี้

วันที่ ลวดลายกลองร็อกง่ายๆ
ลวดลายกลองร็อกง่ายๆ

ซึ่งจะมีการเล่นฮิแฮตทุกโน้ต 8 ตัว และจะเตะและสแนร์ สลับกันไปทุกไตรมาส เป็นเวลา 4/4

สมมติว่าเราโหลดบัฟเฟอร์ kick, snare และ hihat โค้ดสำหรับวิธีการนั้นง่ายมาก

for (var bar = 0; bar < 2; bar++) {
    var time = startTime + bar * 8 * eighthNoteTime;
    // Play the bass (kick) drum on beats 1, 5
    playSound(kick, time);
    playSound(kick, time + 4 * eighthNoteTime);

    // Play the snare drum on beats 3, 7
    playSound(snare, time + 2 * eighthNoteTime);
    playSound(snare, time + 6 * eighthNoteTime);

    // Play the hi-hat every eighth note.
    for (var i = 0; i < 8; ++i) {
    playSound(hihat, time + i * eighthNoteTime);
    }
}

ตรงนี้เราจะสร้างการเล่นซ้ำเพียงรายการเดียว แทนที่จะเป็นการวนซ้ำแบบไม่จำกัดที่เราเห็น โน้ตเพลง ฟังก์ชัน playSound เป็นเมธอดที่เล่น บัฟเฟอร์ในเวลาที่ระบุ ดังนี้

function playSound(buffer, time) {
    var source = context.createBufferSource();
    source.buffer = buffer;
    source.connect(context.destination);
    source.noteOn(time);
}

การปรับระดับเสียง

การดำเนินการขั้นพื้นฐานที่สุดอย่างหนึ่งที่คุณอาจต้องการทำเพื่อให้ได้เสียงคือ ปรับระดับเสียง เมื่อใช้ Web Audio API เราสามารถกำหนดเส้นทางแหล่งที่มาไปยัง ปลายทางผ่าน AudioGainNode เพื่อปรับแต่ง ระดับเสียง:

วันที่ กราฟเสียงที่มีโหนดเกน
กราฟเสียงที่มีโหนดเกน

การตั้งค่าการเชื่อมต่อนี้จะทำได้ดังต่อไปนี้

// Create a gain node.
var gainNode = context.createGainNode();
// Connect the source to the gain node.
source.connect(gainNode);
// Connect the gain node to the destination.
gainNode.connect(context.destination);

เมื่อตั้งค่ากราฟแล้ว คุณสามารถเปลี่ยน ระดับเสียงโดยการควบคุม gainNode.gain.value ดังนี้

// Reduce the volume.
gainNode.gain.value = 0.5;

เสียง 2 เสียงทับซ้อนกัน

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

ซึ่งทําได้ด้วยกราฟเสียงต่อไปนี้

วันที่ กราฟเสียงที่มีแหล่งที่มา 2 แหล่งเชื่อมต่อกันผ่านโหนด เกน
กราฟเสียงที่มีแหล่งที่มา 2 แหล่งเชื่อมต่อกันผ่านโหนด เกน

ในการตั้งค่านี้ เราเพียงสร้าง AudioGainNodes แล้วเชื่อมต่อ แต่ละแหล่งที่มาผ่านทางโหนด โดยใช้ฟังก์ชันนี้

function createSource(buffer) {
    var source = context.createBufferSource();
    // Create a gain node.
    var gainNode = context.createGainNode();
    source.buffer = buffer;
    // Turn on looping.
    source.loop = true;
    // Connect source to gain.
    source.connect(gainNode);
    // Connect gain to destination.
    gainNode.connect(context.destination);

    return {
    source: source,
    gainNode: gainNode
    };
}

ครอสเฟดพลังงานเท่ากัน

วิธีการครอสเฟดเชิงเส้นแบบไร้เดียงสาจะแสดงการลดลงเมื่อคุณเลื่อน ระหว่างกลุ่มตัวอย่าง

วันที่ ครอสเฟดเชิงเส้น
ครอสเฟดเชิงเส้น

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

วันที่ ครอสเฟดที่มีกำลังเท่ากัน
ครอสเฟดที่มีค่าเท่ากัน

ครอสเฟดของเพลย์ลิสต์

แอปพลิเคชันครอสเฟดอีกอย่างหนึ่งคือแอปพลิเคชันโปรแกรมเล่นเพลง เมื่อเพลงเปลี่ยนไป เราก็อยากให้แทร็กที่ฟังอยู่เล่นจบลงแล้วค่อยๆ เบาลง เพื่อหลีกเลี่ยงการเปลี่ยนแปลงที่สะเทือนใจ โดยตั้งเวลา ครอสเฟดไปสู่อนาคต แม้ว่าเราจะใช้ setTimeout เพื่อดำเนินการนี้ได้ การจัดตารางเวลา สิ่งนี้ไม่แม่นยำ ด้วย Web Audio API สามารถใช้อินเทอร์เฟซ AudioParam เพื่อตั้งเวลาค่าในอนาคตสำหรับ เช่น ค่าเกนของ AudioGainNode

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

function playHelper(bufferNow, bufferLater) {
    var playNow = createSource(bufferNow);
    var source = playNow.source;
    var gainNode = playNow.gainNode;
    var duration = bufferNow.duration;
    var currTime = context.currentTime;
    // Fade the playNow track in.
    gainNode.gain.linearRampToValueAtTime(0, currTime);
    gainNode.gain.linearRampToValueAtTime(1, currTime + ctx.FADE_TIME);
    // Play the playNow track.
    source.noteOn(0);
    // At the end of the track, fade it out.
    gainNode.gain.linearRampToValueAtTime(1, currTime + duration-ctx.FADE_TIME);
    gainNode.gain.linearRampToValueAtTime(0, currTime + duration);
    // Schedule a recursive track change with the tracks swapped.
    var recurse = arguments.callee;
    ctx.timer = setTimeout(function() {
    recurse(bufferLater, bufferNow);
    }, (duration - ctx.FADE_TIME) - 1000);
}

Web Audio API มีชุดเมธอด RampToValue อย่างสะดวกในการ ค่อยๆ เปลี่ยนค่าของพารามิเตอร์ เช่น linearRampToValueAtTime และ exponentialRampToValueAtTime

แม้ว่าจะเลือกฟังก์ชันช่วงเวลาการเปลี่ยนภาพได้จากเชิงเส้นในตัว และเลขชี้กำลัง (ตามด้านบน) คุณยังสามารถระบุค่าของคุณเอง โค้งผ่านอาร์เรย์ของค่าโดยใช้ฟังก์ชัน setValueCurveAtTime

การใช้เอฟเฟกต์ฟิลเตอร์ง่ายๆ กับเสียง

วันที่ กราฟเสียงที่มี BiquadFilterNode
กราฟเสียงที่มี BiquadFilterNode

Web Audio API ช่วยให้คุณเชื่อมเสียงจากโหนดเสียงหนึ่งไปยังอีกโหนดหนึ่งได้ เป็นการสร้างเชนโปรเซสเซอร์ที่ซับซ้อน เอฟเฟกต์กับซาวด์ฟอร์มของคุณ

วิธีหนึ่งในการทำเช่นนี้คือการวาง BiquadFilterNode ระหว่างเสียง ต้นทางและปลายทาง โหนดเสียงประเภทนี้สามารถทำสิ่งต่างๆ ตัวกรองลำดับต่ำซึ่งสามารถใช้เพื่อสร้างอีควอไลเซอร์กราฟิก เอฟเฟ็กต์ที่ซับซ้อนมากขึ้น ซึ่งส่วนใหญ่แล้วจะเกี่ยวข้องกับการเลือกส่วนของ สเปกตรัมของเสียงที่ควรเน้นย้ำและที่ควรสื่อไป

ประเภทของตัวกรองที่รองรับ ได้แก่

  • ตัวกรองโลว์พาส
  • ตัวกรอง High Pass
  • ตัวกรองบัตรผ่านสายนาฬิกา
  • ตัวกรองชั้นวางต่ำ
  • ตัวกรองชั้นวางสูง
  • ฟิลเตอร์จุดโฟกัส
  • ฟิลเตอร์รอยบาก
  • ตัวกรองบัตรทั้งหมด

และตัวกรองทั้งหมดจะมีพารามิเตอร์เพื่อระบุ gain ความถี่ในการใช้ตัวกรอง และปัจจัยด้านคุณภาพ ตัวกรองค่ารักษาความถี่ต่ำจะคงช่วงความถี่ต่ำไว้ แต่ปล่อยความถี่สูง ความถี่ จุดเบรกออฟจะพิจารณาจากค่าความถี่ และปัจจัย Q จะไม่มีหน่วย และจะเป็นตัวกำหนดรูปร่างของ กราฟ กำไรที่มีผลต่อตัวกรองบางอย่างเท่านั้น เช่น ชั้นวางต่ำ และ ตัวกรองที่มีประสิทธิภาพสูงสุด ซึ่งไม่ใช่ตัวกรองแบบ Low Pass นี้

มาสร้างตัวกรองแบบโลว์พาสแบบง่ายๆ เพื่อดึงข้อมูลเฉพาะพื้นฐานจาก ตัวอย่างเสียง:

// Create the filter
var filter = context.createBiquadFilter();
// Create the audio graph.
source.connect(filter);
filter.connect(context.destination);
// Create and specify parameters for the low-pass filter.
filter.type = 0; // Low-pass filter. See BiquadFilterNode docs
filter.frequency.value = 440; // Set cutoff to 440 HZ
// Playback the sound.
source.noteOn(0);

โดยทั่วไป ตัวควบคุมความถี่จะต้องปรับแก้เพื่อให้ทำงานกับ สเกลลอการิทึมตั้งแต่การได้ยินของมนุษย์ทำงานบนหลักการเดียวกัน (กล่าวคือ A4 คือ 440 Hz และ A5 เท่ากับ 880hz) ดูรายละเอียดเพิ่มเติมได้ที่ FilterSample.changeFrequency ในลิงก์ซอร์สโค้ดด้านบน

สุดท้าย โปรดทราบว่าโค้ดตัวอย่างจะช่วยให้คุณเชื่อมต่อและยกเลิกการเชื่อมต่อ ซึ่งจะเปลี่ยนแปลงกราฟ AudioContext แบบไดนามิก เราสามารถยกเลิกการเชื่อมต่อ AudioNode จากกราฟโดยการเรียกใช้ node.disconnect(outputNumber) ตัวอย่างเช่น หากต้องการเปลี่ยนเส้นทางกราฟจากการกรองไปยัง โดยตรงได้ เราสามารถทําสิ่งต่อไปนี้ได้

// Disconnect the source and filter.
source.disconnect(0);
filter.disconnect(0);
// Connect the source directly.
source.connect(context.destination);

ฟังเพลงได้อย่างต่อเนื่อง

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

หากต้องการแรงบันดาลใจ นักพัฒนาซอฟต์แวร์จำนวนมากได้สร้าง ทำได้ดีมาก โดยใช้ Web Audio API บางส่วนที่ฉันชอบ รวมข้อมูลต่อไปนี้

  • AudioJedit เครื่องมือเชื่อมต่อเสียงในเบราว์เซอร์ที่ใช้ ลิงก์ถาวรของ SoundCloud
  • ToneCraft เครื่องจัดลำดับเสียงที่สร้างเสียงขึ้นโดย บล็อก 3 มิติซ้อนกัน
  • Plink ซึ่งเป็นเกมสร้างสรรค์เพลงที่ทำร่วมกันโดยใช้ Web Audio และ Web ซ็อกเก็ต