Статьи

API-интерфейс Web Audio: добавление звука в веб-приложение

Что случилось со звуком в сети? Некоторое время веб был платформой, чтобы показать ваш вкус в мелодиях. От MIDI-версий «Final Countdown», пузырящихся на заднем плане, до автоматического проигрывания MySpace mp3-файлов, которые звучат у вас на лице, звук был повсюду.

Уже нет. Будучи сожженными этими злодеяниями пользовательского опыта, веб-разработчики держатся подальше от этого. К сожалению, звук отошел на второй план в Интернете, в то время как нативные приложения процветают.

Подумайте о звуке уведомлений, который вы слышите при получении электронного письма, или о небольшом всплывающем сообщении при обновлении приложения Twitter. Такие приложения показывают, как звук может быть неотъемлемой частью хорошего пользовательского опыта.

В этом уроке я покажу вам, как правильно вернуть звук в Интернет!

Web Audio API — это мощный, высокопроизводительный способ управления звуком в браузере. Прежде чем продолжить этот урок, вы, возможно, захотите ознакомиться с предыдущим уроком из этой серии, в котором я рассказал о том, как создать базовый звук с использованием JavaScript, а также воспроизвести mp3-файл.

Для этого урока мы собираемся смоделировать страницу оплаты, которая дает нам звуковую обратную связь, что наш платеж успешен. Я буду использовать Bootstrap, чтобы все выглядело лучше.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!doctype html>
<html>
    <head>
        <meta charset=»utf-8″>
        <meta name=»viewport» content=»width=device-width»>
        <title>Add sound to your web app</title>
        <link rel=»stylesheet» href=»https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css»>
    </head>
    <body>
        <div class=»container»>
            <div class=»row»>
                <div class=»col-md-6″>
                    <h1>My shop</h1>
                    <p>Are you ready to buy this item?</p>
                    <form action=»»>
                        <div class=»form-group»>
                            <label>Name on card</label>
                            <input type=»text» class=»form-control» value=»Guybrush Threepwood» />
                        </div>
                        <div class=»form-group»>
                            <label>Card number</label>
                            <input type=»text» class=»form-control» value=»1234-1234-1234-1234″ />
                        </div>
                    </form>
                    <button id=»buy-now-button» type=»button» class=»btn btn-primary»
                        data-loading-text=»Processing…» data-complete-text=»Success!»>Buy now</button>
                </div>
            </div>
        </div>
 
        <script src=»https://code.jquery.com/jquery-2.1.3.min.js»></script>
        <script src=»https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js»></script>
         
        <script src=»scripts/success-sound.js»></script>
    </body>
</html>

Вы заметите, что в самом низу я включил файл «success-sound.js». Здесь мы напишем наш код, чтобы предоставить звуковую обратную связь пользователю, когда его оплата будет успешной. Как только вы создали этот файл, первое, что мы хотим сделать, это создать AudioContext. Из последнего урока вы, возможно, помните, что AudioContext — это то, как мы получаем доступ к различным функциям Web Audio API.

var context = new AudioContext();

Одна из лучших особенностей API Web Audio заключается в том, что он позволяет нам создавать звуки с нуля, даже не глядя на аудиофайл. Мы делаем это с помощью осцилляторов.

Осцилляторы — это способ создать тон, который мы можем услышать. Они делают это, генерируя периодическую волну на определенной частоте. Форма этой волны различна, но наиболее распространенными являются волны синуса, квадрата, треугольника и пилообразной волны. Эти типы волн звучат по-разному. Давайте создадим два треугольных волновых генератора.

1
2
3
4
5
var osc1 = context.createOscillator(),
    osc2 = context.createOscillator();
     
osc1.type = ‘triangle’;
osc2.type = ‘triangle’;

По умолчанию осцилляторы довольно громкие, поэтому, если мы не хотим напугать своих пользователей, нам следует немного уменьшить громкость. Поскольку API Web Audio работает, объединяя узлы в единый канал, мы создаем и подключаем наши генераторы к GainNode.

1
2
3
var volume = context.createGain();
 
volume.gain.value = 0.1;

Узлы усиления умножают громкость звука на указанное вами число. Таким образом, в этом случае громкость будет составлять одну десятую часть передаваемого ему сигнала.

Давайте соединим все.

1
2
3
4
5
6
// Connect oscillators to the GainNode
osc1.connect(volume);
osc2.connect(volume);
 
// Connect GainNode to the speakers
volume.connect(context.destination);

Затем убедитесь, что мы сделали это правильно, сыграв на осцилляторах две секунды.

01
02
03
04
05
06
07
08
09
10
11
12
13
// How long to play oscillator for (in seconds)
var duration = 2;
 
// When to start playing the oscillators
var startTime = context.currentTime;
 
// Start the oscillators
osc1.start(startTime);
osc2.start(startTime);
 
// Stop the oscillators 2 seconds from now
osc1.stop(startTime + duration);
osc1.stop(startTime + duration);

В этот момент вы должны услышать тональный сигнал при перезагрузке страницы. Не самый удивительный звук, я уверен, вы согласитесь, но это только начало!

Созданные нами генераторы воспроизводятся с частотой по умолчанию. Изменяя эту частоту, мы можем изменить музыкальную ноту, которую вы слышите при ее воспроизведении. Это то, что сделает наш тон немного более приятным и является ключом к ощущению, которое вы хотите вызвать, когда ваш пользователь услышит его. Давайте переключим наш осциллятор на ноту «B4», которая составляет 493,883 Гц.

1
2
3
4
var frequency = 493.883;
 
osc1.frequency.value = frequency;
osc2.frequency.value = frequency;

Теперь, если мы перезагрузим страницу, вы услышите тон на другом тоне. В этот момент вы можете подумать: «Почему мы играем на двух осцилляторах с одинаковым шагом?» Ну, это приводит нас к небольшому трюку, который мы можем сделать, чтобы наш тон звучал немного лучше.

Если мы отрегулируем наши осцилляторы, чтобы их частоты немного отличались, мы получим приятный эффект хоруса, который сделает наш тон звучащим намного богаче.

1
2
3
4
var frequency = 493.883;
 
osc1.frequency.value = frequency + 1;
osc2.frequency.value = frequency — 2;

Хотя наш маленький звук звучит намного лучше, он заканчивается довольно резко. Чтобы сделать это менее резким, мы должны быстро уменьшить громкость в конце звука; это также известно как «исчезновение». Это делается с помощью AudioParams, которые используются для автоматизации значений аудио узлов, таких как усиление и частота. Мы пойдем в AudioParams более подробно в следующем уроке из этой серии.

1
2
3
4
5
// Set the volume to be 0.1 just before the end of the tone
volume.gain.setValueAtTime(0.1, startTime + duration — 0.05);
 
// Make the volume ramp down to zero 0.1 seconds after the end of the tone
volume.gain.linearRampToValueAtTime(0, startTime + duration);

То, что мы говорим здесь, это убедиться, что громкость составляет 0,1, 0,05 секунды, прежде чем закончится наш тон. Затем продолжайте уменьшать громкость, пока она не достигнет нуля, в то время как наш тон заканчивается.

Давайте свернем наш код до единой функции и посмотрим, что у нас получилось.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Play oscillators at certain frequency and for a certain time
var playNote = function (frequency, startTime, duration) {
    var osc1 = context.createOscillator(),
        osc2 = context.createOscillator(),
        volume = context.createGain();
 
    // Set oscillator wave type
    osc1.type = ‘triangle’;
    osc2.type = ‘triangle’;
 
    volume.gain.value = 0.1;
 
    // Set up node routing
    osc1.connect(volume);
    osc2.connect(volume);
    volume.connect(context.destination);
 
    // Detune oscillators for chorus effect
    osc1.frequency.value = frequency + 1;
    osc2.frequency.value = frequency — 2;
 
    // Fade out
    volume.gain.setValueAtTime(0.1, startTime + duration — 0.05);
    volume.gain.linearRampToValueAtTime(0, startTime + duration);
 
    // Start oscillators
    osc1.start(startTime);
    osc2.start(startTime);
 
    // Stop oscillators
    osc1.stop(startTime + duration);
    osc2.stop(startTime + duration);
};

Чтобы сделать эту функцию немного более мощной, я удалил некоторые переменные и позволил передавать эти значения. Это позволяет нам играть разные ноты на разных частотах. Теперь пришло время проявить творческий подход!

Подумайте о том, что вы хотите, чтобы ваши пользователи чувствовали, когда они только что купили что-то в вашем интернет-магазине. Это положительный опыт — кто-то купил то, что хотел, чтобы как-то улучшить свою жизнь, ошибок не было, и транзакция была успешно обработана.

С точки зрения звука, показатель успеха на самом деле довольно прост. Музыкальный мотив, который поднимается в высоту в конце, всегда звучит гораздо более радостно, чем тот, который падает. Вам даже не нужно иметь мелодию или целую кучу заметок, чтобы передать это. Чтобы доказать эту теорию, давайте просто используем две отдельные заметки для нашего мотива успеха.

1
2
3
4
5
// Play a ‘B’ now that lasts for 0.116 seconds
playNote(493.883, context.currentTime, 0.116);
 
// Play an ‘E’ just as the previous note finishes, that lasts for 0.232 seconds
playNote(659.255, context.currentTime + 0.116, 0.232);

Ах, сладкий звук успеха.

Помните, что если вы не любите играть с осцилляторами, вместо этого вы можете использовать mp3-файл. Прочитайте предыдущий урок, чтобы увидеть как.

Лучше всего playNote эти два playNote в один вызов функции, чтобы у нас был простой способ воспроизвести наш звук.

1
2
3
4
5
6
7
var playSuccessSound = function () {
    // Play a ‘B’ now that lasts for 0.116 seconds
    playNote(493.883, context.currentTime, 0.116);
 
    // Play an ‘E’ just as the previous note finishes, that lasts for 0.232 seconds
    playNote(659.255, context.currentTime + 0.116, 0.232);
};

Теперь вам решать, как вы хотите активировать этот звук и какое событие вы хотите воспроизвести в ответ. Для целей этого урока. давайте подделаем Ajax-вызов, который занимает три секунды. Мы будем использовать это, чтобы сделать вид, что происходит какая-то серверная транзакция.

1
2
3
4
5
var myFakeAjaxCall = function (callback) {
    setTimeout(function () {
        callback();
    }, 3000);
};

Все, что нам нужно сделать сейчас, это добавить прослушиватель событий к нашей кнопке «Купить сейчас».

1
2
3
4
5
$(‘#buy-now-button’).click(function () {
    myFakeAjaxCall(function () {
        playSuccessSound();
    });
});

Нажмите кнопку, подождите три секунды, а затем потанцуйте с радостью, услышав звуковое подтверждение того, что ваша транзакция прошла успешно.

Чтобы изменить текст на кнопке, чтобы визуально указать, что что-то произошло, Bootstrap предоставляет некоторые вспомогательные функции кнопки для замены текста, предоставленного в атрибуте данных. Как это работает, выходит за рамки данной статьи, но вот код для полноты.

1
2
3
4
5
6
7
8
9
$(‘#buy-now-button’).click(function () {
    var that = this,
        $btn = $(this).button(‘loading’);
 
    myFakeAjaxCall(function () {
        playSuccessSound();
        $btn.button(‘complete’);
    });
});

Я надеюсь, что вы нашли этот учебник полезным и что вам рекомендуется добавлять звук (ответственно!) В ваше веб-приложение. Код для этого урока на GitHub , а также демонстрация нашего финального звука . Следующий урок из этой серии предназначен для тех из вас, кто поймал ошибку генератора; мы будем строить веб-аудио синтезатор.