import math import struct from itertools import chain from operator import mul from random import random from player import AplaySink SAMPLE_RATE = 44100 def sin(f, amplitude, duration): samples = (amplitude*math.sin(2*math.pi*f*(t/SAMPLE_RATE)) for t in range(int(duration*SAMPLE_RATE))) return samples def square(f, amplitude, duration): period = SAMPLE_RATE / f half_period = period / 2 for t in range(int(duration*SAMPLE_RATE)): if t % period < half_period: yield amplitude else: yield -amplitude def noise(amplitude, duration): return (amplitude*(2*random()-1) for _ in range(int(duration*SAMPLE_RATE))) def envelope(samples, attack_duration, release_duration): # TODO: rewrite ADSR envelope def compose(a, b): return map(lambda x: mul(*x), zip(a, b)) a = int(attack_duration * SAMPLE_RATE) r = int(release_duration * SAMPLE_RATE) samples = list(samples) attack = (x/a for x in range(0, a)) sustain = len(samples) - a - r release = (x/r for x in range(r, -1, -1)) return chain( compose(samples[:a], attack), samples[a:a+sustain], compose(samples[a+sustain:], release)) def mix(*sources): return (sum(x) for x in zip(*sources)) def pack(samples) -> bytes: return b"".join(struct.pack("