FM synthesis using Numpy

Joost Molenaar dzjoost at
Wed Aug 15 01:39:18 CEST 2007

Hello fellow Python coders,

I'm trying to build a simple FM synthesizer in Python. As a beginner,
I take 'FM synthesizer' to
mean: "using a sine wave to control the frequency of another sine wave."

I tried to generate a tone of 1000 Hz that deviates 15 Hz six times a
second. The start of the
resulting wave file sounds right, i.e., a vibrato effect can be heard.
After a second or so, the
vibrato becomes more and more extreme, as if the modulating
oscillator's amplitude is rising
over time. I suspect that I am misunderstanding the math. I tried a
couple of things:

- removing the factor 2 * num.pi from either of the oscillators does
not fix it, besides, doing so is
even more wrong because numpy.sin works with radians

- using a higher sampling frequency makes no difference

- making t run from 0 to 1 each second (t %= 1) causes a clipping of
the sound, so this seems
wrong too

- the problem is not related to Numpy, because the effect also happens
in pure-Python
implementations of my bug

As you can see, I'm at a loss and am even trying incorrect bugfixes.
Any help would be
very welcome.

Thanks for your time,

Joost Molenaar

[I left out a writewavheader function to aid brevity]

import numpy as num

def oscillator(x, freq=1, amp=1, base=0, phase=0):
    return base + amp * num.sin(2 * num.pi * freq * x + phase)

def writewav(filename, data):
    wave = open(filename, 'wb')

    # .wav header: 30 s at 44100 Hz, 1 channel of 16 bit signed samples
    wave.write('RIFF\x14`(\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00D'

    # write float64 data as signed int16
    (32767 * data).astype(num.int16).tofile(wave)


t = num.arange(0, 30, 1./44100)

freq = oscillator(t, freq=6, amp=15, base=1000)
tone = oscillator(t, freq=freq, amp=0.1)

writewav('spam.wav', tone)

More information about the Python-list mailing list