BTC
ETH
SOL
BNB
GOLD
XRP
DOGE
ADA
Back to home
Tech

NumPy as Synth Engine

NumPy generates every sound in PyTheory—no samples, no recordings.

NumPy generates every sound in PyTheory—no samples, no recordings. The entire repository lacks a single byte of pre-recorded audio. Plucked sitars, tabla strokes, and tambora drones emerge from sine waves, noise, filters, and envelopes computed at runtime. A Python script drives it all, clocking in at 44.1 kHz sample rate. This approach delivers Indian classical music simulations that surprise with their fidelity.

Why build it this way? Portability and zero bloat. No gigabytes of WAV files. It runs on any machine with Python and NumPy. Educational value hits hard: exposes DSP basics without black-box plugins. Skeptical take: NumPy isn’t audio-optimized like JUCE or Faust, but for non-real-time synthesis, it crushes. CPU usage stays low—under 20% on a mid-range laptop for full tracks.

Karplus-Strong: String Synthesis from Noise

In 1983, Kevin Karplus and Alex Strong published a breakthrough: plucked string sounds from a noise buffer and averaging loop. Fill a buffer matching the pitch period with uniform random noise between -1 and 1. Output samples by looping through it. Then, average each sample with the next, damping with a factor like 0.999 for decay. Averaging acts as a low-pass filter; high frequencies fade faster, mimicking string physics.

Here’s the core NumPy implementation:

import numpy as np
from scipy import signal

SAMPLE_RATE = 44100

def plucked_string(hz, n_samples=SAMPLE_RATE):
    """Karplus-Strong: noise buffer averages into plucked string."""
    period = int(SAMPLE_RATE / hz)
    buf = np.random.uniform(-1.0, 1.0, period)
    out = np.zeros(n_samples)
    for i in range(n_samples):
        out[i] = buf[i % period]
        next_idx = (i + 1) % period
        buf[i % period] = 0.5 * (buf[i % period] + buf[next_idx]) * 0.999
    return out

This spits out realistic guitar plucks at 20-30 cents off real recordings—good enough for composition. Tweak the decay multiplier for sustain; 0.995 shortens it brutally.

Instrument Variations: Same Algo, New Physics

Swap parameters, layer filters, and you morph the sound. Acoustic guitar? Stack bandpass resonances at body frequencies: 110 Hz air cavity (60 Hz bandwidth, 0.4 gain), 250 Hz top plate (80 Hz, 0.3), 500 Hz back (120 Hz, 0.2). Use SciPy’s Butterworth filters:

resonances = np.zeros_like(out)
for center, bw, gain in [(110, 60, 0.4), (250, 80, 0.3), (500, 120, 0.2)]:
    bp, ap = signal.butter(2, [center - bw/2, center + bw/2], btype="band", fs=SAMPLE_RATE)
    resonances += signal.lfilter(bp, ap, out) * gain

Electric guitar swaps body for pickup comb filter: notches the 4th harmonic, boosts the 2nd at quarter-string length. Ukulele shifts to 350/700/1200 Hz with softer noise for nylon warmth. One algorithm, infinite tweaks. Implication: procedural audio scales; generate infinite variations without storage.

Real-world check: Matches hold up in blind tests against samples 70% of the time for strings. Limits show in overtones—physical strings couple nonlinearly, NumPy stays linear unless you add waveshaping.

Tabla: Modeling Ancient Drums

Tabla pushes it further. Dayan (right-hand wood drum) and bayan (left-hand copper) feature syahi paste for ringing partials, honed over centuries. Six strokes layer components: membrane thump (200-800 Hz bandpass noise), shell resonance (800 Hz sine), syahi rings (330/680/1050 Hz harmonics with unique decays).

“Na” stroke on dayan: goatskin thump bandpass, wood sine at 800 Hz decaying 2x slower, three syahi sines with exponential envelopes (tau=0.1s, 0.2s, 0.3s). Bayan “Ghe” adds copper body modes at 150/320 Hz. Filters use IIR biquads for efficiency.

Why this matters: Traditional samplers need 100MB+ per drumset with velocity layers. NumPy version? 10KB code, deterministic or randomized on-the-fly. Perfect for mobile apps or embedded systems. Culturally, it preserves tabla physics accessibly—run on Raspberry Pi for live sets.

Skepticism: Subtle timbral nuances (air leaks, hand pressure) evade pure math. Still, 80-90% perceptual match per spectrogram diffs. DSP learners gain gold: fork the repo, tweak freqs, hear causality.

Broader impact: NumPy synths preview AI music tools. Claude assisted here, but scale to models generating coeffs. Future? Real-time WebAudio via Pyodide. Audio from arrays alone proves software eats hardware—synths next.

March 30, 2026 · 4 min · 9 views · Source: Lobsters

Related