Building a Simple Synthesizer

Introduction 

These tutorial uses the concept of very simple electronic music instruments to introduce some of the core concepts of synthesizing and processing audio in Pure Data. Those who are already familiar with audio synthesis should quickly grasp how it is done in PD, while those with no previous knowledge will be introduced to its theory alongside its practical application in PD.

A synthesizer is one of the most fundamental instruments in electronic music. Its essential function is to generate a musical tone when it receives a note from either a keyboard or a sequencer. In analog electronic music, a synthesizer is built from several modules, or parts:

1) The Oscillators, which generates the tones.
2) The LFO (Low Frequency Oscillator), which usually modulates either the frequency or gain of the Oscillator(s), or the frequency of the Filter.
3) The Filter, which emphasizes and/or removes certain frequencies.
4) The Envelope Generator, which controls changes in frequency or gain over the duration of the note.
5) The Amplifier, which controls the gain of the synthesizer.

Synthesizers can be capable of playing one note at a time (monophonic), or several notes at a time, allowing for chords (polyphonic). The number of simultaneous notes that a synthesizer can play are called its voices. Originally, the word "Voltage" was used (i.e. Voltage Controlled Oscillator, Voltage Controlled Filter or Voltage Controlled Amplifier) because in an analog synthesizer each of these modules was controlled by electrical voltage from the keyboard, sequencer or another module. Because we're working in the digital domain, this voltage is replaced by data in the form of numbers, messages and streams of digital audio.

For this tutorial, we will construct a monophonic synthesizer in PD based roughly on the design of the famous MiniMoog analog synthesizer (but much simpler!), and with a sound which is useful for generating basslines. It will take input from the computer keyboard, a MIDI keyboard or the sequencer we will build in the the next tutorial. This synthesizer will be based on two Oscillators to produce the note, another oscillator (the Low Frequency Oscillator) which will change the gain of the sound, a Filter which will only allow only certain frequencies of the sound to pass, an Envelope Generator which will control the "shape" of the gain of the note, and a final Amplifier which will be controlled by the Envelope Generator and a volume setting on the screen.

Downloads 

The patches used in this tutorial can be downloaded from:

http://en.flossmanuals.net/floss/pub/PureData/SimpleSynthesizer/simple_synth.zip

Oscillators


Oscillators are the basic signal generators in electronic music. By combining, filtering or modulating them, almost any imaginable sound can be created. In Pure Data, audio signals are represented by a stream of numbers which are between the values of -1 and 1. So the waveform of each oscillator has been programmed to send out values within this range.

The name of each oscillator refers to their waveform, which is the shape of one period (or one Herz) of that oscillator. Different waveforms make different sounds.

Sine Wave Oscillator


The Sine Wave Oscillator makes a pure tone with no harmonics. The shape of the wave smoothly moves from 0 up to 1, back down through 0 to -1 and back up to 0.

osc1

Sawtooth Wave Oscillator


The Sawtooth Wave Oscillator sounds harsher in comparison to the sinewave, and it contains both odd and even harmonics of the fundamental frequency. This makes it ideal for filtering and for synthesizing string sounds. The shape of this wave ramps up sharply from 0 to 1, then immediately drops back to 0.

osc2

Square Wave Oscillator


And the Square Wave Oscillator has a "hollow" sound, and contains only odd harmonics and is useful for synthesizing wind instrument as well as "heavy" bass sounds. It's shape alternates instantly between 0 and 1. Since there is no square wave object in PD, we create a square wave by checking to see if the output of the Sawtooth Wave object [phasor~] is greater than 0.5. If it is, the Expression object [expr~] outputs a 1, otherwise it outputs a zero. This creates the "high" (1) and "low" (0) states of the square wave, as you can see in the graph.

osc3

Other Waveforms


Other possible waveforms include a triangle wave as well as many other mathematical shapes.


waveshapes.png

Frequency


In order to to create sound, each oscillator object, takes an input of a number which represents a frequency in Hertz. This number determines the number of times the oscillator will make its waveform during one second. By using an creation argument (a default setting typed into the object box when the object is first created), we can set the initial frequency of an oscillator. And by using an [hslider] (Horizontal Slider), a Number or a Message, we can send numerical messages to change the frequency of the oscillator.

01

In all the examples so far, notice the difference between the cable for numbers and messages, which is thin, and the cable for audio, which is thicker. Numbers and messages can be sent to audio objects (those with a ~ in their name), but usually audio cannot be sent to dataflow objects (those without a ~ in their name). Attempting to do so will cause PD to print "error: can't connect signal outlet to control inlet", and it will not allow the connection to be made.

osc3.5

MIDI and Frequency


For many musical applications, the MIDI scale is a useful way of controlling the frequency of an oscillator. One can imagine the MIDI scale as a piano keyboard with 128 keys on it, and each key has been marked with a frequency in Hertz which represents that musical note. Below is a part of the table which makes up the MIDI scale. Three octaves are shown. The most important thing to notice is that a note which is one octave higher than another note (for example, the three A notes of 110 Hz, 220 Hz and 440 Hz) has a frequency which is twice that of the lower note.

    MIDI                 MIDI                   MIDI
    Note   Frequency     Note   Frequency       Note   Frequency

 C  36  65.4063913251    48   130.8127826503    60   261.6255653006
 Db 37  69.2956577442    49   138.5913154884    61   277.1826309769
 D  38  73.4161919794    50   146.8323839587    62   293.6647679174
 Eb 39  77.7817459305    51   155.5634918610    63   311.1269837221
 E  40  82.4068892282    52   164.8137784564    64   329.6275569129
 F  41  87.3070578583    53   174.6141157165    65   349.2282314330
 Gb 42  92.4986056779    54   184.9972113558    66   369.9944227116
 G  43  97.9988589954    55   195.9977179909    67   391.9954359817
 Ab 44  103.8261743950   56   207.6523487900    68   415.3046975799
 A  45  110.0000000000   57   220.0000000000    69   440.0000000000
 Bb 46  116.5409403795   58   233.0818807590    70   466.1637615181
 B  47  123.4708253140   59   246.9416506281    71   493.8833012561


For the complete table, see http://www.borg.com/~jglatt/tutr/notefreq.htm

The object in PD which turns a MIDI note into a frequency in Hertz is called [mtof], or MIDI to Frequency. When the MIDI note "69" is sent to it, for example, it will output the number "440". Looking at our examples, you can see that each slider has a range of 0-127, and this is converted by an [mtof] object to a frequency which tells the oscillator what to do.

Of course, you aren't limited to the notes that Western music schools teach you are correct. So-called "microtonal" notes are possible as well. If you hold down the Shift key while using the mouse to change a Number, decimal numbers are possible, so that you can tell an [osc~] to play MIDI note number 76.89, for example.

Additive Synthesis


Because PD adds together the audio signals which come to the inlet of any audio object, it's simple to add two or more signals together into a single waveform. Below, we can see what happens when a Sawtooth Wave and a Sine Wave are added together. The resulting waveform is a combination of the shapes of both, added together. Note that the two waveforms are sent to an Audio Multiplication [*~] object, which multiplies the combined signal by half to reduce the total range of values sent to the soundcard.

osc4

Remember that, at full volume, each oscillator is going from either 0 or -1  to 1 many times a second. Because most everything in PD is simply numbers, any number of signals can be added together. However, if the combined values of those signals go outside the -1 to 1 range when they reach the Digital to Analog Converter [dac~] object (i.e. the line out to the sound card), then clipping and distortion will occur. Any value outside of the accepted range will simply be treated as a -1 or a 1. You can see how two combined signals can go outside this range on the graph in the patch below.

osc5

An interesting thing happens when we combine two waveforms whose frequencies are very close to each other. The combined values of the two waves interfere with each other, causing a periodic modulation of the sound. The frequency of this modulation is equal to the difference of the two original frequencies in Hz. This is known as a "beating frequency", or "phase interference". The sound of two oscillators slightly "de-tuned" from each other is often used for different kinds of electronic music sounds, such as a "fat" bass effect.

osc6

Low Frequency Oscillators & Modulation

Low Frequency Oscillators (or LFOs) are used to control many aspects of a synthesizer, including the frequency of the Oscillators, the gain of the synthesizer or the cutoff frequency of the Filters (see below), and a complex synthesizer can contain many LFOs.

Amplitude Modulation


For a typical LFO, we can use the [osc~] object. By connecting the output of the LFO [osc~] to an Audio Multiplier [*~], we can modulate (i.e. change over time) the gain of any signal which passes through it. This effect is commonly called Amplitude Modulation, or AM Synthesis, and it gives additional character to the sound of a synthesizer.

Unlike the sound-generating Oscillators, we will not use MIDI note numbers to control this oscillator. This is because the speed of this oscillator must be much slower than that of musical notes. A typical LFO oscillates at speeds close to or even slower than once a second. So to control this [osc~], we will use a Number connected directly to its left-most inlet. By changing the number is this box, we send a frequency in Herz directly to the [osc~]. To send numbers smaller than one (where 0.5 would equal a speed of two seconds, for example), or numbers with any decimal place, use the Shift key while changing the Number with the mouse.

osc7

Ring Modulation


You can also modulate one audio signal with another audio signal. This effect is called Ring Modulation. If you have a microphone connected to your computer, try the following patch. The sound of your voice will enter PD through the Analog to Digital Converter [adc~] object (the line in from the soundcard), and be modulated by a Sawtooth Wave [phasor~] object. Notice that there is no sound when only one audio signal is present (i.e. when you are not speaking). This is because one audio signal multiplied by zero (no audio signal) will always be zero. And the louder the input signal is, the louder the output will be.

osc8

The Ring Modulation effect was often used in Science Fiction movies to create alien voices. You may want to use headphones when running a microphone into PD to prevent feedback (the output of the speakers going back into the microphone and making a howling sound).

Frequency Modulation


While Amplitude Modulation Synthesis changes the gain or volume of an audio signal, Frequency Modulation Synthesis, or FM Synthesis, is used to make periodic changes to the frequency of an oscillator. In it's simplest form, Frequency Modulation uses two oscillators. The first is the "carrier" oscillator, which is the one whose frequency will be changed over time. The second is the "modulator" oscillator, which will change the frequency of the "carrier".

For the "carrier", we only set the base "carrier frequency" using a Number box and a MIDI to Frequency [mtof~] object. Because all the adjustments afterwards will be done by audio signals, it's best to use the audio version of [mtof], hence the tilde is added to its name.

The "modulator" is where we do most of the adjustments. The first thing we want to do is set the frequency of the "modulator", i.e. how fast it will change the frequency of the "carrier". We do this with a Number box. The second thing we want to set is how much change we will make in the base frequency of the "carrier". So the output of the "modulator" [osc~] is multiplied by another Number box using an Audio Multiplier [*~] object to get the "modulation amount".

When this stream of numbers, which is changing with the speed the "modulator" and in the range set by the "modulation amount", is added to the "carrier frequency", then the "carrier frequency" will change as well. This stream of numbers is sent to the second [osc~], where it produces a complex sound which you can see in the graph.

Even more complex sounds can be created by using further "modulators" to make changes in the frequency of the main "modulator" oscillator.

osc9

Pulse Width Modulation


We've already seen how a simple mathematical check ("is the value of this audio ramp greater than 0.5?") can be used to turn a Sawtooth wave into a Square wave. This produces a Square Wave which is 1 half the time, and 0 the other half of the time. This is called the Pulse Width of the Square Wave. Different Pulse Widths make a different sound. And when we use a Square Wave as an LFO, different Pulse Widths will have different effects on the sound it is modulating.

When the Square Wave is 1 half the time and 0 the other half, it is said that it has a Pulse Width of 50%. To change the Pulse Width, it is necessary to send a new number to replace the "0.5" in the [expr~] object. The [expr~] object current has one Variable, which is written as $v1, and one constant, "0.5". If the constant is replaced with a second variable, $v2, then we can use a Number box to change the Pulse Width. Sending the number 0.25 will result in a Pulse Width of 25%, i.e. the Square Wave will be 1 a quarter of the time, and 0 three quarters of the time.

osc10

It is also possible to modulate the Pulse Width of the Square Wave with an LFO, which creates a unique sound. Instead of using a Number box, the output of a Sine Wave Oscillator is sent to an Absolute audio [abs~] object, which converts any negative values from the [osc~] into positive ones, and this stream of numbers is sent to the second inlet of the [expr~] object.

osc11

Math & Logic Operations


Once we are working with Square waves, whose value is either a 0 or a 1, then we can also use Logic operations to create patterns. Logic operations take as their inputs either a 0 or a 1 (and nothing in between!), and compare the two numbers, giving either a 0 or a 1 as an output.

The AND operation works like this:

	0 AND 0  =  0
	0 AND 1  =  0
	1 AND 0  =  0
	1 AND 1  =  1


In short, this means that the output is 1 only when both inputs are also 1, otherwise the output is 0. In PD, this is represented by the [&&] object for numbers, and the [&&~] object for audio.


The OR operation works like this:


	0 or 0 = 0
	0 or 1 = 1
	1 or 0 = 1
	1 or 1 = 1

In short, this means that the output is 1 only when both inputs are also 0, otherwise the output is 0. In PD, this is represented by the [||] object for numbers, and the [||~] object for audio.

And the EQUAL operation works like this:

	0 or 0 = 1
	0 or 1 = 0
	1 or 0 = 0
	1 or 1 = 1


In short, this means that the output is 1 only when both inputs are the same, otherwise the output is 0. In PD, this is represented by the [==] object for numbers, and the [==~] object for audio.

In the following patch, different logic operations are used to make patterns from two Square Wave Oscillators, which are then compared with a final Square Wave Low Frequency Oscillator. What you will hear is a pattern of Square Waves which are switched on and off by each other. The final LFO makes a recognizable rhythm in the sound.

osc12

Try replacing any of the AND [&&~] or OR [||~] objects with an EQUAL [==~] object to hear the difference it makes in the sound. Or add further Logic operations to the output of the LFO to make more complex rhythmic patterns. You can also experiment with changing the Pulse Width as described in the previous patches.

Filters


A filter works by allowing some frequencies through, while reducing or eliminating others.

A filter which allows only low frequencies to pass is called a Low Pass Filter. The object for this kind of filter in PD is [lop~]. It has one inlet for audio and one inlet for a number which determines the frequency in Hertz where the filter starts to reduce the audio (the Cutoff Point). Frequencies above the Cutoff Point are reduced or eliminated.

filt1

While one which allows only high frequencies is called a High Pass Filter. The object for this kind of filter in PD is [hip~]. It has one inlet for audio and one inlet for the the Cutoff Point. Frequencies below the Cutoff Point are reduced or eliminated.

filt2

A filter which allows some range of frequencies between highest and lowest is called a Band Pass Filter. The object for this kind of filter in PD is [bp~]. It has one inlet for audio, a second inlet for the center frequency that it will allow to pass and a third inlet for the Resonance, which determines the width of the range of frequencies it allows to pass (the Pass Band). The Center Frequency will pass unchanged, and frequencies higher or lower than that will be reduced or eliminated. How much they will be eliminated depends on the Resonance. Useful numbers for the Resonance tend to be between 0 and 10.

filt3

The three filters we've seen so far all take numbers to control their Cutoff or Center Frequencies as well as their Resonance (in the case of [bp~]. However, there are times when you might want to control the frequency of a filter with an audio signal. A typical situation is when a filter is "swept" by an LFO.

[vcf~] (Voltage Controlled Filter) is a filter whose Center Frequency and Resonance can be controlled by audio signals. The way this is done is quite similar to the tutorial on Frequency Modulation. A Slider sends a MIDI note to a MIDI to Frequency audio [mtof~] object to provide the Center Frequency to be swept, or modulated. Then we have an LFO [osc~] object, whose output is multiplied by the amount in Hertz which we want to sweep the filter frequency. This stream of numbers is added to the Center Frequency coming from the [mtof~] object and sent to the Frequency inlet of the [vcf~]

filt4

The Envelope Generator

The Envelope of a sound refers to changes in either its pitch or gain over the duration of a note. A gain envelope is the most common, because it is used to synthesize the dynamics of acoustic instruments. For example, a piano has a very sharp or percussive attack, with the note becoming loud quite quickly before gradually fading out. A violin, on the other hand, takes a longer time for the sound to build up as the strings begin to vibrate, and then fades away relatively quickly. A gain envelope has five main characteristics:

1) Attack: the length of time it takes the note to reach it's loudest point.
2) Decay: the length of time after the Attack it takes the note to reach it's Sustain volume.
3) Sustain: the volume of the note which is held until the note is Released.
4) Release: the length of time it takes the note to fade to zero after the key on the keyboard has been released.

This is commonly abbreviated as ADSR, and can be drawn graphically like this, where the horizontal axis represents time and the vertical axis represents volume:
adsr.png

An additional parameter which comes from the MIDI world is called "Velocity", and it refers to how hard the key of the keyboard has been pressed. In our synthesizer, Velocity will refer to the volume of the note at its loudest point, i.e the peak of the Attack.

The simplest Envelope Generator can be made using the object [line]. This object takes two numbers, a target and a time (in milliseconds), and interpolates numbers to that target in the time given. If it is sent a single number, the time of the ramp is assumed to be zero, and [line] "jumps" to that value. It remembers that last value that it reached, so the next pair of numbers will start a new ramp from the current value. If a new pair of numbers is sent to [line] while it is still making a ramp, it will immediately stop that ramp and start the new one.

eg1

To make a simple up/down, or Attack/Decay envelope, we need to send two different messages to [line]. The first will tell it to go to "1" in a certain amount of time, the second will tell it to go back to "0" in a certain amount of time. These two messages can be triggered with a single "bang", as long as we delay the triggering of the second message long enough for the first ramp to finish, using the [delay] object.

eg2

A more complex envelope can be created with the [vline~] object. This object can be programmed to make sequences of ramps in order, and with a delay in between them. For example, the message "10 1000, 0 0 1000, 1 1000 3000" would tell [vline~] to do the following:

Ramp up to 10 in 1000ms, then jump to 0 in 0ms after waiting 1000ms (from the start of the ramp), and finally ramp back up to 1 in 1000ms after waiting 3000ms (from start of the ramp).

eg3

Because it accepts more complex messages, [vline~] is useful for the traditional Attack/Decay/Sustain/Release envelope. Also, [vline~] is an audio object rather than a dataflow object, which means it is more suitable for audio multiplication, as we will see in the next section.

eg4

For an envelope with an arbitrary curve, a table is the most useful way to go. First we must create a table, by using the Put menu to place and Array in the patch. When we do that, we will see two Properties dialogs appear. In one, we name the Array "envelope" and set a length of 100 units. In the second we can change the graphical appearance and the range of the X and Y axes. In this case, set the X range to "0 to 99", and the Y range to "1 to 0". The size can be anything that is convenient, and is measured in pixels. You can get these Properties dialogs back by Right-clicking or CTL+clicking on the Array. These dialogs appear under the screenshot below.

To read a table, we can use the object [tabread]. The [tabread] object takes a creation argument of the name of the table it is supposed to read.  In order to draw inside the table, you should click on the line and drag with the mouse. A value sent to the inlet of [tabread] represents a point on the X axis, and the output is the corresponding value on the Y axis.

eg5

If we want to read a table continuously from start to finish, we can use [line] to send a continuous stream of numbers to [tabread], starting with the first position on the X axis of the table ("0"), and ending with the last position ("99"). Remember that [line] takes a pair of numbers, the target ("99", the end of the table) and the time it takes to get there (4000 milliseconds, or 4 seconds). When we want to start over from the beginning of the table, we send a single number, "0", and the [line] object jumps back to it.

In the example below, [tabread] gets values between 0-1 from the table "pitch_envelope". We multiply these numbers by 127 with a [*] (Multiplication) object, to get a MIDI note value between 0-127. After that, we use a [mtof] (MIDI to Frequency) object to convert the MIDI notes into a frequency in Hertz. The frequency is sent to a sine wave oscillator [osc~] object, which sends audio to the [dac~] (Digital to Analog Converter), PD's connection to the soundcard.

eg6

The Amplifier


The next step in our synthesizer is to create the audio amplifier, which will change the gain of the signal. Whatever method you use to create your envelope, if you are using it to control the amplitude of a signal you will want to make sure the output is an audio signal as well. This is done to avoid clicks in the audio.

Using a Slider

In the two examples below, an audio signal from the Sine Wave Oscillator [osc~] is being changed manually, via a slider, in the same way as the Volume knob on your home stereo might work. In the first example, the numbers from the slider, which go from 0-127, are divided by 127 with a Division [/] object, to get them within the range of 0-1. These numbers are sent directly to the right inlet of the Audio Multiplication [*~] object, so that every audio sample coming from the [osc~] is multiplied by a number between 0-1. This will reduce the volume of each sample. "0" means no sound, "1" means full volume. However, these changes in volume will have clicks in them, as each number from the slider is sent to the [*~].

amp1

Using [line~], [vline~] and [tabread4~]

In the second example, the numbers from the slider are sent to an Audio Ramp object [line~], after being packed together into a message by [pack] with the number 50. What this message, which might appear as "0.76 50" for example, tells line is that it should ramp to the next number in 50 milliseconds. This is known as Interpolation, which is to smoothly transition from one value to another by providing (or guessing) all the values in between. Since the [line~] object is an audio object, the signal it sends out should cleanly control the volume of the audio signal.

amp2

If you use [line] to make your envelope, you can make an audio signal by using the audio object [line~] instead.

amp3

[vline~] outputs an audio signal already.

amp4

And to read a table and get an audio signal out, the [tabread4~] object is useful. Note that [tabread4~] responds better when controlled with an audio signal as well, so [line~] is used instead of [line].
 
amp5

Controlling the Synthesizer


Reviewing what we've covered in this tutorial, we can see that all the building blocks of a simple synthesizer are present.

We have various Oscillators to generate the tones. Then there are Low Frequency Oscillators, which provide the possibility to modulate either the frequency or gain of the Oscillator(s), or the frequency of a Filter. There are also different types of Filters, which emphasizes and/or removes certain frequencies. Envelope Generators control changes in frequency or gain over time, and Amplifiers control the final gain of the synthesizer.

The way each of these elements are put together gives the final definition to the sound and functionality of your synthesizer. And there are an almost infinite number of was to do this! In the following examples, we'll look at some simple ways to combine the different elements of a basic synthesizer with ways of controlling it, either from the computer keyboard, a MIDI keyboard or a 16 step sequencer which we will build.

Input from the Computer Keyboard

To get a very crude input from the computer keyboard, we can use the objects [key] and [keyup]. Each key on the computer keyboard has what is called an ASCII value, which is a number used to represent that key. [key] outputs this number when a key is pressed, and [keyup] sends this number when a key is released. Like MIDI Notes, these numbers are within the range of 0 to 127. However, the layout of these ASCII values on the computer keyboard is far from musical! But they are a good way to get some immediate input into a patch, and later on [key] and [keyup] can used to trigger different elements of a PD patch besides musical notes.

In the following patch, the ASCII values of the computer keyboard are treated as MIDI notes and control the frequency and volume of a Sine Wave Oscillator. We will use [line~] as a simple Attack/Decay Envelope Generator here, to make the envelope of the note smooth and to avoid clicks.

When a key is pressed, [key] sends the ASCII value, which becomes a frequency through [mtof] and controls the [osc~]. At the same time, when the key is pressed, the output of [key] is converted to a "bang", which triggers the message "1" to be sent to [pack]. In [pack], this "1" is packed together with "50" to make a message which says "1 50". [line~] interprets the message "0 50" to mean "ramp to 1 in 50 milliseconds". This will smoothly ramp the audio signal from the [osc~] up to full volume.

When a key is released, then [keyup] will send a number out as well. We will convert this to a "bang", which sends the message "0" to [pack]. [pack] then makes the message "0 50" and sends it to [line~], and [line~] will ramp back down to 0 in 50 milliseconds.

ctl1

Input from a MIDI Keyboard

This task is made simpler (and more musical!) with the addition of a MIDI keyboard. Make sure you have selected the proper MIDI input device in your Preferences (see Configuring PD for more details). The [notein] object receives the MIDI Note and Velocity information from the MIDI keyboard. Because usually you will want to listen to the first MIDI keyboard you plug in, we give [notein] a creation argument of "1", thus [notein 1] will receive MIDI Notes on MIDI Channel 1. The MIDI Note played will come out the left outlet, and the Velocity (how hard the key is pressed) will come out the right outlet.

The MIDI Note we send to an [mtof], which converts it to a frequency and sends it to the [osc~]. The Velocity we divide by 127 to get a value between 0 and 1. This value gets [pack]ed together with 50, and sent to the  [line~] object, which we will use again as an Attack Decay Envelope Generator. [line~] makes a 50 millisecond audio ramp, either to "0" when the MIDI key is released and the Velocity is "0", or to a value between 0 and 1 when the MIDI key is pressed, depending on how hard it has been pressed. [line~] sends an audio ramp to the Audio Multiplier [*~], which smoothly changes the volume of the audio signal form the [osc~].

ctl2

Building a 16-Step Sequencer

Besides using a keyboard, another way to control a synthesizer is with a Sequencer, which stores MIDI Notes and plays them back in sequence, and at a speed which can be changed from faster to slower.

Before we can build the note-storing section of the Sequencer, however, we have to learn a little bit about dataflow in PD in order to make a counter. This counter will count from 0 to 15, and each number it sends out will trigger one of the steps in a 16-Step Sequencer.

The patch below shows a counter, built with basic PD objects.

ctl3

[metro] is used to send the message "bang" every so many milliseconds. This interval is set by a Number sent to the right inlet. The [metro] is turned on and off by sending either a "1" or a "0" to the left inlet. We use the [toggle] object to send these messages.

Hot and Cold

Below the [metro] is a construction which takes advantage of one of the most fundamental lessons in learning about dataflow in PD: "hot" and "cold" inlets. The left-most inlet of almost any non-audio PD object is called the "hot" inlet. Any input to the hot inlet of an object gives immediate output. Any other inlet to the right of the hot inlet is called a "cold" inlet. Input to a cold inlet is stored in the object, waiting for input on the hot side. In this case, when a new number comes to the hot side of the [*], it is multiplied by the number stored in the cold side. The information in the cold inlets is kept there until new information received at that inlet changes it, or until the object is re-created (by retyping its name, cutting/pasting the object or by reopening the patch).

hotcold1
hotcold2

So in our counter, there is an object called [float], which stores and outputs a Floating Point Number. Floating Point Number is another name for a number with a decimal place, usually called simply a "float". The opposite of a "float" is an Integer, or "int", which has no decimal place. All numbers in PD are assumed to be floats. When [float] receives a "bang" to its left ("hot") inlet, it outputs the float which is stored on it's right ("cold") inlet. When this [float] outputs a number, it is also sent to the inlet of a [+ 1] object, where 1 is added to that number and sent back to the "cold" inlet of [float] to wait for the next "bang". So, every time this construction receives a "bang", the number it will output will be 1 more than before.

For more information on "hot" and "cold", as well as other descriptions of how to get used to how dataflow works in PD, please see the Dataflow Tutorials in this FLOSS Manual.

The numbers sent from our counter will increase endlessly. In order to keep them within the bounds of our 16-Step Sequencer, we need a way to "wrap" these numbers around so that they start over when the counter reaches 16, and every other division of 16 that comes later on. [mod] is the object which does this. Technically, [mod] means "modulo", and it outputs the remainder of a division operation using the number in the creation argument. Thus "16" becomes "0", "17" becomes "1", "18" becomes "2" and so on.

Storing and Retrieving MIDI Note Values

In the next patch, we see how to store and recall a number from an [hslider] using the [float] object as well. Here, [float] has been abbreviated to the commonly used [f]. At the bottom of our counter construction from the previous example, we have replace the Number with an [hradio] array of buttons, so that we can see which step of our Sequencer we are at. (Right or Control+Click on the [hradio] to see its properties, and type "16" in the "number" field to set the size.)

Below the counter we have the object [select]. This object checks the input on its left inlet against either the input on the right inlet, or in this case against a series of creation arguments. When the input on the left matches one of the creation arguments, then the message "bang" comes out of the corresponding outlet. Thus, an input of "0" will send a "bang" out the first outlet, an input of "1" sends a"bang" out the second outlet, etc etc. In this way, we have a seperate "bang" for each step in the Sequencer.

For each step in the Sequencer, we will use a [f] object to store a MIDI Note send from a [vslider]. The range of the [vslider] is 0-127, and the number it outputs is sent to the "cold" inlet of [f], to wait for a "bang" to come to the "hot" inlet. When that "bang" comes, the MIDI Note is sent out. You can change the value of the [vslider] with the mouse at any time, and the MIDI note will only be sent at step 0 of the sequence.

ctl4

The Finished 16-Step Sequencer Patch

And here we have the finished patch, with all 16 steps included, connected to a simple synthesizer. Each step of the sequence sends a MIDI Note to [mtof], which controls the frequency of a [phasor~] as well as the frequency of a Band Pass Filter [bp~]. The creation arguments of the [bp~] set it's starting frequency as 220 Hz, but this is changed every time it receives a new number from the [mtof], which has been multiplied by 1.5 to make the center frequency of the filter a half octave above that of the Sawtooth Oscillator [phasor~]. The resonance is set very high, at "5", so the harsh sound of the [phasor~] is softened.

ctl5

In this version, no Envelope Generator is used, so the volume of the audio going to the soundcard remains constant. This leads to noticeable clicks when the frequencies of the MIDI Notes change. An Envelope Generator based on [line~], [vline~] or [tabread4~] could be inserted between the output of [bp~] and the [dac~] if desired.

A Four Stage Filtered Additive Synthesizer

Our final example shows all the different elements of a simple synthesizer combined together into an instrument which can be played by the computer keyboard using [key]. It has four distinct sections:

* The INPUT STAGE: where note information is received and sent to the other stages.
* The OSCILLATOR STAGE: where the notes received from the INPUT STAGE are converted to frequencies which control two detuned Sawtooth Oscillators.
* The FILTER STAGE: where notes received from the INPUT STAGE are turned into an audio signal which sweeps a Voltage Controlled Filter, and where the audio signal from the OSCILLATOR STAGE is filtered.
* And the AMP STAGE: where the "bang" at the start of every note from the INPUT STAGE is used to trigger a message to the [vline~] Envelope Generator, which smoothly changes the volume of the audio from the FILTER STAGE.

ctl6

The Input Stage

At the INPUT STAGE, we use the [key] object to get the ASCII values of the computer keys being pressed. This information is passed to the [trigger] object. [trigger] is a very important PD object used to specify the order in which events happen.

What [trigger] does depends entirely on its creation arguments. When it receives any input, [trigger] sends messages to its output in a right to left order, based on these creation arguments. In this case, our [trigger] has the creation arguments "float", "float" and "bang". So on any input from [key], which sends a Floating Point Number (a "float"), [trigger] will first send the message "bang" out its right-most outlet, which will go the AMP STAGE. The it will send that float which came in to the center outlet, which will go to the FILTER STAGE. And finally it will send that float to the left-most outlet, which will go the OSCILLATOR STAGE. [trigger] is often abbreviated as [t], so the [trigger] in this example could also be typed as [t f f b].

For more information on [trigger], please see the Dataflow Tutorials in this FLOSS Manual.

The Oscillator Stage

This stage is concerned only with the Additive Synthesis of two detuned Sawtooth Oscillators. This means that the output of two [phasor~] objects, whose frequencies are slightly different from each other, will be added together. Since the difference in frequency is quite small (one [phasor~]'s frequency is 99% of the other's), instead of hearing two tones we will hear a periodic modulation of one tone.

The float from the [trigger] in the INPUT STAGE arrives at an [mtof] object, which converts it to a frequency in Hertz. This frequency is sent immediately to one [phasor~], and also to a Multiplication [*] object, which makes a new frequency number which is 99% of the other, and this new scaled frequency is sent to a second [phasor~].

The audio output of the two [phasor~] objects is added together in an Audio Multiplier [*~] object, which reduces the overall volume by 50% to prevent clipping when it reaches the soundcard. The resulting audio signal is sent to the FILTER STAGE.

The Filter Stage

The FILTER STAGE is responsible for taking the audio from the OSCILLATOR STAGE and applying a swept Voltage Controlled Filter [vcf~] object to that signal. The center frequency of the [vcf~] is also determined by the key which has been pressed on the keyboard.

When the float sent by [trigger] from the INPUT STAGE reaches this stage, it is converted into a frequency number by [mtof]. This number is multiplied by 1.5 so that the center frequency of [vcf~] is a half octave above that of the Sawtooth Oscillators. The number from [mtof] is [pack]ed together with 300 and sent to a [line~] object. This message tells [line~] to ramp to any new number it receives in 300 milliseconds.

The audio ramp from [line~] is used to control the center frequency of the [vcf~] object. The result is that the [vcf~] will not jump to any new frequency it receives, but it will smoothly ramp there over 300 milliseconds, resulting in the distinctive "filter sweep" sound.

The audio leaving the Voltage Controlled Filter is now sent to the AMP STAGE.

The Amp Stage

This final stage controls the overall volume of each note played by this synthesizer. It uses a [vline~] object as a complex Envelope Generator.

Every time a key on the keyboard is pressed, the [trigger] object in the INPUT STAGE sends the message "bang" to the AMP STAGE. Here it triggers the message "1 150, 0.9 150 150, 0 1000 500", which is sent to the [vline~] and tells [vline~] to make this audio ramp.

The exact instructions the message tells [vline~] are as follows:

* First ramp to 1 in 150ms
* Then ramp down to 0.9 in 150ms after a delay of 150ms from the start of the complex ramp
* After that, ramp down to 0 in 1000ms after a delay of 500ms from the start of the complex ramp

This translates to:

* Attack: 150ms
* Decay: 150ms to a value of 0.9
* Sustain: 200ms (the 500ms of the last ramp minus the 300ms of the first two ramps equals a "rest period" of 200ms)
* Release: 1000ms

With these instructions, [vline~] creates an audio ramp which smoothly controls the overall volume of the audio coming from the FILTER SECTION via an Audio Multiplication [*~] object.

Subpatches

Now that we have an instrument that is separated into four distinct stages, we may want to make the screen a bit easier to look at by putting each stage inside its own Subpatch.

A Subpatch is simply a visual container which objects can be placed in to get them out of the way. To create a Subpatch in a PD patch, simply create an object named [pd mysubpatch], where "mysubpatch" can be any name you choose. A new empty patch window opens up and you can cut or copy and paste the objects you want to place in the Subpatch inside this new window. When you close the window, the objects will be inside this Subpatch, still functioning as normal.

To get information in and out of a Subpatch, you can use the objects [inlet] and [outlet] for numbers and other messages, and the objects [inlet~] and [outlet~] for audio. This will create inlets and outlets in the Subpatch in the main patch you are working in, that you can connect as normal. You can give a creation argument to each inlet or outlet, which could be a reminder of what is supposed to come in our out of that inlet or outlet ("midi_note", "start_trigger", "audio_from_filter", etc etc).

Here is our Four Stage Subtractive Filtered Synthesizer, with each stage inside it's own Subpatch.

ctl7-1

ctl7-2
ctl7-3
ctl7-4
ctl7-5