Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # date:29/03/2009 10:59
- import os
- import sys
- import re
- import time
- import math
- import winsound
- import wave
- import cStringIO
- import struct
- import random
- from itertools import izip
- from time import sleep
- def note_frequency(n = 1):
- f = 2**(float(n)/12)*440
- #print n, f
- return f
- def memoize(func):
- saved = {}
- def call(cls, *args):
- try:
- res = saved[args]
- print "memoized", len(res), str(args)
- return res
- except KeyError:
- print "calling", str(args)
- res = func(cls, *args)
- saved[args] = res
- return res
- except TypeError:
- # Unhashable argument
- print "unhashable"
- return func(cls, *args)
- call.func_name = func.func_name
- return call
- #class SampleGenerator2(object):
- # def __init__(self, framerate = 22050):
- # self.nchanells = 1
- # self.sampwidth = 2
- # self.framerate = framerate
- # self._cache = {}
- # self._really_play = True
- # pass
- #
- # def generate_samples(self, *args):
- # """must be overriden"""
- # yield random.random()
- #
- # @memoize
- # def generate_sound_buffer(self, *args):
- # print "generating", str(args)
- # stream = cStringIO.StringIO()
- # wf = wave.open(stream, "wb")
- # wf.setnchannels(self.nchanells)
- # wf.setsampwidth(self.sampwidth)
- # wf.setframerate(self.framerate)
- # samples = [self.convert_one_sample(samp) for samp in self.generate_samples(*args)]
- # data = struct.pack("%dh" % len(samples), *samples)
- # wf.writeframes(data)
- # wf.close()
- # stream.seek(0)
- # data = stream.read()
- # stream.close()
- # return data
- #
- # def play(self, *args):
- # return self._real_play(*args)
- #
- # def _real_play(self, *args):
- # data = self.generate_sound_buffer(*args)
- # if self._really_play:
- # winsound.PlaySound(data, winsound.SND_MEMORY)
- #
- # #def prefetch(self, *args):
- # # """only generates data, and stores it in cache"""
- # # self._really_play = False
- # # self.play(args)
- # # self._really_play = True
- #
- # convert_ratio = float(2**15)
- # def convert_one_sample(self, float_sample):
- # return int(float_sample * self.convert_ratio)
- class SampleGenerator(object):
- def __init__(self, framerate = 22050):
- self.nchanells = 1
- self.sampwidth = 2
- self.framerate = framerate
- self.length_in_seconds = 0.0
- def generate_samples(self):
- """must be overriden"""
- yield random.random()
- def hash(self):
- return (random.random(), random.random(), random.random())
- def nsamples(self):
- return int(self.length_in_seconds * self.framerate)
- def rewind(self):
- pass
- def cleanup(self):
- pass
- class Synthesizer(object):
- def __init__(self, framerate = 22050):
- self.nchanells = 1
- self.sampwidth = 2
- self.framerate = framerate
- self.generators = []
- def add_sample_generator(self, generator):
- self.generators.append(generator)
- def clear(self):
- self.generators = []
- return self
- def play(self, generator = None):
- if not generator is None:
- self.add_sample_generator(generator)
- data = self.generate()
- winsound.PlaySound(data, winsound.SND_MEMORY)
- return self
- def generate(self):
- return self.generate_sound_buffer(hash(tuple([g.hash() for g in self.generators])))
- @memoize
- def generate_sound_buffer(self, *hashable_args):
- stream = cStringIO.StringIO()
- wf = wave.open(stream, "wb")
- wf.setnchannels(self.nchanells)
- wf.setsampwidth(self.sampwidth)
- wf.setframerate(self.framerate)
- #samples = [self.convert_one_sample(samp) for samp in generator.generate_samples() for generator in generators]
- samples = []
- for generator in self.generators:
- samples.extend([self.convert_one_sample(samp) for samp in generator.generate_samples()])
- data = struct.pack("%dh" % len(samples), *samples)
- wf.writeframes(data)
- wf.close()
- stream.seek(0)
- data = stream.read()
- stream.close()
- return data
- convert_ratio = float(2**15)
- def convert_one_sample(self, float_sample):
- #print "%.2f" % float_sample
- float_sample = max(min(float_sample, 1.0), -1.0)
- v = int(float_sample * (self.convert_ratio-1))
- #print float_sample
- return v
- #class MultiSample(SampleGenerator):
- # def __init__(self, *args):
- # SampleGenerator.__init__(self)
- # self.samples = []
- # def add_sample(self, sample):
- # self.samples.append(sample)
- #
- # def generate_samples(self):
- # for generator in self.samples:
- # for sample in generator.generate_samples():
- # yield sample
- # def clear(self):
- # self.samples = []
- # def hash(self):
- # return tuple([g.hash() for g in self.samples])
- class PersampleFilter(object):
- def __init__(self):
- pass
- def processed(self, sample):
- pass
- class SinusoidSample(SampleGenerator):
- def __init__(self, length_in_seconds, frequency, volume):
- SampleGenerator.__init__(self)
- self.length_in_seconds = length_in_seconds
- self.frequency = frequency
- self.volume = volume
- def generate_samples(self):
- """ sinusoid """
- volume = self.volume
- cyclesPerSample = float(self.frequency)/self.framerate
- for samp in xrange(self.nsamples()):
- phi = samp * cyclesPerSample
- yield self.length_in_seconds * math.sin(2.0 * math.pi * phi) * volume * 0.5#?? why * 0.5??
- def hash(self):
- return (type(self), self.length_in_seconds, self.frequency, self.volume)
- class NoiseSample(SampleGenerator):
- # XXX refactor SampleGenerator to hold length_in_seconds and volume
- def __init__(self, length_in_seconds, volume = 1.0):
- SampleGenerator.__init__(self)
- self.length_in_seconds = length_in_seconds
- self.volume = volume
- def generate_samples(self):
- """ sinusoid """
- volume = min(self.volume, 1.0)
- nsamples = int(self.length_in_seconds * self.framerate)
- for samp in xrange(nsamples):
- yield random.random() * volume
- class WavfileSample(SampleGenerator):
- def __init__(self, file):
- SampleGenerator.__init__(self)
- self.length_in_seconds = 0
- self.wf = wave.open(file, "rb")
- self.framerate = self.wf.getframerate()
- def generate_samples(self):
- nframes = self.wf.getnframes()
- for i in range(nframes):
- frame = struct.unpack("h", self.wf.readframes(1))[0]
- yield self.frame2sample(frame)
- convert_ratio = 1.0/(float(2**15) - 1)
- def frame2sample(self, frame):
- sample = float(frame) * (self.convert_ratio)
- #float_sample = max(min(float_sample, 1.0), -1.0)
- #print "%.1f %d" % (sample, frame)
- return sample
- class DistortionFilterNaive(PersampleFilter):
- def __init__(self, distortion = 1.3):
- self.distortion = distortion
- def processed(self, sample):
- v = sample * self.distortion
- return max(min(sample, 1.0), -1.0)
- class VolumeChangeFilter(PersampleFilter):
- def __init__(self, volume = 1.0):
- self.volume = volume
- def processed(self, sample):
- return sample * self.volume
- class DistortionFilter(PersampleFilter):
- def __init__(self, distortion = 1.3):
- self.distortion = distortion
- def processed(self, sample):
- for i in range(self.distortion):
- sample = self.cubic(sample)
- return sample * (1.0 - self.myrand(0, 0.4))
- def cubic(self, input):
- if( input < 0.0 ):
- temp = input + 1.0
- output = (temp * temp * temp) - 1.0
- else:
- temp = input - 1.0
- output = (temp * temp * temp) + 1.0
- return output
- def myrand(self, min, max):
- r = random.random()
- r1 = math.fmod(r, max)
- r = r1 + min
- return r
- class FadeFilter(PersampleFilter):
- def __init__(self, generator, fade_out = True, function = None):
- self.nsamples = generator.nsamples()
- self.counter = 0
- self.fade_out = fade_out
- self.function = function
- if function is None:
- self.function = lambda s, x: x
- def processed(self, sample):
- fade_rate = float(self.nsamples - self.counter)/float(self.nsamples)
- if not self.fade_out:
- fade_rate = 1.0 - fade_rate
- #print fade_rate
- self.counter += 1
- # XXX what a fuck??
- return sample * self.function(self, fade_rate)
- def exp(self, x):
- xexp = math.exp(x)
- return 1.0-(math.e - xexp)/xexp
- def sin(self, x):
- return math.sin(x)
- class FilteredSample(SampleGenerator):
- def __init__(self, generator, filters):
- SampleGenerator.__init__(self)
- self.generator = generator
- self.filters = filters
- def generate_samples(self):
- for sample in self.generator.generate_samples():
- for filter in self.filters:
- sample = filter.processed(sample)
- yield sample
- #def hash(self):
- # return tuple([g.hash() for g in self.samples])
- if __name__ == "__main__":
- #def test():
- # wf = wave.open("short_beep.wav")
- # print wf.getparams()
- # pass
- #def test():
- # for ntimes in range(5):
- # for i in range(5):
- # s = SinusoidSample(0.5, note_frequency(i + 1), 1.0)
- # s.play()
- #def test():
- # ms = MultiSample()
- # synthez = Synthesizer()
- # for ntimes in range(5):
- # for i in range(5):
- # ms.add_sample(SinusoidSample(0.5, note_frequency(i + 1), 0.5))
- # synthez.play(ms)
- # ms.clear()
- #def test():
- # synthez = Synthesizer()
- # for ntimes in range(5):
- # for i in range(5):
- # s = SinusoidSample(0.5, note_frequency(i + 10), 0.3)
- # synthez.add_sample_generator(s)
- # synthez.play().clear().play(NoiseSample(0.5, 0.5)).clear()
- #def test():
- # synthez = Synthesizer()
- # s = SinusoidSample(1.5, note_frequency(1), 1)
- # synthez.add_sample_generator(FilteredSample(s, [DistortionFilter(10.0)]))
- # #synthez.play()
- # f = open("test.wav", "wb")
- # f.write(synthez.generate())
- #def test():
- # synthez = Synthesizer()
- # s = SinusoidSample(2, note_frequency(1), 1.0)
- # synthez.add_sample_generator(FilteredSample(s, [DistortionFilter(5.0), FadeFilter(s, True)]))
- # if 1:
- # synthez.play()
- # else:
- # f = open("test.wav", "wb")
- # f.write(synthez.generate())
- # f.close()
- #def test():
- # filesample = WavfileSample("test.wav")
- # if 1:
- # synthez = Synthesizer()
- # synthez.add_sample_generator(filesample)
- # synthez.play()
- # else:
- # for sample in filesample.generate_samples():
- # print "%.2f" % sample
- def test():
- filesample = WavfileSample("test.wav")
- fs = FilteredSample(filesample, [DistortionFilter(1), VolumeChangeFilter(0.5)])
- if 1:
- synthez = Synthesizer()
- synthez.add_sample_generator(fs)
- synthez.play()
- else:
- file = open("tst", "w")
- for sample in fs.generate_samples():
- file.write("%.2f\n" % sample)
- file.close()
- print "done"
- test()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement