Programming synthesizers with Python

Posted by StuffonmyMind on August 16, 2024

I think we can all agree Synthesizers are awesome and with that thinking comes the intense urge to build it from scratch as it slowly consumes all aspects of my social life.

Unlike normal instruments tho synths use electrical signals that generate waveforms which has its own sound, similar to how when you blow the flute or pluck a guitar you hear a sound from waveform moving across air molecules.

Sound waves produced by a guitar is different frequency from flute which is why they sound different (Timbre)

In Synths tho since this is a electronic waveform we can tune the intensity, duration, frequency and stuff we create sounds far beyond the range of any conventional musical instrument and this makes them very very powerful

Synths generate electrical signals & these signals are converted to sound using Voltage Controlled Oscillators (VCO) which essentially means we can use Voltage to tell the oscillator precisely what frequency to oscillate at in order to produce a musical note! Pitch is controlled by tuning the voltage, So if 1V increase on the input changes the output frequency one octave then its a 1V/Octave synthesizer.

Aside from the tunable frequency or pitch, the shape of Oscillator’s waveform can be a simple Sine wave or maybe you choose Triangle, Sawtooth, Square, Pulse waves and so on & on

This is how Synths generate sound!!!

Hardware is not my forte & to be honest i am actively shit at it but with scientific Python libraries like Numpy & Scipy we can programmatically build these waveforms to make some noise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np

SAMPLE_RATE=44100

def radians(frequency):
    # The total number of sample points that define your sound
    n_samples = int(duration * SAMPLE_RATE)

    # Range of the sound: n_samples points equaly spaced in the range
    sample_space = np.linspace(0, duration, n_samples, endpoint=False)

    return 2*PI*frequency*sample_space

freq = 400
np.sin(radians(freq))

Once sound is produced we need the ability to modify it, these can be done using components like Filters & Modulators.

Filters remove certain frequencies in order to shape the sound and alter the waveform, we can use them to boost frequencies

  • High-Pass: remove low frequencies
  • Low-Pass: remove high frequencies
  • Band-Pass: allow only a range of frequencies

Along with filtering you can also accentuate frequencies using Resonance which helps you further emphasize or suppress signals below a given cutoff frequency

With enough feedback, the filter is unstable and will blow up, oscillating at the cutoff frequency. But then nonlinear saturation in the amplifiers acts against the oscillations blowing up. The result of these two opposing forces in the feedback loop:

  • The linear part which blows up
  • The nonlinear part which prevents the oscillation from blowing up

This results in something really cool: A stable oscillation at the cutoff frequency, also called self-oscillation resulting waveform is usually fairly close to a sine wave.

Modulator just modifies the original sound or signal. Modulating a sound will change something about the effect your control signal has on the wave from the Oscillator. You can add a sense of movement and depth to the sound to modulating things like the Pitch, timbre, filter cutoff and even the waveform.

There can be multiple sources of modulation like Envelope Groups (EGs), Low Frequency Oscillators (LFOs) and synth components receiving and reacting to the are modulations are called destinations. These include Oscillators and Filters.

To control the sound behavior over time we use Envelopes. These really help shape the sound we hear and are some of the building blocks of sound design! They determine how the sound evolves over time, whether it starts abruptly, gradually fades in and out, or sustains at a certain level.

For example the Amplifier Envelope controls the volume of the amplifier using four common parameters abbreviated as ADSR

  • attack (how fast sound reaches full amplitude)
  • decay (how quickly the sound declines after attack)
  • sustain (how long should the sound last)
  • release (how long until sound gradually becomes silence after sustaining)

We can use multiple oscillators with different envelope settings to create really complex and evolving timbre and tonal characters.

These are just the basic components I tried to implement by pulling code from the inter webs and prototyping a demo of an object oriented Synth builder!

I called is Synthoor (don’t even ask) and put it up online

https://github.com/sangarshanan/synthoor

I also gave a demo of this at the CCsante meetup