mirror of
https://github.com/kennethreitz/pytheory.git
synced 2026-06-05 23:00:20 +00:00
398cc68166
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
373 lines
13 KiB
ReStructuredText
373 lines
13 KiB
ReStructuredText
Synthesizers
|
||
============
|
||
|
||
PyTheory includes 10 built-in waveforms and 8 ADSR envelope presets.
|
||
Every sound is generated from scratch -- no samples or external audio
|
||
files needed.
|
||
|
||
Here's the beautiful thing about synthesis: all of it comes from math.
|
||
Sine waves, addition, and shaping. That's the entire foundation. Every
|
||
legendary synth in history -- the Moog Minimoog, the Sequential Prophet-5,
|
||
the Yamaha DX7, the Roland Juno-106, the Roland TB-303 -- uses some
|
||
combination of these building blocks. When you choose a waveform in
|
||
PyTheory, you're reaching for the same raw materials that defined
|
||
decades of music. The difference between a Moog bass and a DX7 bell
|
||
isn't magic; it's which waveforms you start with and how you shape them.
|
||
|
||
Classic Waveforms
|
||
-----------------
|
||
|
||
These four are the fundamentals. Every analog synthesizer ever built
|
||
starts here. If you learn nothing else about synthesis, learn these --
|
||
they're the primary colors you mix everything else from.
|
||
|
||
Sine
|
||
~~~~
|
||
|
||
The purest tone possible. Contains only the fundamental frequency with
|
||
no harmonics. Sounds smooth, clean, and "electronic." This is the
|
||
building block of all other waveforms (Fourier's theorem).
|
||
|
||
**Use for:** sub bass, clean pads, test tones, blending under other voices.
|
||
|
||
.. code-block:: python
|
||
|
||
from pytheory import play, Synth, Tone
|
||
|
||
tone = Tone.from_string("C4", system="western")
|
||
play(tone, synth=Synth.SINE)
|
||
|
||
Sawtooth
|
||
~~~~~~~~
|
||
|
||
Contains all harmonics (both odd and even), each at amplitude 1/n.
|
||
The richest of the classic waveforms — bright, buzzy, and aggressive.
|
||
Named for its ramp shape.
|
||
|
||
**Use for:** leads, brass, pads, anything that needs presence and bite.
|
||
|
||
.. code-block:: python
|
||
|
||
play(tone, synth=Synth.SAW)
|
||
|
||
Triangle
|
||
~~~~~~~~
|
||
|
||
Contains only odd harmonics, each at amplitude 1/n-squared. Softer and
|
||
more mellow than sawtooth — somewhere between sine and saw. Often
|
||
described as "woody" or "hollow."
|
||
|
||
**Use for:** flute-like leads, mellow bass, gentle pads.
|
||
|
||
.. code-block:: python
|
||
|
||
play(tone, synth=Synth.TRIANGLE)
|
||
|
||
Square
|
||
~~~~~~
|
||
|
||
Contains only odd harmonics, each at amplitude 1/n. Sounds hollow and
|
||
punchy — the classic chiptune / 8-bit sound. A special case of the
|
||
pulse wave with a 50% duty cycle.
|
||
|
||
**Use for:** chiptune, 8-bit game music, hollow leads, sub-octave bass.
|
||
|
||
.. code-block:: python
|
||
|
||
play(tone, synth=Synth.SQUARE)
|
||
|
||
Extended Waveforms
|
||
------------------
|
||
|
||
These go beyond the basics into territory that defined specific
|
||
instruments and eras. The pulse wave is the sound of the NES. FM
|
||
synthesis is the sound of the 1980s. If the classic waveforms are
|
||
primary colors, these are the specific pigments that painters actually
|
||
reach for.
|
||
|
||
Pulse
|
||
~~~~~
|
||
|
||
A pulse wave with a variable duty cycle. Narrower pulses sound thinner
|
||
and more nasal. At 50% it equals a square wave; at 10--20% it produces
|
||
the classic NES-style buzzy tone.
|
||
|
||
**Use for:** NES/chiptune sounds, nasal leads, retro textures.
|
||
|
||
.. code-block:: python
|
||
|
||
lead = score.part("lead", synth="pulse", envelope="pluck")
|
||
|
||
FM Synthesis
|
||
~~~~~~~~~~~~
|
||
|
||
Frequency modulation -- one oscillator (the modulator) modulates the
|
||
frequency of another (the carrier), producing complex inharmonic
|
||
spectra. This is how the Yamaha DX7 works -- the best-selling
|
||
synthesizer of all time. Released in 1983, it was suddenly everywhere:
|
||
the electric piano in every Whitney Houston ballad, the bass in every
|
||
Depeche Mode track, the bells in a thousand TV jingles. If you heard
|
||
pop music in the 80s, you heard FM synthesis.
|
||
|
||
**Use for:** electric piano (rhodes), bells, metallic leads, jazz chords.
|
||
|
||
.. code-block:: python
|
||
|
||
rhodes = score.part(
|
||
"rhodes",
|
||
synth="fm",
|
||
envelope="piano",
|
||
volume=0.3,
|
||
reverb=0.4,
|
||
)
|
||
|
||
Noise
|
||
-----
|
||
|
||
White Noise
|
||
~~~~~~~~~~~
|
||
|
||
Equal energy at all frequencies — pure randomness with no pitch.
|
||
Useful as a texture layer, a percussion source, or a wind/ocean effect.
|
||
|
||
**Use for:** snare layers, hi-hats, wind effects, risers, ambient texture.
|
||
|
||
.. code-block:: python
|
||
|
||
texture = score.part(
|
||
"texture",
|
||
synth="noise",
|
||
envelope="pad",
|
||
volume=0.1,
|
||
lowpass=2000,
|
||
)
|
||
|
||
Ensemble Waveforms
|
||
------------------
|
||
|
||
These all create "bigger" sounds by layering or modulating multiple
|
||
oscillators. Where a single sawtooth wave sounds like one instrument,
|
||
these sound like a section -- a string ensemble, a choir, a wall of
|
||
synths. They're the pad and atmosphere machines, the sounds that fill
|
||
out a mix and make it feel wide and immersive.
|
||
|
||
Supersaw
|
||
~~~~~~~~
|
||
|
||
Seven detuned sawtooth oscillators stacked together. The slight pitch
|
||
differences create a shimmering, massive wall of sound. This is the
|
||
Roland JP-8000's gift to the world -- the waveform that launched an
|
||
entire genre. Every trance anthem from the late 90s and early 2000s,
|
||
every euphoric EDM drop, every J-pop power chord owes something to the
|
||
supersaw.
|
||
|
||
**Use for:** trance pads, EDM leads, massive chords, anthem hooks.
|
||
|
||
.. code-block:: python
|
||
|
||
pad = score.part(
|
||
"pad",
|
||
synth="supersaw",
|
||
envelope="pad",
|
||
volume=0.4,
|
||
chorus=0.3,
|
||
reverb=0.5,
|
||
)
|
||
|
||
PWM Slow
|
||
~~~~~~~~
|
||
|
||
Pulse width modulation with a slow LFO. The duty cycle sweeps back and
|
||
forth, creating a lush, animated pad sound. This is the Roland Juno-106
|
||
in a nutshell -- arguably the most recorded synth pad sound in history.
|
||
That warm, slowly evolving, slightly chorused wash you hear in everything
|
||
from Boards of Canada to Drake? PWM with a slow LFO.
|
||
|
||
**Use for:** lush analog pads, slow evolving textures, Juno-style warmth.
|
||
|
||
.. code-block:: python
|
||
|
||
pad = score.part(
|
||
"pad",
|
||
synth="pwm_slow",
|
||
envelope="pad",
|
||
volume=0.35,
|
||
reverb=0.4,
|
||
)
|
||
|
||
PWM Fast
|
||
~~~~~~~~
|
||
|
||
Pulse width modulation with a fast LFO. The rapid duty cycle sweep
|
||
produces a natural chorus/vibrato effect built into the waveform itself.
|
||
|
||
**Use for:** animated leads, vibrato textures, movement without effects.
|
||
|
||
.. code-block:: python
|
||
|
||
lead = score.part("lead", synth="pwm_fast", envelope="pluck", volume=0.5)
|
||
|
||
ADSR Envelopes
|
||
--------------
|
||
|
||
Here's a question: a piano and an organ can play the exact same note at
|
||
the exact same frequency. Why do they sound completely different? The
|
||
answer is the envelope -- the *shape* of the sound over time. A piano
|
||
hits hard and immediately starts fading. An organ snaps on at full
|
||
volume and stays there until you lift the key. A violin swells in
|
||
gradually. The frequency is the same; the envelope is what makes each
|
||
instrument feel like itself.
|
||
|
||
ADSR stands for Attack, Decay, Sustain, Release -- four stages that
|
||
describe how any sound's volume changes from the moment you press a key
|
||
to the moment it falls silent. Understanding ADSR is the single most
|
||
important thing you can learn about synthesis, because it's the
|
||
difference between a sound that feels like an instrument and a sound
|
||
that feels like a test tone.
|
||
|
||
Raw waveforms click at the start and end of each note. An ADSR envelope
|
||
shapes the amplitude over time for natural-sounding notes:
|
||
|
||
- **Attack** -- how quickly the sound reaches full volume.
|
||
- **Decay** -- how quickly it drops to the sustain level.
|
||
- **Sustain** -- the held volume while the note is on.
|
||
- **Release** -- how quickly it fades to silence after the note ends.
|
||
|
||
PyTheory includes 8 presets:
|
||
|
||
.. code-block:: python
|
||
|
||
from pytheory import play, Envelope, Tone
|
||
|
||
tone = Tone.from_string("C4", system="western")
|
||
|
||
play(tone, envelope=Envelope.PIANO) # Quick attack, natural decay
|
||
play(tone, envelope=Envelope.PLUCK) # Sharp attack, fast decay
|
||
play(tone, envelope=Envelope.PAD) # Slow fade in, lush sustain
|
||
play(tone, envelope=Envelope.ORGAN) # Instant on/off, no shaping
|
||
play(tone, envelope=Envelope.BELL) # Instant attack, long ring
|
||
play(tone, envelope=Envelope.STRINGS) # Gradual bow attack
|
||
play(tone, envelope=Envelope.STACCATO) # Short and punchy
|
||
play(tone, envelope=Envelope.NONE) # Raw waveform, no shaping
|
||
|
||
Envelope Descriptions
|
||
~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
=============== ================================================
|
||
Name Character
|
||
=============== ================================================
|
||
``"piano"`` Quick attack, natural decay -- acoustic piano feel
|
||
``"pluck"`` Sharp attack, fast decay -- guitar pick, harp
|
||
``"pad"`` Slow fade in, lush sustain -- strings, synth pads
|
||
``"organ"`` Instant on/off -- Hammond organ, no shaping
|
||
``"bell"`` Instant attack, long ring -- vibraphone, tubular
|
||
``"strings"`` Gradual bow attack -- orchestral strings, slow
|
||
``"staccato"`` Short and punchy -- funk stabs, percussive hits
|
||
``"none"`` Raw waveform, no amplitude shaping at all
|
||
=============== ================================================
|
||
|
||
Detune
|
||
------
|
||
|
||
Any synth can be fattened with the ``detune`` parameter — it renders
|
||
three oscillators per note: the center pitch plus one shifted up and
|
||
one shifted down by the specified number of cents. The slight frequency
|
||
differences create beating and width, like an analog synth with
|
||
oscillator drift.
|
||
|
||
.. code-block:: python
|
||
|
||
# Juno-style analog drift — subtle, warm
|
||
pad = score.part("pad", synth="saw", detune=15)
|
||
|
||
# Trance supersaw territory — wide, shimmery
|
||
lead = score.part("lead", synth="saw", detune=25)
|
||
|
||
# Subtle thickening on a bass
|
||
bass = score.part("bass", synth="pulse", detune=8)
|
||
|
||
# Works on any synth — even FM
|
||
bells = score.part("bells", synth="fm", detune=12)
|
||
|
||
Detune values:
|
||
|
||
- **5–10** = subtle thickening (barely noticeable, just warmer)
|
||
- **12–18** = classic analog drift (Juno, Prophet)
|
||
- **20–30** = wide and shimmery (trance, EDM)
|
||
- **40+** = extreme, almost chorus-like
|
||
|
||
This is different from the ``chorus`` effect — detune creates
|
||
additional oscillators at render time (three per note), while chorus
|
||
processes the audio after rendering with a modulated delay line.
|
||
Detune is "wider at the source," chorus is "wider after the fact."
|
||
Stack both for maximum fatness.
|
||
|
||
Stereo Placement
|
||
----------------
|
||
|
||
Every part can be placed in the stereo field with ``pan`` and ``spread``.
|
||
|
||
**Pan** positions a part left or right. Constant-power panning keeps
|
||
the perceived loudness even as you move across the field:
|
||
|
||
.. code-block:: python
|
||
|
||
rhythm = score.part("rhythm", synth="saw", pan=-0.7) # left
|
||
lead = score.part("lead", synth="saw", pan=0.6) # right
|
||
bass = score.part("bass", synth="sine", pan=0.0) # center
|
||
hats = score.part("hats", synth="noise", pan=0.3) # slightly right
|
||
|
||
Pan values: -1.0 (hard left), 0.0 (center), 1.0 (hard right).
|
||
|
||
**Spread** works with ``detune`` — the up-detuned oscillator goes to
|
||
the right channel and the down-detuned goes to the left, creating
|
||
stereo width at the source:
|
||
|
||
.. code-block:: python
|
||
|
||
# Wide pad: detuned + spread across the stereo field
|
||
pad = score.part(
|
||
"pad",
|
||
synth="saw",
|
||
detune=20,
|
||
spread=1.0, # full L/R separation of detuned voices
|
||
reverb=0.4,
|
||
)
|
||
|
||
Spread values: 0.0 (detuned voices stay mono), 1.0 (full L/R split).
|
||
Stack with pan to offset the center of the spread.
|
||
|
||
Reverb is also stereo — the left and right channels get different
|
||
early reflection patterns, so the reverb tail occupies real space
|
||
in the stereo field rather than sitting dead center.
|
||
|
||
Choosing Synth and Envelope Combos
|
||
----------------------------------
|
||
|
||
The right combination of synth and envelope defines the character of a
|
||
voice. This is where you stop thinking about waveforms and start
|
||
thinking about *instruments*. Here are some starting points:
|
||
|
||
- **Funk stabs:** ``saw`` + ``staccato`` -- bright, punchy, rhythmic.
|
||
- **Jazz keys:** ``fm`` + ``bell`` -- glassy DX7 electric piano.
|
||
- **Ambient pads:** ``supersaw`` + ``pad`` -- massive, slow-building wash.
|
||
- **Acid bass:** ``saw`` + ``pluck`` with lowpass and glide -- 303-style.
|
||
- **Chiptune lead:** ``square`` + ``none`` -- raw 8-bit.
|
||
- **Film strings:** ``triangle`` + ``strings`` -- soft, bowed, organic.
|
||
- **Sub bass:** ``sine`` + ``pluck`` with lowpass -- deep and round.
|
||
- **Retro synth:** ``pwm_slow`` + ``pad`` -- Juno-style analog warmth.
|
||
- **Percussive hit:** ``noise`` + ``staccato`` with lowpass -- snare layer.
|
||
- **E-piano ballad:** ``fm`` + ``piano`` with reverb -- intimate jazz club.
|
||
|
||
Some practical combos worth memorizing:
|
||
|
||
- ``saw`` + ``staccato`` + legato = **acid 303 line.** Add a resonant
|
||
lowpass and some glide and you're in a warehouse in 1988.
|
||
- ``fm`` + ``bell`` = **jazz vibraphone.** The glassy, harmonic-rich
|
||
attack with a long ring-out. Add reverb for a late-night club feel.
|
||
- ``supersaw`` + ``pad`` = **ambient wash.** The slow attack lets the
|
||
detuned oscillators build into a shimmering wall. Add chorus and
|
||
long reverb and you're scoring a nature documentary.
|
||
- ``saw`` + ``pluck`` = **funk stab.** Short, sharp, bright. The
|
||
sound of Nile Rodgers' right hand.
|