In my Creating a Basic Synth in XNA 4.0 - Part II article I exemplified sound generation using a simple sine wave function. However, the sample video at the end of the article showed a bunch of different kinds of waves. Each of those types of waves are very common in sound synthesis, and were being generated by a simple class that I named Oscillator. I’ll be talking about the Oscillator class now.

OscillatorHud

In general terms, an oscillator is a mechanical or electronic device that generates a signal. The nature of the generated signal depends on how the oscillator is built. In most oscillators used by real synthesizers, the frequency of the signal is controlled by varying the voltage of its input. On the other hand, the amplitude of the generated signal is usually fixed, and has to be modified later using amplifiers or envelopes (something that I’ll talk about some other time).

In our case, since we’re emulating an oscillator in software, we can pretty much do whatever we want. We can specify whatever parameters we need to control the sound, and we’re under no obligiation to mimic how a real oscillator works. So the first think I did was go ahead and add two properties to directly control the amplitude and frequency of the signal.

public double Amplitude = 1.0;
public double Frequency = 440.0;

There. Another thing we need is a way to get the generated signal. In conformance with the interface described in my earlier article, I created a method to give me the amplitude of the signal for any given time:

public double GetSignal(double time);

Finally, I wanted my oscillator to support a few different types of waves. I created an enumeration of all types of waves I needed, and a property to hold what type of wave to use.

public enum WaveformTypes
{
    Sine,
    Triangle,
    Square,
    Sawtooth,
    Pulse,
    Noise
}

public WaveformTypes Waveform = WaveformTypes.Sine;

So, what’s with all these types of waves? Actually, these types of waves are special because they form the basis for the kind of synthesis we’ll be using - subtractive synthesis.

Subtractive Synthesis

There are more than one way to generate sounds. The one we’ll be using is called subtractive synthesis. It’s called this way because we start with a sound that contains all the required harmonic content for the final sound, and then remove any wanted frequencies from the sound with a filter, while shaping the sound’s volume with an envelope. This is usually viewed as a two step process, where each component is either a source (which generates the original sound) or a modifier (which changes the sound to our needs).

Right now we’re only interested in sources, because that’s what our oscillator is. Most sources used in subtractive synthesizers are based around mathematic concepts, such as waves - or as they’re commonly called, waveforms. There are a few types of waveforms present in almost any oscillator used for synthesizers:

Sine Sine

Triangle Triangle

Square Square

Sawtooth Sawtooth

Pulse Pulse

Noise Noise

Notes: The last one is actually not a waveform, but rather a random signal which contains a constantly changing mix of all frequencies. It is also frequently known as white noise. Another thing to notice is that the only difference between a square waveform and a pulse waveform is that the square waveform “switches” side exactly in the middle of its period, while the pulse wave can change earlier or later than that (this is controlled by a parameter known as duty cycle or pulse width). In fact a square waveform is simply a pulse waveform with a duty cycle of 50%.

Each of them sounds slightly different from the others, not only because of their shape, but because of the harmonics they contain. The theory behind it is a little complicated, so for now I would just experiment with each of them in order for the ear to become used to how they sound. You’ll realize for instance, that the triangle waveform sounds very soothing, while the sawtooth is much harsher.

Implementation

For the implementation of these waveforms, I simply looked up their mathematical formulas on wikipedia and translated them to code. Here’s the complete GetSignal method.

public double GetSignal(double time)
{
    switch (Waveform)
    {
        case WaveType.Sine:
        {
            return Math.Sin(Frequency * time * 2 * Math.PI) * Amplitude;
        }
        case WaveType.Triangle:
        {
            return Math.Abs(2 * (time * Frequency - Math.Floor(time * Frequency + 0.5))) * Amplitude * 2 - Amplitude;
        }
        case WaveType.Square:
        {
            return Math.Sin(Frequency * time * 2 * Math.PI) >= 0 ? Amplitude : -Amplitude;
        }
        case WaveType.Sawtooth:
        {
            return 2 * (time * Frequency - Math.Floor(time * Frequency + 0.5)) * Amplitude;
        }
        case WaveType.Pulse:
        {
            double period = 1.0 / Frequency;
            double timeModulusPeriod = time - Math.Floor(time / period) * period;
            double phase = timeModulusPeriod / period;
            if (phase <= DutyCycle)
                return Amplitude;
            else
                return -Amplitude;
        }
        case WaveType.Noise:
        {
            return (Rng.NextDouble() - Rng.NextDouble()) * Amplitude;
        }
    }
}

And I also added a parameter for controlling the duty cycle of pulse waves, which should always stay between 0 and 1:

public double DutyCycle = 0.5;

And a random number generation for generating the noise signal:

private static readonly Random Rng = new Random();

Usage

If you’ve looked at the sample source code of the previous article you can see how the oscillator class was used. Basically I created two Oscillator instances, one for the left and one for the right channel. When reading input from the keyboard I simply changed the oscillator parameters, and when generating the sound samples, I delegated that to the corresponding GetSignal method of the Oscillator class. That’s it!

Continue To Part III