Created
January 31, 2019 13:41
-
-
Save gto76/3132ac6f44160c7fc117fa39d094bb1e to your computer and use it in GitHub Desktop.
Simple music sinthesizer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# pip3 install simpleaudio | |
import wave, struct | |
import simpleaudio as sa | |
from collections import namedtuple | |
from math import pi, sin | |
Settings = namedtuple('Setting', 'n_channels sample_width f') | |
S = Settings(n_channels=1, sample_width=2, f=44100) | |
SECONDS = 4 | |
def get_sin(frame_no, hz=440): | |
return sin(frame_no * 2 * pi * hz / S.f) | |
def get_square(frame_no, hz=440): | |
return 1 if (frame_no * hz / S.f) % 1 < 0.5 else -1 | |
def get_saw(frame_no, hz=440): | |
return ((frame_no * hz / S.f) % 1) * 2 - 1 | |
def get_wave(fun=get_sin, hz=440, seconds=SECONDS): | |
return (fun(i, hz) for i in range(seconds * S.f)) | |
def get_lfo(fun=get_sin, hz=0.25, seconds=SECONDS, low_value=0, hi_value=1): | |
wave = get_wave(fun=fun, hz=hz, seconds=seconds) | |
return (to_lfo(a, low_value=low_value, hi_value=hi_value) for a in wave) | |
def to_lfo(pressure, low_value=0, hi_value=1): | |
return ((pressure + 1) / 2) * (hi_value - low_value) + low_value | |
def filter_LFO(wave, lfo): | |
lpf = get_lpf() | |
return (lpf(pressure=p, alpha_in=a) for p, a in zip(wave, lfo)) | |
def filter_wave(wave, alpha=0.1): | |
lpf = get_lpf(alpha) | |
return (lpf(p) for p in wave) | |
def get_lpf(alpha=0.1): | |
avg = 0 | |
def out(pressure, alpha_in=None): | |
nonlocal avg, alpha | |
if alpha_in: | |
alpha = alpha_in | |
avg += alpha * (pressure - avg) | |
return avg | |
return out | |
def play(float_samples): | |
audio_data = get_bytes(float_samples) | |
play_obj = sa.play_buffer(audio_data, S.n_channels, S.sample_width, S.f) | |
play_obj.wait_done() | |
def save(float_samples): | |
wf = wave.open('test.wav', 'wb') | |
wf.setnchannels(S.n_channels) | |
wf.setsampwidth(S.sample_width) | |
wf.setframerate(S.f) | |
wf.writeframes(get_bytes(float_samples)) | |
wf.close() | |
def get_bytes(float_samples): | |
samples = [struct.pack('<h', int(a * 30000)) for a in float_samples] | |
return b''.join(samples) | |
sine_wave = get_wave() | |
square_wave = get_wave(get_square) | |
filtered_w = filter_wave(get_wave(get_square), alpha=0.01) | |
filtered_lfo = filter_LFO(wave=get_wave(get_square), lfo=get_lfo()) | |
save(filter_LFO(wave=get_wave(get_square), lfo=get_lfo(low_value=0.01, hi_value=0.2))) | |
play(filter_LFO(wave=get_wave(get_saw), lfo=get_lfo(low_value=0.01, hi_value=0.065, hz=10))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment