Управление несколькими параметрами с помощью ConstantSourceNode
В этой статье показано, как использовать ConstantSourceNode для связывания нескольких параметров, чтобы они имели одно и то же значение, которое можно изменить, установив значение параметра ConstantSourceNode.offset.
Иногда вам может потребоваться связать несколько аудиопараметров, чтобы они имели одно и то же значение, которое каким-то образом изменяется. Например, у вас есть набор осцилляторов, два из которых должны иметь одинаковую настраиваемую громкость, или у вас есть фильтр, применяемый к определённым входам, но не ко всем. Вы можете использовать цикл и изменять значение каждого затронутого AudioParam по одному. Однако у этого подхода есть два недостатка: во-первых, это дополнительный код, которого, как вы сейчас увидите, писать не нужно; во-вторых, этот цикл использует ценное время ЦП на вашем потоке (вероятно, главном потоке), и есть способ переложить всю эту работу на поток аудиорендеринга, который оптимизирован для этой работы и может работать на уровне приоритета, более подходящем для вашего кода.
Решение простое, и оно включает в себя использование типа аудиоузла, который, на первый взгляд, не выглядит особо полезным: ConstantSourceNode.
Методика
Использование ConstantSourceNode — это простой способ сделать то, что кажется сложным. Вам необходимо создать ConstantSourceNode и подключить его ко всем AudioParam, значения которых должны быть связаны и всегда совпадать. Поскольку значение offset ConstantSourceNode передаётся напрямую на все его выходы, он действует как разделитель для этого значения, отправляя его каждому подключенному параметру.
На диаграмме ниже показано, как это работает; входное значение, N, устанавливается в качестве значения свойства ConstantSourceNode.offset. ConstantSourceNode может иметь любое количество выходов; в данном случае мы подключили его к трём узлам: двум GainNode и StereoPannerNode. Таким образом, N становится значением указанного параметра (gain для GainNode и панорамирования для StereoPannerNode.
В результате каждый раз, когда вы изменяете N (значение входного AudioParam), значения двух свойств GainNode.gain и значение свойства StereoPannerNode свойства pan также устанавливаются в N.
Пример
Давайте рассмотрим эту технику в действии. В этом простом примере мы создаём три объекта OscillatorNode. Два из них имеют регулируемую громкость, управляемую с помощью общего входного управления. Другой осциллятор имеет фиксированную громкость.
HTML
Контент HTML для этого примера в основном представляет собой флажок, оформленный как кнопка, для включения и выключения тонов осциллятора, и элемент <input> типа range для управления громкостью двух из трёх осцилляторов.
<div class="controls">
<input type="checkbox" id="playButton">
<label for="playButton">Activate: </label>
<label for="volumeControl">Volume: </label>
<input type="range" min="0.0" max="1.0" step="0.01"
value="0.8" name="volume" id="volumeControl">
</div>
</div>
<p>Toggle the checkbox above to start and stop the tones, and use the volume control to
change the volume of the notes E and G in the chord.</p>
JavaScript
Теперь давайте рассмотрим код JavaScript, по частям.
Настройка
Начнем с инициализации глобальных переменных.
// Useful UI elements
const playButton = document.querySelector("#playButton");
const volumeControl = document.querySelector("#volumeControl");
// The audio context and the node will be initialized after the first request
let context = null;
let oscNode1 = null;
let oscNode2 = null;
let oscNode3 = null;
let constantNode = null;
let gainNode1 = null;
let gainNode2 = null;
let gainNode3 = null;
Эти переменные:
context-
Контекст
AudioContext, в котором хранятся все аудио узлы; он будет инициализирован после действия пользователя. -
Ссылки на элементы кнопки воспроизведения и регулятора громкости.
oscNode1,oscNode2, иoscNode3-
Три
OscillatorNode, используемые для генерации аккорда. gainNode1,gainNode2, иgainNode3-
Три экземпляра
GainNode, которые обеспечивают уровни громкости для каждого из трех осцилляторов.gainNode2иgainNode3будут связаны вместе для использования одного настраиваемого значения с помощьюConstantSourceNode. constantNode-
ConstantSourceNode, используемый для управления значениямиgainNode2иgainNode3вместе.
Теперь давайте посмотрим на функцию setup(), вызываемую, когда пользователь впервые включает кнопку воспроизведения; она выполняет все задачи инициализации для настройки аудио графа.
function setup() {
context = new AudioContext();
gainNode1 = new GainNode(context, {
gain: 0.5,
});
gainNode2 = new GainNode(context, {
gain: gainNode1.gain.value,
});
gainNode3 = new GainNode(context, {
gain: gainNode1.gain.value,
});
volumeControl.value = gainNode1.gain.value;
constantNode = new ConstantSourceNode(context, {
offset: volumeControl.value,
});
constantNode.connect(gainNode2.gain);
constantNode.connect(gainNode3.gain);
constantNode.start();
gainNode1.connect(context.destination);
gainNode2.connect(context.destination);
gainNode3.connect(context.destination);
// All is set up. We can hook the volume control.
volumeControl.addEventListener("input", changeVolume, false);
}
Сначала мы получаем доступ к AudioContext окна, сохраняя ссылку в context. Затем мы получаем ссылки на элементы управления, устанавливая playButton для ссылки на кнопку воспроизведения и volumeControl для ссылки на ползунок, который пользователь будет использовать для регулировки усиления связанной пары осцилляторов.
Далее создается GainNode gainNode1 для управления громкостью несвязанного осциллятора (oscNode1). Мы устанавливаем это усиление в 0,5. Мы также создаем gainNode2 и gainNode3, устанавливаем их значения для соответствия gainNode1, а затем устанавливаем значение ползунка громкости на то же значение, чтобы оно оставалось синхронизированным с уровнем усиления, которое он контролирует.
После создания всех узлов усиления мы создаем ConstantSourceNode, constantNode. Мы подключаем его выход к gain AudioParam на обоих gainNode2 и gainNode3, и мы запускаем узел постоянного значения, вызвав его метод start(); теперь он отправляет значение 0,5 в значения двух узлов усиления, и любое изменение constantNode.offset автоматически установит усиление как gainNode2 и gainNode3 (влияя на их аудио входы, как ожидается).
Наконец, мы подключаем все узлы усиления к AudioContext's destination, чтобы любой звук, подаваемый на узлы усиления, достигал выхода, будь то динамики, наушники, поток записи или любой другой тип назначения.
Затем мы назначаем обработчик для события input ползунка громкости (см. Управление связанными осцилляторами, чтобы увидеть очень короткую функцию changeVolume()).
Сразу после объявления функции setup() мы добавляем обработчик к событию change флажка воспроизведения (см. Включение и выключение осцилляторов для получения дополнительной информации о методе togglePlay()), и сценарий готов. Давайте посмотрим, как происходит действие.
playButton.addEventListener("change", togglePlay, false);
Включение и выключение осцилляторов
Поскольку OscillatorNode не поддерживает понятие приостановки, мы должны его смоделировать, завершая осцилляторы и перезапуская их, когда пользователь снова нажимает на флажок воспроизведения, чтобы включить их снова. Давайте посмотрим на код.
function togglePlay(event) {
if (!playButton.checked) {
stopOscillators();
} else {
// If it is the first start, initialize the audio graph
if (!context) {
setup();
}
startOscillators();
}
}
Если элемент управления playButton включен, осцилляторы уже воспроизводятся, и мы вызываем stopOscillators() для их остановки. См. Остановка осцилляторов ниже для этого кода.
Если элемент управления playButton включен, что указывает на то, что мы сейчас приостановили, мы вызываем startOscillators() для запуска осцилляторов, чтобы воспроизводить их тоны. Ниже мы опишем этот код в разделе Запуск осцилляторов.
Управление связанными осцилляторами
Функция changeVolume(), обработчик событий для ползунка регулировки громкости связанной пары осцилляторов, выглядит так:
function changeVolume(event) {
constantNode.offset.value = volumeControl.value;
}
Эта простая функция управляет усилением обоих узлов. Все, что нам нужно сделать, это установить значение параметра ConstantSourceNode's offset. Это значение становится постоянным выходным значением узла, подаваемым на все его выходы, gainNode2 и gainNode3.
Хотя это элементарный пример, представьте себе 32-х осцилляторный синтезатор с множеством связанных параметров, работающих через множество соединённых узлов. Сокращение числа операций для их регулировки будет очень полезным как для размера кода, так и для производительности.
Запуск осцилляторов
Когда пользователь нажимает на кнопку переключения воспроизведения/паузы, когда осцилляторы не воспроизводятся, вызывается функция startOscillators().
function startOscillators() {
oscNode1 = new OscillatorNode(context, {
type: "sine",
frequency: 261.625565300598634, // middle C$
});
oscNode1.connect(gainNode1);
oscNode2 = new OscillatorNode(context, {
type: "sine",
frequency: 329.627556912869929, // E
});
oscNode2.connect(gainNode2);
oscNode3 = new OscillatorNode(context, {
type: "sine",
frequency: 391.995435981749294, // G
});
oscNode3.connect(gainNode3);
oscNode1.start();
oscNode2.start();
oscNode3.start();
}
Каждый из трех осцилляторов настраивается одинаково, создавая OscillatorNode вызывая конструктор OscillatorNode() с двумя параметрами:
- Устанавливает
typeосциллятора на"sine"для использования синусоидальной волны в качестве аудио формы. - Устанавливает
frequencyосциллятора на нужное значение; в этом случаеoscNode1устанавливается на средний До, в то время какoscNode2иoscNode3дополняют аккорд, воспроизводя ноты Ми и Соль.
Затем мы подключаем новый осциллятор к соответствующему узлу усиления.
После создания всех трех осцилляторов они запускаются путем вызова метода ConstantSourceNode.start() каждого из них по очереди.
Остановка осцилляторов
Остановка осцилляторов, когда пользователь переключает состояние воспроизведения на паузу, так же просто, как остановка каждого узла.
function stopOscillators() {
oscNode1.stop();
oscNode2.stop();
oscNode3.stop();
}
Каждый узел останавливается путем вызова его метода ConstantSourceNode.stop().
Результат
См. также
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Controlling_multiple_parameters_with_ConstantSourceNode