Making Synthesizer from Scratch

Hey. You know that feeling where you study something in college and never get to actually use it? And then when you use it it turns out you’re missing a whole lot of practical knowledge? That’s how I feel about EE. This week I tried (somewhat successfully) to design and build a basic music synthesizer circuit and found a ton of gaps in my knowledge along the way. So I thought I’d share and maybe you’ll start experimenting with synth circuits too! In this post we’ll cover my initial design and what I learned along the way, so without further ado…

Part 1: Designing the Circuit

Basic Layout

The basic function of a sythesizer is to turn a digital signal into an analog sound wave

In the abstract, that’s really it. In come some bits and out comes some sound. More concretely you might imagine your bits represent the desired pitch of your output and maybe some additional bits for which instrument your synthesizer should simulate. If you want to get really fancy with polyphony you’ll allow multiple notes to be played simultaneously so you’ll use an event-based protocol like MIDI. We’re not gonna get really fancy in this post! I kept my circuit to the bare bones to understand the fundamentals, one note at a time and one type of instrument.

So how did I break down this problem? Basically I envisioned it as having three parts

  1. A Digital-to-analog converter or DAC takes in a digital signal and converts it to an analog one, usually a voltage or current. In this case the signal should then dictate what is the frequency of the wave generator.
  2. The wave generator circuit will take that analog signal and output a sound wave. The wave’s frequency will depend on the input signal and this is how we will vary the pitch over time to produce a melody.
  3. Finally we use an arduino to actually provide the digital bits to our synth. It is in our arduino that we will program our song.

Designing the Wave Generator

Digging deeper into the wave generator we notice we can realize it with a 555 timer circuit. These circuits are often used as clocks to a computer, meaning they produce a square wave as a voltage. Hook this clock signal up directly to a speaker though and you get a nice buzzing sound with a pitch based on the wave’s frequency (e.g. A4 is 440 Hz).

Timer circuits typically come in a few flavors which you might hear called by their formal names like monostable or bistable. These words describe the output wave form and there are standard circuit designs to achieve each one. The flavor that we care about is astable which will output a continuous and even stream of high and low voltages, a square wave, like a clock. If you are curious why we call it astable, it’s because the circuit never achieves a stable permanent value; it always fluctuates.

The key to turning a timer circuit into a proper wave generator is to realize that its output frequency is a function of the resistances and capacitance of its components. As usual Ben Eater has a terrific explanation of this topic which you can find here. In particular, if we vary the resistance R1 of the circuit, we will vary its output pitch. So all we need now is a DAC that can convert a digital collection of bits into an analog resistance and we are in business!

Why a DAC

What we have so far are two parts. An Arduino can deliver a discrete sequence of bits and a wave generator can turn an analog parameter (resistance) into a sound wave with the input frequency. What we need is a bridge between these two signal types that can convert bits into resistances. The ideal i/o behavior of such a device looks like this

where the output will increase step-wise and proportionally as the input increases. Importantly, the input is not a signal so much as a combination of high and low signals which we can enumerate as for example

Input Output
00 500Ω
01 1kΩ
10 1.5kΩ
11 2kΩ

Let’s see what it took to actually build a component with these characteristics.

Part 2: Building a DAC

Basics of Transistors

Ok. Here is where it got really interesting for me. Building a DAC required some transistor knowledge which I was apparently lacking. When I started this project I told myself, “well, just use a bunch of transistors as switches in parallel with a bunch of resistors. If you activate the transistors, they’ll short the resistors and bam you have variable resistance”

When I was in university, we got a pretty hand-wavy last section on computer architecture that covered the realization of logic gates from transistors. And this is about as detailed as it got. Turns out, in fact, there are many different kinds of transistors, six of which are in common use

and your selection of a transistor type has a bunch of implications for your circuit design. Let’s talk about how this works, starting with doping (just like the pros do!).

A crystaline material like Silicon is not by itself a good conductor. No electrons naturally exist in the energy bands that allow the electrons to flow freely across the material. When you “dope” the crystal you introduce impurities like small amounts of Boron or Phosphorous that will wedge themselves into the crystal lattice and give the material semi-conductive properties. A transistor is a special arrangement of doped and non-doped material that will act as a resistor, but with variable resistance coming across from the signal to one of its inputs (hence transistor).

A simple way you might achieve this behavior is by sandwiching one type of doped material in between another

Here “P” is a so-called positively doping material rich in holes from, say, Boron and “N” is a negatively doping material rich in free electrons from, say, Phosphorous. What we observe with this arrangement is that we are then able to attach three terminals to the material which we’ll call base, emitter, and collector

and if we induce a current from the base to the emitter then a proportional amount of current can be drawn from the collector to the emitter. The simplified picture we typically draw of this phenomenon is the semi-classical Drude model in which we imagine free electrons flowing from N to P and holes flowing from P to N, but only when a base current is present. If you want to dive deeper into this phenomenon, I highly recommend looking into quantum models of materials and in particular Ashcroft’s Solid State Physics.

I started this project with this kind of two materials spliced together transistor called a bipolar junction transistor and learned three important things that made me change course:

  1. BJTs are current controlled which makes them hard to reason about in voltage driven circuits. That is, if you induce a current across the base and emitter terminals of a BJT, the transistor will draw a proportional max current across the collector and emitter terminals. But if you’re driving and processing signals as voltages your components will be speaking different languages. So I switched to field effect transistors, a different arrangement of doping materials that will input and output voltages.
  2. All transistors are biased (but I’m sure they still appreciate diversity). That is transistors only exhibit their controlled-resistance behavior in one direction of current flow, not the other, making them more like controlled-diodes (hence the circuit diagram includes a diode). The direction of bias is determined by the order in which n doping and p doping is done (reverse the order and you reverse the bias). Importantly, because of this biasing your choice of an n-type or p-type transistor will affect where you put it in the circuit and thus your overall design.
  3. Transistors only have three terminals. You might be saying, “well, duh! how is that news?” - but, it turns out to be very important because your control signal and output signal always have a common terminal for draining current (the emitter terminal of a BJT or drain terminal of a FET). Our parallel switch-and-resistor design above now seems less viable because it’s hard to know what the current or voltage will be out of any particualr transistor and thus what our control signal will be relative to. Usually to simplify things you’ll tie this reference terminal either high or low so that the control signal is always relative to a known baseline.

After realizing these three points I took my design back to the drawing board (literally). I thought to myself, “let’s try and simulate the most basic DAC assemblies one bit at a time and generalize from there.” Here’s what I came up with

BJT DACs

For starters you can see a two-bit BJT DAC here the simulation of which is available here. Notice how both switches are effecitvely emitting to ground (each through a fixed size current limiting resistor). Notice also that we are using current sources as signals to the transistors shorting the transistors when the signals are high. Finally notice that our bigger resistor is double the resistance of the smaller one. Let’s work out the net effect this has assuming negligible impact from all the other current limiters.

If both transistors are off then our resistance is “infinite” so we’ll set that case aside. If only one transistor is one then current can only flow through it so our resistance will either be exactly 1024Ω or 2048Ω. So that leaves us with the case of both transistors being active which our law of parallel resistors will tell us has a resistance of

R=111042+12014=132048700Ω

This prediction not only agrees with the simulation but it generalizes quite nicely. Say you had N resistors each one a power of two and controlled by a bit bi making up the Nbit digital number B. Then you’d have a total resistance of

R=1bN20++b22N2+b12N1+b02N

Now realize we can express each of these resistances with the common denominator that is 2N

R=12NbN2N++22b22N+2b12N+b02N=2N2NbN++22b2+2b1+b0

Remarkably that final denominator is our digital number B! So as we increase B our resistance will decrease in an inverse linear fashion. If you remember Ohm’s law then

I=VR

we see that we can keep our current fixed and vary B and our voltage will increase linearly and proportionally to B! Exactly what we wanted. We simulate this in circuitlab and see this is indeed the effect.

Play around with this yourself and convince yourself it makes sense. Ask yourself what would happen if we change the transistors to P-type BJTs or changed the direction of the currents. Try it out and see if you’re right!

FET DACs

Turning this design into a voltage one now isn’t too hard. I replaced the BJTs with MOSFETs and the current sources with voltage ones. In this example circuit you’ll see the resistors below the transistors. This is because we’re using P-channel MOSFETs so the voltage will be relative to our source voltage not ground. As an exercise see if you can chanage this DAC to look more like our BJT (hint: use n-channel MOSFETs). This simulation is available here for you to work with and when we run it we see indeed we get a linear response.

Part 3: Putting it Together

Rethinking the DAC

So finally I decided to assemble this all together and see if I could get a little tune out of my circuit. While it was a nice puzzle to figure out how to make a voltage DAC I realized what I really want is voltage driven variable resistance. I decided to give my daisy-chained switch-and-resistor a second shot but with MOSFETs (in particular IRF520Ns) and it worked!

To test this approach I started with just some jumpers and an LED. Using the jumpers I set the gate for each transistor either high or low to manually increment values and then putting the LED in series with the transistors I saw its brightness increase as I went. Further experimenting with this approach I hooked up the full wave generator circuit to the MOSFETs and ran an arduino program to rotate between digital values.

const char OUT[] = {45, 47, 49, 51, 53};

#define PINS 5

void setup() {
	for (int pin = 0; pin < PINS; pin ++) {
		pinMode(OUT[pin], OUTPUT);
	}
}

void loop() {
	while (1) {
		for (int val = 0; val < 32; val ++) {
			for (int pin = 0; pin < PINS; pin ++) {
				digitalWrite(OUT[pin], (val >> pin) & 1);
			}
			delay(66);
		}
	}
}

and doing this I found the buzzing sound from my speaker would go up incrementally and smoothly in pitch which is pretty cool!

Programming the Arduino

Now it was at this point that I remembered that pitches don’t go up linearly in frequency, but geometrically. That is, to go from C to G or G to D (the same distance musically) you want to multiply your frequency by 32 not add a value to it. That means mapping our input values to output tones in theory becomes a pretty daunting task. So for this first iteration I decided to be empirical about it instead, homing in on specific input values and hearing what pitches they made. With some luck, this was enough to get a minor third, perfect fourth, and diminished fifth interval, exactly the notes you need to play Deep Purple’s Smoke on the Water.

const char OUT[] = {45, 47, 49, 51, 53};
const int MELODY[] = {27, 26, 25, 27, 26, 24, 25, 28, 27, 26, 25, 26, 28, 27, 28};
const int DELAYS[] = {333, 333, 666, 333, 333, 165, 666, 165, 333, 333, 666, 165, 165, 666, 333};
const int MELODY_LEN = 15;

#define PINS 5

void setup() {
	for (int pin = 0; pin < PINS; pin ++) {
		pinMode(OUT[pin], OUTPUT);
	}
}

void loop() {
	while (1) {
		for (int i = 0; i < MELODY_LEN; i ++) {
			int val = MELODY[i];
			for (int pin = 0; pin < PINS; pin ++) {
				digitalWrite(OUT[pin], (val >> pin) & 1);
			}
			delay(DELAYS[i]);
		}
	}
}

So that’s neat! In a future post I plan to dive into the theory more and see if we can take a second pass at this design with what we’ve learned, one where we’re more intentional about our choice of resistances based on the full 12-tone scale we want to generate. Perhaps we can even get fancy with polyphony. Until then, I hope you’ve enjoyed roughing the world of non-linear tri-terminal circuits with me and learned some things that will make you appreciate even simple things like your cell phone’s ringer more. Until next time!