Я в процессе создания синтезатора бас-барабана с использованием Web Audio API. Мне удалось заставить кнопку запускать функцию, которая генерирует синусоидальную волну с изменением высоты тона и громкости, но кнопка, похоже, работает только один раз, и при повторном нажатии звук не воспроизводится с начала.
const audioCtx = new AudioContext(); // Инициализация аудиоконтекста
const osc = audioCtx.createOscillator(); // Создание осциллятора
const volume = audioCtx.createGain(); // Создание усилителя
osc.type = "sine"; // Установка типа исходной формы волны
osc.frequency.value = 440; // Установка частоты осциллятора
osc.start(); // Начать воспроизведение осциллятора
osc.connect(volume); // Установка назначения для осциллятора
function generateKick() {
volume.gain.value = 1;
osc.frequency.setTargetAtTime(22, 0, 0.1);
volume.gain.setTargetAtTime(0, audioCtx.currentTime, 0.1);
volume.connect(audioCtx.destination);
}
Как я могу изменить свою функцию так, чтобы каждый раз при нажатии кнопки звук начинался с начала и звучал одинаково?
Я пытался вставить функцию osc.start()
внутрь своей функции, но это не сработало, так как функция .start()
не может быть вызвана более одного раза.
Я не эксперт в Web Audio, но использование setValueAtTime
для сброса громкости и частоты перед каждым вызовом setTargetAtTime
похоже, решает проблему (я также вынес volume.connect
за пределы функции, чтобы она выполнялась только один раз):
const audioCtx = new AudioContext(); // Инициализация аудиоконтекста
const osc = audioCtx.createOscillator(); // Создание осциллятора
const volume = audioCtx.createGain(); // Создание усилителя
osc.type = "sine"; // Установка типа исходной формы волны
osc.frequency.value = 440; // Установка частоты осциллятора
osc.start(); // Начать воспроизведение осциллятора
osc.connect(volume); // Установка назначения для осциллятора
volume.gain.value = 0;
volume.connect(audioCtx.destination);
function generateKick() {
volume.gain.setValueAtTime(1, audioCtx.currentTime);
volume.gain.setTargetAtTime(0, audioCtx.currentTime, 0.1);
osc.frequency.setValueAtTime(440, audioCtx.currentTime);
osc.frequency.setTargetAtTime(22, audioCtx.currentTime, 0.1);
}
Ответ
Чтобы перезапустить осциллятор в Web Audio API каждый раз, когда вы нажимаете кнопку, нужно создавать новый осциллятор и новую цепь для подключения в вашей функции generateKick
. Ниже представлен исправленный код, который решает вашу проблему.
Исправленный код
const audioCtx = new AudioContext(); // Инициализация Audio Context
function generateKick() {
const osc = audioCtx.createOscillator(); // Создание нового осциллятора
const volume = audioCtx.createGain(); // Создание нового Gain
osc.type = "sine"; // Установка типа волны
osc.frequency.value = 440; // Установка начальной частоты осциллятора
volume.gain.setValueAtTime(1, audioCtx.currentTime); // Установка начальной громкости
volume.gain.setTargetAtTime(0, audioCtx.currentTime + 0.1, 0.1); // Установка целевой громкости для затухания
osc.frequency.setValueAtTime(440, audioCtx.currentTime); // Установка начальной частоты
osc.frequency.setTargetAtTime(22, audioCtx.currentTime + 0.1, 0.1); // Установка целевой частоты для сдвига
osc.connect(volume); // Подключение осциллятора к ganho
volume.connect(audioCtx.destination); // Подключение gain к выходу
osc.start(); // Запуск осциллятора
osc.stop(audioCtx.currentTime + 0.2); // Остановка осциллятора через 0.2 секунды
}
// Пример кнопки (не забудьте добавить HTML-код для кнопки)
document.getElementById('kickButton').addEventListener('click', generateKick);
Объяснение кода:
-
Создание нового осциллятора: Каждый раз, когда вызывается функция
generateKick
, создается новый экземпляр осциллятора и объектаGain
. Это позволяет заново инициализировать все параметры звука. -
Установка громкости и частоты: Значения громкости и частоты настраиваются перед их изменением с помощью
setTargetAtTime
, чтобы создать нужный эффект. -
Подключение: Осциллятор подключается к объекту
Gain
, который затем подключается к выходу звука. - Автоостановка: Исключительно для того, чтобы звук не продолжался бесконечно, осциллятор останавливается через 0.2 секунды после начала.
Как использовать:
Добавьте кнопку в HTML с ID kickButton
и свяжите её с функцией generateKick
, как показано в примере. Этот подход позволяет каждому клику запускать новый экземпляр осциллятора, обеспечивая, чтобы каждый клик создавал новый звук, начиная с начала.