The Easiest Way to Save and Share Code Snippets on the web

Control-Rate Envelope Generator

python

posted: Apr, 29th 2010 | jump to bottom

#!/usr/bin/env python
# Copyright (c) 2010 Jacob Joaquin, jacobjoaquin@gmail.com
# Visit Slipmat -- http://slipmat.noisepages.com/
 
import math
 
sr = 44100
ksmps = 10    
 
class Multiply:
    '''Multiplies multiples signals.'''
 
    def __init__(self, *ins):
        self.ins = ins
 
    def __iter__(self):
        self.index = 0
        self.iters = [(j for j in i) for i in self.ins]
        return self
 
    def next(self): 
        if self.index >= ksmps:
            raise StopIteration
 
        self.index += 1
        return reduce(lambda x, y: x*y, (i.next() for i in self.iters))
 
class RiseFall:
    '''A rise-fall envelope generator.'''
 
    def __init__(self, dur, peak=0.5):
        self.frames = int(dur * sr / float(ksmps))
        self.rise = int(peak * self.frames)
        self.fall = int(self.frames - self.rise)
        self.inc = 0
        self.v = 0
 
    def __iter__(self):
        self.index = 0
 
        if self.inc <= self.rise and self.rise != 0:
            self.v = self.inc / float(self.rise)
        else:
            self.v = (self.fall - (self.inc - self.rise)) / float(self.fall)
 
        self.inc += 1
        return self
 
    def next(self):
        if self.index >= ksmps:
            raise StopIteration
 
        self.index += 1          
        return self.v
 
class Run:
    '''Render frames over time.'''
 
    def __init__(self, dur=1.0):
        self.frames = int(dur * sr / float(ksmps))
 
    def __iter__(self):
        self.index = 0
        return self
 
    def next(self): 
        if self.index >= self.frames:
            raise StopIteration
 
        self.index += 1
        return self.index
 
class Sine:
    '''A sine wave oscillator.'''
 
    def __init__(self, amp=1.0, freq=440, phase=0.0):
        self.amp = amp
        self.freq = float(freq)
        self.phase = phase
 
    def __iter__(self):
        self.index = 0
        return self
 
    def next(self):
        if self.index >= ksmps:
            raise StopIteration
 
        self.index += 1
        v = math.sin(self.phase * 2 * math.pi)
        self.phase += self.freq / sr
        return v * self.amp
 
class Sum:
    '''Sums multiples signals.'''
 
    def __init__(self, *ins):
        self.ins = ins
 
    def __iter__(self):
        self.index = 0
        self.iters = [(j for j in i) for i in self.ins]
        return self
 
    def next(self): 
        if self.index >= ksmps:
            raise StopIteration
 
        self.index += 1
        return reduce(lambda x, y: x+y, (i.next() for i in self.iters))
 
if __name__ == "__main__":
    t = 0.002
    a1 = Sine(0.5, 440)
    a2 = Sine(0.5, 440 * 2 ** (7 / 12.0))
    amix = Sum(a1, a2)
    aenv = RiseFall(t, 0.5)
    aout = Multiply(amix, aenv)
 
    for frame in Run(t):
        print '%d:' % frame
        for i in aout:
            print '\t%.8f' % i
127 views