Веб

Использование AudioContext для создания звуков музыкальных инструментов

Пошаговое руководство по созданию звуков пианино, флейты и других инструментов с помощью Web Audio API и Tone.js. Примеры кода и лучшие практики.

5 ответов 1 просмотр

Как использовать Javascript AudioContext для воспроизведения звуков, похожих на музыкальные инструменты?

Я могу воспроизводить простые тоны с помощью приведенного ниже кода. Но как можно генерировать звуки, похожие на музыкальные инструменты (пианино, флейта и т.д.)?

javascript
function playTone(freq, duration, delay = 0) {
 const osc = ctx.createOscillator();
 osc.type = "sine";
 osc.frequency.value = freq;
 const gain = ctx.createGain();
 gain.gain.setValueAtTime(0.2, ctx.currentTime + delay);
 osc.connect(gain).connect(ctx.destination);
 osc.start(ctx.currentTime + delay);
 osc.stop(ctx.currentTime + delay + duration);
}

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


Содержание


Введение в Web Audio API для синтеза звуков музыкальных инструментов

Web Audio API предоставляет мощные инструменты для создания и обработки звука в браузере. Основная концепция revolves around audio nodes that can be connected to form an audio processing graph. Для имитации музыкальных инструментов нам нужно создать сложную цепочку обработки звука, которая включает генерацию сигнала, его модуляцию и обработку.

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


Использование OscillatorNode и типов волн для создания инструментальных звуков

Для создания звука музыкального инструмента начнем с OscillatorNode. Хотя простые типы волн вроде sine, square, sawtooth и triangle могут дать нам базовые тона, они не звучат как реальные инструменты. Чтобы получить более реалистичный звук, нам нужно:

javascript
// Создание сложной волны с заданными гармониками
const real = new Float32Array([1, 0.5, 0.25, 0.125]); // Коэффициенты косинусных компонент
const imag = new Float32Array([0, 0.25, 0.1, 0.05]); // Коэффициенты синусных компонент
const wave = ctx.createPeriodicWave(real, imag);

// Использование этой волны в осцилляторе
const osc = ctx.createOscillator();
osc.setPeriodicWave(wave);
osc.frequency.value = 440; // A4

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


Применение ADSR-окна и фильтров для реалистичного звучания

Простые тоны звучат искусственно потому, что они не имеют характерной динамики. Для реалистичного звучания нам нужно реализовать ADSR-окно (Attack, Decay, Sustain, Release):

javascript
function playInstrumentalTone(freq, duration) {
 const osc = ctx.createOscillator();
 const gain = ctx.createGain();
 
 // Создание сложной волны для инструмента
 const real = new Float32Array([0.5, 0.25, 0.1, 0.05]);
 const imag = new Float32Array([0, 0.1, 0.05, 0.02]);
 const wave = ctx.createPeriodicWave(real, imag);
 osc.setPeriodicWave(wave);
 osc.frequency.value = freq;
 
 // ADSR-окно
 const now = ctx.currentTime;
 gain.gain.setValueAtTime(0, now);
 gain.gain.linearRampToValueAtTime(0.8, now + 0.01); // Attack
 gain.gain.linearRampToValueAtTime(0.5, now + 0.1); // Decay
 gain.gain.setValueAtTime(0.5, now + duration - 0.1); // Sustain
 gain.gain.linearRampToValueAtTime(0, now + duration); // Release
 
 osc.connect(gain).connect(ctx.destination);
 osc.start(now);
 osc.stop(now + duration);
}

Дополнительно можно использовать BiquadFilterNode для добавления тембральных особенностей:

javascript
const filter = ctx.createBiquadFilter();
filter.type = "lowpass";
filter.frequency.value = 2000;
filter.Q.value = 5;
gain.connect(filter).connect(ctx.destination);

Библиотека Tone.js: упрощение создания инструментальных звуков

Ручная реализация инструментальных звуков требует глубоких знаний и много кода. Tone.js предлагает готовые решения:

javascript
// Инициализация Tone.js
const synth = new Tone.Synth().toDestination();
const fmSynth = new Tone.FMSynth().toDestination();
const sampler = new Tone.Sampler({
 urls: {
 C4: "C4.mp3",
 D4: "D4.mp3",
 E4: "E4.mp3",
 F4: "F4.mp3",
 G4: "G4.mp3",
 A4: "A4.mp3",
 B4: "B4.mp3",
 C5: "C5.mp3"
 },
 baseUrl: "https://tonejs.github.io/audio/salamander/"
}).toDestination();

// Воспроизведение разных звуков
function playPiano(note, duration) {
 sampler.triggerAttackRelease(note, duration);
}

function playFlute(note, duration) {
 fmSynth.triggerAttackRelease(note, duration);
}

function playSynth(note, duration) {
 synth.triggerAttackRelease(note, duration);
}

Tone.js предоставляет готовые синтезаторы:

  • Tone.Synth - для пианино и клавишных
  • Tone.FMSynth - для духовых инструментов вроде флейты
  • Tone.PolySynth - для полифонических звуков
  • Tone.Sampler - для воспроизведения сэмплов реальных инструментов

Примеры реализации звуков пианино и флейты

Реализация пианино с сэмплами

javascript
// Загрузка сэмплов пианино
const pianoSampler = new Tone.Sampler({
 urls: {
 C4: "piano/C4.mp3",
 C#4: "piano/Csharp4.mp3",
 D4: "piano/D4.mp3",
 // ... все ноты
 }
}).toDestination();

function playPianoNote(note, velocity = 0.8) {
 pianoSampler.triggerAttackRelease(note, "8n", undefined, velocity);
}

// Пример использования
playPianoNote("C4"); // До
playPianoNote("E4"); // Ми
playPianoNote("G4"); // Соль

Реализация флейты с ФМ-синтезом

javascript
// Настройка ФМ-синтезатора для флейты
const fluteSynth = new Tone.FMSynth({
 harmonicity: 3.01,
 modulationIndex: 14,
 detune: 0,
 portamento: 0.05,
 oscillator: {
 type: "sine"
 },
 envelope: {
 attack: 0.1,
 decay: 0.2,
 sustain: 0.8,
 release: 1.2
 },
 modulation: {
 type: "sine",
 envelope: {
 attack: 0.01,
 decay: 0.2,
 sustain: 0.8,
 release: 1.2
 }
 }
}).toDestination();

function playFluteNote(note) {
 fluteSynth.triggerAttackRelease(note, "8n");
}

// Пример мелодии
const melody = ["C5", "D5", "E5", "F5", "E5", "D5", "C5"];
melody.forEach((note, i) => {
 setTimeout(() => playFluteNote(note), i * 300);
});

Комплексный пример: создадим собственный инструмент

javascript
class Instrument {
 constructor(audioContext) {
 this.ctx = audioContext;
 this.masterGain = audioContext.createGain();
 this.masterGain.connect(audioContext.destination);
 this.masterGain.gain.value = 0.3;
 }
 
 // Для духовых инструментов
 createWindInstrument(fundamentalFreq) {
 const osc = this.ctx.createOscillator();
 const gain = this.ctx.createGain();
 const filter = this.ctx.createBiquadFilter();
 
 // Настройки для флейты
 filter.type = "lowpass";
 filter.frequency.value = 3000;
 filter.Q.value = 10;
 
 // ADSR для плавного звучания
 const now = this.ctx.currentTime;
 gain.gain.setValueAtTime(0, now);
 gain.gain.linearRampToValueAtTime(0.7, now + 0.1);
 gain.gain.setValueAtTime(0.5, now + 0.5);
 gain.gain.linearRampToValueAtTime(0, now + 2);
 
 osc.frequency.value = fundamentalFreq;
 osc.type = "sine";
 
 osc.connect(gain);
 gain.connect(filter);
 filter.connect(this.masterGain);
 
 osc.start();
 osc.stop(now + 2);
 }
 
 // Для ударных инструментов
 createDrumSound(frequency = 100) {
 const noise = this.ctx.createBufferSource();
 const buffer = this.ctx.createBuffer(1, this.ctx.sampleRate * 0.2, this.ctx.sampleRate);
 const data = buffer.getChannelData(0);
 
 // Создание белого шума
 for (let i = 0; i < buffer.length; i++) {
 data[i] = Math.random() * 2 - 1;
 }
 
 noise.buffer = buffer;
 
 const filter = this.ctx.createBiquadFilter();
 filter.type = "highpass";
 filter.frequency.value = frequency;
 
 const gain = this.ctx.createGain();
 const now = this.ctx.currentTime;
 gain.gain.setValueAtTime(1, now);
 gain.gain.exponentialRampToValueAtTime(0.01, now + 0.2);
 
 noise.connect(filter);
 filter.connect(gain);
 gain.connect(this.ctx.destination);
 
 noise.start();
 }
}

// Использование
const instrument = new Instrument(ctx);
instrument.createWindInstrument(523.25); // C5
setTimeout(() => instrument.createDrumSound(150), 500);

Заключение и дополнительные ресурсы

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

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


Источники

  1. MDN Web Docs — Документация по Web Audio API и OscillatorNode: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
  2. Tone.js Documentation — Руководство по созданию музыкальных инструментов: https://tonejs.github.io/
  3. MDN Web Docs — Руководство по BiquadFilterNode для обработки звука: https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
  4. MDN Web Docs — Примеры использования PeriodicWave для создания сложных звуков: https://developer.mozilla.org/en-US/docs/Web/API/OscillatorNode/setPeriodicWave
  5. GitHub MDN Web Audio Examples — Примеры кода для изучения синтеза звука: https://github.com/mdn/webaudio-examples
M

Для создания звуков, похожих на музыкальные инструменты, в Web Audio API обычно используют OscillatorNode с разными типами волн, а также Envelope (GainNode) и фильтры (BiquadFilterNode). Можно создать собственный PeriodicWave, чтобы имитировать характерные гармоники инструмента, и применить LFO для вибрации. Кроме того, можно загружать предварительно записанные аудиофайлы через AudioBufferSourceNode и обрабатывать их с помощью эффектов. Для упрощения разработки существуют библиотеки, например Tone.js, которые предоставляют готовые синтезаторы и инструменты.

M

Для генерации звуков, напоминающих музыкальные инструменты, в Web Audio API обычно используют OscillatorNode в сочетании с GainNode и, при необходимости, PeriodicWave. Чтобы получить более «инструментальный» звук, можно использовать setPeriodicWave с пользовательским спектром, а также применять GainNode для создания ADSR-октавы. Для более сложных звуков, как у пианино или флейты, можно комбинировать несколько осцилляторов, использовать PeriodicWave для создания гармоник и применять GainNode для имитации атаки, тела и релиза.

Tone.js / JavaScript библиотека

В Tone.js удобно использовать готовые синтезаторы: Tone.Synth (простой синтезатор), Tone.FMSynth (ФМ-синтезатор), Tone.PolySynth (полифонический синтезатор), Tone.Sampler (сэмплер), Tone.Player (плейер). Библиотека Tone.js предоставляет методы triggerAttackRelease() для управления воспроизведением звуков и Tone.getTransport() для синхронизации. Для создания реалистичных звуков пианино лучше использовать Tone.Sampler, который загружает аудиофайлы и автоматически меняет высоту. Для флейты можно использовать Tone.FMSynth, который позволяет получить более сложные, «птицы-пахучие» тоны.

G

В репозитории MDN webaudio-examples содержатся примеры кода для изучения Web Audio API, включая audio-analyser, audio-basics, audio-buffer, audio-param, audio-context-states, audioworklet и другие. Особый интерес представляет пример Violent Theremin, который демонстрирует, как с помощью Web Audio API можно моделировать музыкальные инструменты с помощью мыши. Эти примеры помогут вам освоить основные концепции синтеза звука и применить их для создания собственных инструментальных звуков.

Авторы
M
Разработчики
G
Разработчики
Источники
MDN Web Docs / Документационный портал
Документационный портал
Tone.js / JavaScript библиотека
JavaScript библиотека
GitHub / Платформа разработки
Платформа разработки
Проверено модерацией
НейроОтветы
Модерация