Python code for generating audio files algorithmically

The most versatile and user friendly E-Stim control unit available today. If you want More Power, More Control, and more fun, then the 2B is the one you want.
Post Reply
birdburdy
Active Developer
Posts: 162
Joined: Mon Aug 11, 2008 6:58 pm

Python code for generating audio files algorithmically

Post by birdburdy »

Something I was working on recently, some Python code to generate audio files for use with the 2B.
At the moment is has amplitude modulation but not frequency modulation yet. An example script is attached at the end of the script.
I will probably put this on github soon enough.

ssynth.py

Code: Select all

from scipy.io.wavfile import write
from numpy import linspace, sin, pi, int16
import seaborn as sns; sns.set()
import numpy as np
from scipy import signal

def tone(freq, len, amp=1, rate=44100):
    t = linspace(0, len, len*rate)
    data = sin(2*pi*freq*t) * amp
    return data

def square(freq, len, duty=0.5, amp=1, rate=44100):
    t = linspace(0, len, len*rate)
    sq = signal.square(2*pi*t*freq, duty=duty)
    return sq * amp

def sawtooth(freq, len, width=1., amp=1, rate=44100):
    t = linspace(0, len, len*rate)
    saw = signal.sawtooth(2*pi*t*freq, width)
    return saw * amp

def pause(len, rate=44100):
    t = linspace(0, 0, len*rate)
    return t

def extract_snip(tone, start, end, rate=44100):
    nsamples = len(tone)
    length = float(nsamples)/rate
    start_sample = start * rate
    end_sample = end * rate
    return tone[start_sample:end_sample]

def modulate(tone, mod):
    assert len(tone) == len(mod)
    return tone * mod

def modulate_gaussian(tone, c, rate=44100):
    nsamples = len(tone)
    length = float(nsamples)/rate
    t = linspace(-length/2, length/2, nsamples)
    #tshift = -nsamples/2
    g = np.exp(-(t)**2/(2*c**2))
    return modulate(tone, g)

def modulate_fadein(tone, in_by=0.25, rate=44100):
    nsamples = len(tone)
    length = float(nsamples)/rate
    in_by_sample = int(in_by * rate)
    t = linspace(0, 1, in_by_sample)
    nfollowing = int(nsamples - in_by_sample)
    following = linspace(1, 1, nfollowing)
    t = np.append( [t], [following] )
    return modulate(tone, t)

def modulate_fadeout(tone, start_fade=0.75, rate=44100):
    nsamples = len(tone)
    length = float(nsamples)/rate
    fade_at_sample = start_fade * rate
    nfade = int(nsamples - fade_at_sample)
    fade = linspace(1, 0, nfade)
    t = linspace(1, 1, fade_at_sample)
    t = np.append( [t], [fade] )
    return modulate(tone, t)

def modulate_parabola(tone, rate=44100):
    nsamples = len(tone)
    length = float(nsamples)/rate
    t = linspace(0, length, nsamples)
    length = length/2
    p = length**2 - (t - length)**2
    p /= np.max(p)
    return modulate(tone, p)
 

def write_waveform(data, fn, bitrate=44100):
    write(fn, bitrate, data.astype(int16))

def plot_waveform(data, fn='waveform.png'):
    sns.plt.plot(data)
    sns.plt.savefig(fn)
    sns.plt.close()
To use it (example):
example.py

Code: Select all

import numpy as np
from ssynth import *


# presets
rumble_low = square(15, len=6, amp=10000)
rumble = square(40, len=6, amp=10000)
rumble_mid = square(100, len=6, amp=10000)
rumble_high = square(150, len=5, amp=10000)
spike = tone(2000, len=4, amp=15000)
rampup = modulate_fadein(sawtooth(100, len=30, amp=12500), in_by=27)
pulse_high = modulate_parabola(tone(1500, len=2, amp=20000))
pulse_low = modulate_parabola(tone(200, len=2, amp=12500))


p0 = pause(0.25)
p1 = pause(1)
p2 = pause(2)
p3 = pause(3)

stream = np.zeros(1)
stream = np.append(stream, rumble)
stream = np.append(stream, p1)

stream = np.append(stream, rumble_low)
stream = np.append(stream, p0)

stream = np.append(stream, rumble_mid)
stream = np.append(stream, spike)
stream = np.append(stream, rumble_mid)
stream = np.append(stream, spike)

stream = np.append(stream, rumble_mid)
stream = np.append(stream, spike)

stream = np.append(stream, p1)
stream = np.append(stream, pulse_high)
stream = np.append(stream, pulse_low)

stream = np.append(stream, p1)
stream = np.append(stream, rampup)

stream = np.append(stream, p1)
stream = np.append(stream, rampup)

write_waveform(stream, 'audio.wav')
Soon I'll post the Python API I wrote a few years ago. I need to clean up the code a little first though.


Unofficial Python API for the E-Stim 2B: https://github.com/fredhatt/estim2bapi
Generating sounds in Python: https://github.com/fredhatt/estimsoundsynth
birdburdy
Active Developer
Posts: 162
Joined: Mon Aug 11, 2008 6:58 pm

Re: Python code for generating audio files algorithmically

Post by birdburdy »

Here it is on github.com, for anyone who's interested.
https://github.com/fredhatt/estimsoundsynth
Unofficial Python API for the E-Stim 2B: https://github.com/fredhatt/estim2bapi
Generating sounds in Python: https://github.com/fredhatt/estimsoundsynth
Post Reply