FM-Synthesis in the Browser. Part 1

sss10241 pts0 comments

FM-Synthesis in the Browser. Part 1 / Habr

Pull to refresh

ZvoogHub Jun 29 at 13:59

FM-Synthesis in the Browser. Part 1<br>Level of difficultyHard<br>Reading time8 min<br>Reach and readers2.5K<br>Sound

Tutorial

Let’s explore the possibilities of sound synthesis in browsers. We’ll explore the basics and, as a practical example, create a Yamaha DX7 synthesizer emulator.<br>Web Audio API<br>Browsers allow you to call JavaScript objects to control and create sound. Documentation: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API<br>The API provides components for creating and modifying audio signals. These components can be connected together, and their properties can be changed on a schedule.<br>Hello World!<br>Let’s look at a simple example, something like the standard “Hello World!” for programming languages.<br>Example HTML page code with explanatory comments.<br>beep

function start() {<br>let audioContext = new AudioContext();//create the main object<br>let when = audioContext.currentTime + 0.1;//start time<br>let beep = audioContext.createOscillator();//beep object<br>beep.frequency.value = 440;//frequency of note A<br>beep.connect(audioContext.destination);//send sound to the output<br>beep.start(when);//start sound<br>beep.stop(when + 1);//stop sound after 1 second

Open the page https://mzxbox.ru/fmsynth/beep.html in your browser and listen to the sound signal.<br>Sound envelope<br>If you pluck a guitar string or press a piano key, you’ll notice the difference between the natural sound and the computer-generated sound. The key’s sound increases in volume at the moment you press it and gradually fades over time. In synthesizers, this effect is achieved by adjusting the ADSR envelope:<br>More - https://en.wikipedia.org/wiki/ADSR<br>Let’s expand on our previous example and add an envelope. Here’s the component connection diagram:<br>Example code with comments<br>beep AHDSR

function start() {<br>let audioContext = new AudioContext();//create the main object<br>let when = audioContext.currentTime + 0.1;//start time<br>let beep = audioContext.createOscillator();//beep object<br>let envelope = audioContext.createGain();//gain node to set envelope of sound

beep.frequency.value = 440;//частота ноты Ля

envelope.gain.setValueAtTime(0, when);//0 at begining<br>envelope.gain.linearRampToValueAtTime(1, when + 0.05);//gradually increase to 1 in 0.5 sec<br>envelope.gain.linearRampToValueAtTime(0.5, when + 0.2);//reduce to 0.5 in 0.2 s<br>envelope.gain.setValueAtTime(0.5, when + 0.99);//setup last volume value<br>envelope.gain.linearRampToValueAtTime(0, when + 1);//reduce to 0 at end

envelope.connect(audioContext.destination);//send final sound to output<br>beep.connect(envelope);//send beep sound to envelope cahnger

beep.start(when);<br>beep.stop(when + 1);

Open the page https://mzxbox.ru/fmsynth/envelope.html in your browser - the sound will be smooth, louder at the beginning and quieter at the end.<br>Modulation of sound signal<br>Audio modulation is the process of modifying a carrier signal using a modulator signal. More information can be found at: https://en.wikipedia.org/wiki/Modulation<br>Amplitude modulation is a type of modulation in which the variable parameter of the carrier signal is its amplitude.<br>Frequency modulation is a type of analog modulation in which the modulating signal controls the frequency of the carrier wave. Compared to amplitude modulation, the amplitude remains constant.<br>Amplitude modulation<br>Sound from a modulator connected to the gain parameter of a node whose input is connected to a carrier:<br>Code example<br>Amplitude modulation

function start() {<br>let audioContext = new AudioContext();<br>let when = audioContext.currentTime + 0.1;

let carrier = audioContext.createOscillator();<br>let modulator = audioContext.createOscillator();<br>let result = audioContext.createGain();<br>let level = audioContext.createGain();

carrier.frequency.value = 500;<br>modulator.frequency.value = 4;<br>level.gain.value = 0.5;//reduce to 0.5<br>result.gain.value = 0.5;//shift to 0.5

modulator.connect(level);<br>level.connect(result.gain);<br>carrier.connect(result);<br>result.connect(audioContext.destination);

carrier.start(when);<br>modulator.start(when);

carrier.stop(when + 2);<br>modulator.stop(when + 2);

The generator produces a sine wave signal [-1; +1], but the volume should change as [0; +1] - therefore, additional transformations are required.<br>Open the page to listen to the sound https://mzxbox.ru/fmsynth/amplitude.html<br>Frequency modulation<br>Connection mix:<br>Code example<br>frequency modulation

function start() {<br>let audioContext = new AudioContext();<br>let when = audioContext.currentTime + 0.1;

let carrier = audioContext.createOscillator();<br>let modulator = audioContext.createOscillator();<br>let level = audioContext.createGain();

modulator.frequency.value = 4;<br>level.gain.value = 200;<br>carrier.frequency.value = 300;

carrier.connect(audioContext.destination);<br>level.connect(carrier.frequency);<br>modulator.connect(level);

carrier.start(when);<br>modulator.start(when);

carrier.stop(when + 2);<br>modulator.stop(when + 2);

Open the page...

audiocontext sound beep carrier envelope start

Related Articles