עדכונים של אודיו באינטרנט ב-Chrome 49

כריס וילסון
כריס ווילסון

Chrome שיפר את התמיכה שלו ב-Web Audio API באופן עקבי ושקט. ב-Chrome 49 (גרסת בטא מפברואר 2016, ואנחנו צופים שהיא תהיה יציבה במרץ 2016) עדכנו מספר תכונות למעקב אחר המפרטים, והוספנו גם צומת חדש אחד.

decodeAudioData() מחזיר הבטחה

השיטה decodeAudioData() ב-AudioContext מחזירה עכשיו Promise, וכך מאפשרת טיפול בדפוסים אסינכרוניים באמצעות Promise. השיטה decodeAudioData() תמיד משתמשת בפונקציות של קריאה חוזרת (callback) מסוג הצלחה ושגיאה כפרמטרים:

context.decodeAudioData( arraybufferData, onSuccess, onError);

אבל עכשיו תוכלו להשתמש בשיטת Promise רגילה כדי לטפל באופי האסינכרוני של פענוח נתוני אודיו:

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

למרות שדוגמה אחת נראית ארוכה יותר, ההבטחות הופכות את התכנות האסינכרוני לקל ועקבי יותר. מבחינת התאימות, הפונקציות 'הצלחה' ו'שגיאה' עדיין נתמכות, לפי המפרט.

במצב אופליין יש עכשיו תמיכה ב-Pause() וב-reserve()

במבט ראשון, אולי נראה מוזר להשעות() ב-OfflineAudioContext. אחרי הכול, בוצעה הוספה של suspend() אל AudioContext כדי לאפשר להעביר את חומרת האודיו למצב המתנה. מצב זה נראה חסר טעם במקרים של רינדור למאגר נתונים זמני (כמובן שהמטרה שלו היא OfflineAudioContext). עם זאת, המטרה של התכונה הזו היא להצליח לבנות רק חלק מ"ציון" בכל פעם, כדי לצמצם את השימוש בזיכרון. אפשר ליצור צמתים נוספים בזמן העיבוד באמצע העיבוד.

לדוגמה, הסונטה 'אור הירח' של בטהובן מכילה כ-6,500 תווים. סביר להניח שכל "הערה" מפרשת לשני צמתים של גרף אודיו לפחות (לדוגמה, AudioBuffer וצומת Gain). אם אתם רוצים לעבד את שבע וחצי דקות לתוך מאגר נתונים זמני באמצעות 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

במפרט נוסף צומת עבור חובבי אודיו שרוצים ליצור infinite-impulse-response (בדיוק רב-מצופה), ה-IIRFilterNode. המסנן הזה משלים את BiquadFilterNode, אבל מאפשר מפרט מלא של הפרמטרים של תגובת הסינון (במקום להשתמש ב-AudioParams הנוח לשימוש של BiquadFilterNode לסוג, תדירות, Q וכדומה). השדה IIRFilterNode מאפשר פירוט מדויק של מסננים שלא ניתן היה ליצור לפני כן, כמו מסננים בהזמנה יחידה. עם זאת, השימוש ב-IIRFilterNode מחייב ידע מעמיק לגבי אופן הפעולה של מסנני IIR, וגם אי אפשר לתזמן אותם כמו BiquadFilterNodes.

שינויים קודמים

חשוב לציין גם כמה שיפורים שבוצעו בעבר: ב-Chrome 48, האוטומציה של צמתים של BiquadFilter התחילה לפעול בקצב אודיו. ה-API לא השתנה בכלל, אבל המשמעות היא שניקוי המסננים יישמע אפילו יותר חלק. כמו כן, ב-Chrome 48 הוספנו שרשור ל-method AudioNode.connect() על ידי החזרת הצומת שאליו אנחנו מתחברים. כך קל יותר ליצור שרשראות של צמתים, כמו בדוגמה הזו:

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

זה הכול בינתיים, המשיכו כך!