Synthesizing Musical Sounds with Web Audio API – Part 2

Web Audio API is a system for creating, controlling, and manipulating audio in a Web browser using JavaScript.

This series of articles is intended to demonstrate the basic concepts needed to synthesize musical sounds using Web Audio API.

In part 1 of this series, we created a Web page and JavaScript code to start and stop playing a tone and to add a very short fade-in and fade-out to make the start less abrupt and prevent annoying click/pop sounds when stopping.

With that code, the tone is always at 440 Hz (Middle A) and is always a sine wave, which is a simple, pure timbre with no overtones. Now, let’s update the code to let us play tones with different frequencies and timbres.

Now, you can change the shape of the wave to be any of sine, square, sawtooth, or triangle, and you can change the frequency in a range from 20 Hz to 20000 Hz (20 kHz) which is roughly the human hearing range.

If you check the documentation for the type parameter of OscillatorNode, you will notice that there is also a “custom” value that we have not included as a selection. That value is used in conjunction with the setPeriodicWave() method to define a custom waveform, and you can read the documentation for more details on how to use that.

Like the gain property of a GainNode, the frequency property of an OscillatorNode  is a reference to an AudioParam, so we don’t assign directly to it. We’re changing the frequency value immediately though and not trying to gradually change it from one to value another, so we can simply assign to frequency’s value  property rather than scheduling a change as we did with the gain.

At this point, we’re dealing with pitch only in terms of frequency, but that’s not very useful for creating music. We generally talk abut musical pitch in terms of notes in a musical scale.

In Western music, we usually are working with an equal-tempered 12-tone scale. “Equal tempered” means that the ratio between frequencies of any 2 consecutive notes is the same as between any other consecutive notes, and 12-tone means there are 12 notes in a scale that spans 1 octave. An interval of 1 octave represents a doubling of the frequency, so with Middle A at 440 Hz, the A above Middle A is 880 Hz, and the A below Middle A is 220 Hz. The upshot of all of this is that the ratio between any consecutive notes in an equal-tempered, 12-tone scale is the 12th root of 2.

Here is an update to the code that allows the pitch to be selected in terms of octave numbers and named note values.

You have probably noticed that the sound is much louder with some of the waveforms (particularly Square and Sawtooth) than others. This is not due to any problem or bug. It is due to the fact that those waveforms have a lot more intensity than others at the same amplitude.

Any waveform can be treated as the sum of one or more sine waves, and each of those sine waves has a particular intensity depending on its amplitude and pitch. Square and sawtooth waves contain a lot of intense overtones (sine waves at multiples of the fundamental frequency) so they sound louder than the other waveforms.

That leads us to the topic of filtering which will be covered in part 3 part of this series.


Synthesizing Musical Sounds with Web Audio API – Part 1

Web Audio API is a system for creating, controlling, and manipulating audio in a Web browser using JavaScript.

This series of articles is intended to demonstrate the basic concepts needed to synthesize musical sounds using Web Audio API.

Let’s start out by simply starting and stopping the sounding of a tone.

If you open this in a browser and click the “On” radio button, you should hear a tone, and the tone should stop when you click the “Off” radio button. Although there is nothing in this code to say what timbre (waveform, kind) of sound to make or at what pitch, the sound we hear is a sine wave at 440 Hz (Middle A). That is because of the default values of the type and frequency properties for an OscillatorNode which are “sine” and 440 respectively.

If you start and stop the tone a few times, you will probably notice an unpleasant click/pop sound sometimes when you turn the tone off. Also, although there is not a click or pop at the start of the tone, it does start very abruptly. We’ll deal with those issues, but first, let’s dig into what this code is doing so far.

Before the first time the tone is sounded, we have to create an AudioContext object. Everything else that we do is in relation to this context. Using that, we then create an OscillatorNode that will generate the sound that we’re going to hear. The browser routes audio signals to the computer’s speakers through the destination property of the audio context, so to allow the oscillator’s output to be heard, we connect it to that.

Finally, we call the start method of the oscillator so that it starts producing a tone.

When the tone is playing, we can then stop it by simply calling the stop method of the oscillator.

Notice that we clear the reference to the oscillator after we stop the tone, and we create a new oscillator to play the tone again to re-start it. You may ask why don’t we just keep one oscillator around and start it again. That is because an OscillatorNode object is actually intended to be used one time and then discarded and can only be started and stopped once. It cannot be used to make sound again after its stop method has been called.

Now, getting back to that click when stopping the oscillator. That happens because the oscillator has been producing a smoothly changing sine wave as output, and we stop it at an arbitrary moment in the middle of a wave cycle. Similarly, even though the start of the tone will happen at at beginning of a wave, it is an abrupt start, jumping immediately to full volume.

We can solve both of those problems by adding a short fade-in at when starting the tone and fade-out when stopping the tone.

Since an oscillator provides no way to control its volume directly, we route it through a GainNode.

We can control the amount of gain using the GainNode’s gain property. The gain property is not simply a value though. It refers to an AudioParam object. The AudioParam object has a value property, but if any of the time-based methods are being used with an AudioParam (as we are doing here) then it’s usually best to use only those methods and not the value property.

The context has a currentTime value which is a floating point number of seconds since the context was started, and all the time values we pass to methods of objects associated with that context are with respect to that. Since the JavaScript code itself takes a non-zero amount time to run, we generally want to schedule everything at least a tiny bit into the future by adding a fraction of a second to the current time. Note that we can schedule parameter changes in the past (including at time 0) and the result of that is that the current value jumps to what it would be now if that had actually happened as scheduled.

For starting the tone, we set the gain to 0.0 at time 0, and then we also set the gain to 0.0 at a time slightly into the future. That becomes the starting time and value for the subsequent ramp up. We then ramp the value up to 1.0 ending at a time slightly farther into the future. That gives us a gentle rise to maximum volume so the start is not so abrupt.

For ending the tone, we essentially do the same thing in reverse. The gain was ramped up to 1.0 when the tone was started, so we set it to 1.0 again at a point slightly in the future to be the starting point for ramping down to 0.0. We then ramp the value down to 0.0 ending at a point slightly farther into the future. We don’t want to stop the oscillator until its gain has been ramped all the way down, so we schedule the stop to happen at the same time as the end of the ramp-down. This eliminates that nasty click that we previously could have when stopping the tone.

The oscillator has an onended event handler property, and we use that to schedule the cleanup of the oscillator-related references after we’re completely done with them.

You might have noticed that there’s a bigger delay before starting the ramp-down for stopping the tone than there is before starting the ramp-up for starting it. This is to make sure that if the tone is started and stopped quickly, it has had time to ramp all the way up before we set it to 1.0 to start the ramp-down. There is possibly a better way to handle that in the form of AudioParam.cancelAndHoldAtTime(), but as of this writing, that is still “experimental technology”.

In part 2 of this series, we will explore how to control the pitch and timbre of the tone.


How To Compute 1+2+…+n and How to Remember How

I was recently writing a test for an object containing a map of currency amounts for months by month number. I needed to verify that each value was exposed through a month-specific attribute and that it exposed the sum of values across all the months through another attribute.

For test data, I chose the following map:

Obviously, those 12 thousands add up to 12,000, but what is the contribution of those 1–to–12 parts? I could have just added the numbers together, but there’s an easier way.

That easier way is the formula 12 ⨉ 13 / 2 or more generally, n ⨉ (n + 1) / 2, and in the case above, that’s 78, but how do I remember that formula? This is something I need to know somewhat often, but not quite often enough to simply have the formula memorized. The way that I remember how to re–create this formula quickly when I need it is with a nifty visual mnemonic that I’d like to share. For this example, we’ll say that n is equal to 4.


The black squares (the ones we count) form a triangle, and the white squares (the ones we don’t count) form an identical triangle rotated 180 degrees. If we stick those triangles together as shown, we get a 4 x 5 rectangle, and since each triangle in the rectangle has the same number of squares, that means half of the squares in the rectangle are black.

Curious Effects of Different Ruby Class & Module Nesting Styles

Typically, in Ruby, we see modules and classes nested by having one declaration inside of the the other.

When the outer class or module has previously been declared, however, we can also declare the nested one directly using its fully qualified name, and it is not uncommon to see that done.

On the surface, these seem to be 2 ways to do exactly the same thing, and for the most part they are. They are not doing exactly the same thing, however, and that can result in some interesting side effects. We start to see those effects when methods methods defined within our declarations make reference to constants.

As you can see, each of the instance methods of Foo::Bar  is accessing constants from a different level of nesting.

What’s going on is that the nesting with respect to an executing method belongs to the method itself and not the class or module on which it is defined. The source of that nesting is nesting of class  and module  code blocks at the point where the method was defined.

The side effects of this can get positively weird.

Say what? The hello  instance method cannot even reference its own class using an unqualified name? That is because the Bar  constant belongs to the Foo  module, but since the method was not defined within a module Foo  block, its constants (including Bar ) are not implicitly available.