Slipmat Lead-In
python
posted: May, 4th 2010 | jump to bottom
#!/usr/bin/env python # # Slipmat Lead-In # # Copyright (c) 2010 Jacob Joaquin # Email jacobjoaquin@gmail.com # Visit Slipmat -- http://slipmat.noisepages.com/ # # Code License: GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 # http://www.gnu.org/licenses/lgpl-3.0.txt # # Music License: # This work is licensed under the Creative Commons Attribution 3.0 # United States License. To view a copy of this license, visit # http://creativecommons.org/licenses/by/3.0/us/ or send a letter to # Creative Commons, 171 Second Street, Suite 300, San Francisco, # California, 94105, USA. import math import operator import struct sr = 44100 ksmps = 1 class UnitGenerator: '''All unit generator classes inherit from this.''' def __init__(self): pass def __iter__(self): pass def next(self): raise StopIteration def __add__(self, ugen): return Add(self, ugen) def __mul__(self, ugen): return Mul(self, ugen) class Instr(): '''Decorator for creating a UnitGenerator from a definition.''' def __init__(self, ugen_def): self.ugen_def = ugen_def def __call__(self, *args): return self.Iter(self.ugen_def, *args) class Iter(UnitGenerator): def __init__(self, ugen_def, *args): self.ugen_def = ugen_def(*args) def __iter__(self): self.index = 0 self._iter = (i for i in self.ugen_def) return self def next(self): if self.index >= ksmps: raise StopIteration self.index += 1 return self._iter.next() class IterReduce(UnitGenerator): '''Reduces a list of iterators with the op function.''' op = operator.add def __init__(self, *ugens): self.ugens = ugens def __iter__(self): self.index = 0 self.iters = [(j for j in i) for i in self.ugens] return self def next(self): if self.index >= ksmps: raise StopIteration self.index += 1 return reduce(self.op, (i.next() for i in self.iters)) class Mul(IterReduce): op = operator.mul class Add(IterReduce): pass class RiseFall(UnitGenerator): '''A rise-fall envelope generator.''' def __init__(self, dur, peak=0.5): self.frames = sec_to_frames(dur) 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 Sine(UnitGenerator): '''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 UVal(UnitGenerator): '''Convert a numeric value to a unit generator object''' def __init__(self, v): self.v = v def __iter__(self): self.index = 0 return self def next(self): if self.index >= ksmps: raise StopIteration self.index += 1 return self.v class ScoreEvents: '''Schedule events for unit generators.''' def __init__(self, tempo=60): self.tempo = tempo self.event_dict = {} self.ID = 0 self.last_frame = 0 def event(self, start, dur, ugen): ugen_start = sec_to_frames(start * 60 / float(self.tempo)) ugen_end = ugen_start + sec_to_frames(dur * 60 / float(self.tempo)) self.last_frame = max(ugen_start, ugen_end, self.last_frame) if ugen_start not in self.event_dict.keys(): self.event_dict.update({ugen_start: [(self.ID, 'start', ugen)]}) else: self.event_dict[ugen_start].append((self.ID, 'start', ugen)) if ugen_end not in self.event_dict.keys(): self.event_dict.update({ugen_end: [(self.ID, 'stop', None)]}) else: self.event_dict[ugen_end].append((self.ID, 'stop', None)) self.ID += 1 def cpspch(p): '''Convert pitch class to frequency.''' octave, note = divmod(p, 1) return 440 * 2 ** (((octave - 8) * 12 + ((note * 100) - 9)) / 12.0) def sec_to_frames(dur): return int(dur * sr / float(ksmps)) def ScoreEventsToWave(score, filename): events = {} wave = open(filename, 'wb') chunk_2_size = score.last_frame * ksmps * 2 wave.write(struct.pack('< 4s I 4s', 'RIFF', 36 + chunk_2_size, 'WAVE')) wave.write(struct.pack('< 4s I 2h 2I 2h', 'fmt ', 16, 1, 1, sr, \ sr * 2, 2, 16)) wave.write(struct.pack('< 4s I', 'data', chunk_2_size)) for f in range(score.last_frame + 1): print '%d:' % f if f in score.event_dict: for L in score.event_dict[f]: ID, command, function = L if command == 'start': events.update({ID: function}) elif command == 'stop': del events[ID] iters = [(j for j in v) for v in events.itervalues()] for i in range(ksmps): if iters: v = reduce(operator.add, (i.next() for i in iters)) else: v = 0 if v > 1: v = 1 if v < -1: v = -1 wave.write(struct.pack('h', int(v * 32767))) wave.close() if __name__ == "__main__": import random # Instruments @Instr def RingTine(dur, amp, freq_1, freq_2, peak=0): '''Two ring modulated sine waves with an amplitude envelope.''' return Sine(amp, freq_1) * Sine(amp, freq_2) * RiseFall(dur, peak) @Instr def DirtySine(dur, amp, freq, peak): amp = 1.0 / 1.44 * amp a1 = Sine(1, freq) a2 = Sine(0.1, freq * 3) a3 = Sine(0.24, freq * 5) a4 = Sine(0.1, freq * 1.15) ring = a1 + (a2 + a3 + a4) * Sine(1, 1.003) return ring * RiseFall(dur, peak) * UVal(amp) # Event Generators def dusty_vinyl(s, start, dur, amp, freq_min, freq_max, density): '''Granular Sine Event Generator.''' for i in range(int(density * dur)): freq = random.random() * (freq_max - freq_min) + freq_min t = random.random() * (dur - start) + start s.event(t, 1 / freq, Sine(amp * random.random(), freq)) def sine_arp(s, start, bars, res, amp, note_list, decay): offset = start b = 60.0 / s.tempo # duration of a beat in seconds for bar in range(bars): n = 0 while n < 4.0 / res: note = cpspch(note_list[n % len(note_list)]) ugen = Sine(amp, note) * RiseFall(decay * b, 0) s.event(offset, decay, ugen) n += 1 offset = start + bar * 4 + n * res # Score s = ScoreEvents(tempo=169) b = 60.0 / s.tempo dusty_vinyl(s, 0, 80, 0.25, 1000, 10000, 30 * 60 / 169.0) s.event(6, 16, DirtySine(16 * b, 0.15, cpspch(8.07), 0.95)) s.event(22, 4, RingTine(4, 0.5, cpspch(10.10), 55, 0)) n = [8.00, 8.03, 8.02, 8.07, 8.05, 8.10, 8.09, 9.00] sine_arp(s, 22, 8, 0.25, 0.1, n, 0.8) s.event(26, 9, RingTine(9, 0.3, cpspch(9.03), 33, 0.9)) s.event(33, 9, RingTine(9, 0.5, cpspch(8.10), 55, 0)) s.event(40, 9, RingTine(9, 0.25, cpspch(7.00), 11, 0)) s.event(54.5, 9, RingTine(9 * b, 0.3, cpspch(9.03), 33, 0.1)) s.event(54, 9, RingTine(9 * b, 0.5, cpspch(8.07), 44, 0)) s.event(54, 8, DirtySine(8 * b, 0.15, cpspch(7.07), 0.1)) s.event(60, 4, DirtySine(4 * b, 0.15, cpspch(6.07), 0.1)) ScoreEventsToWave(s, 'slipmat_lead-in.wav')
278 views




