On my never-ending search for new things to try, I wanted to see if a browser could play music. A simple Google search brought me to the Web Audio API.
Web Audio API
First a Web Audio API Context object needs to be made as so
Sound is basically a waveform of some frequency. The pleasant sounding notes of a piano are just certain specific frequencies.
Without going into much depth, the first thing one needs is an OscillatorNode. An OscillatorNode basically represents a periodic waveform, like a sine wave or a square wave. It can be made using the
createOscillator method of an
AudioContext. Here’s an example
AudioContext is then linked to an input for a destination such as headphones or a speaker and the
OscillatorNode is connected to it.
This will simply play a 1000 Hz tone which can be stopped using
Seeing all this I had an idea to make the browser play a random tune selecting from notes of certain frequencies. However this leads to several pitfalls.
When you reuse an oscillator object for different notes, the frequency transition causes an audible sliding noise. The solution is to use different oscillators for each note played.
The second issue is that you may notice a clipping sound when you end the note. This might not seem like much of an issue but will definitely cause problems when many notes are played back to back relatively quickly. Here’s a demo.
Band.js is a library based on the Web Audio API which makes playing rhythmic notes and different time signatures very easy. It’s greatest advantage over the bare API is the ease of timing notes. Here’s a nice tutorial I found on Band.js.
To set a tempo, all you have to do is
Then you make an “instrument” using the
createInstrument() method and adding notes is as simple as using the
note() method. It has the time and key as arguments.
Once that is done, we let Band.js know the music is finished after which we can play, pause or stop it.
The first approach was to play the notes at random. I chose all the major notes of the 4th quadrant and played each as a quarter note. It worked but sounded a bit too random.
Then I assigned weights (probabilities of being played next) to each of the notes depending on the current note being played. For example, if the current note being played is F, then E and G will have the most weight and it decreases as we go further from the current note. This sounds much better as there is often a continuous string of notes being played rather than random jumps. The timing is also chosen at random between a quarter note and eighth note.