demos/demo_sink_create_woodblock.py: table lookup to improve synthesis
authorPaul Brossier <piem@piem.org>
Sat, 9 Mar 2013 01:26:24 +0000 (20:26 -0500)
committerPaul Brossier <piem@piem.org>
Sat, 9 Mar 2013 01:26:24 +0000 (20:26 -0500)
python/demos/demo_sink_create_woodblock.py

index 9fd86ae1390ed912b08453274d5c85b102ccf017..398c41e0a2bc1317ce619453807e1ede019c0f2c 100755 (executable)
@@ -1,38 +1,53 @@
 #! /usr/bin/env python
 
 import sys
-from math import sin, pi
+from math import pi, e
 from aubio import sink
-from numpy import array
+from numpy import arange, resize, sin, exp, zeros
 
-if len(sys.argv) != 2:
-    print 'usage: %s <outputfile>' % sys.argv[0]
+if len(sys.argv) < 2:
+    print 'usage: %s <outputfile> [samplerate]' % sys.argv[0]
     sys.exit(1)
 
-samplerate = 44100      # in Hz
+samplerate = 44100 # samplerate in Hz
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
 pitch = 2200            # in Hz
 blocksize = 256         # in samples
 duration = 0.02         # in seconds
 
 twopi = pi * 2.
 
-duration = int ( 44100 * duration ) # convert to samples
-attack = 3
-
-period = int ( float(samplerate) /  pitch )
-sinetone = [ 0.7 * sin(twopi * i/ period) for i in range(period) ] 
-sinetone *= int ( duration / period )
-sinetone = array(sinetone, dtype = 'float32')
-
-from math import exp, e
-for i in range(len(sinetone)):
-    sinetone[i] *= exp( - e * float(i) / len(sinetone))
-for i in range(attack):
-    sinetone[i] *= exp( e * (float(i) / attack - 1 ) )
-
-my_sink = sink(sys.argv[1], 44100)
-
-i = 0
-while i + blocksize < duration:
-    my_sink(sinetone[i:i+blocksize], blocksize)
-    i += blocksize
+duration = int ( samplerate * duration ) # convert to samples
+attack = int (samplerate * .001 )
+decay = .5
+
+period = float(samplerate) /  pitch
+# create a sine lookup table
+tablelen = 1000
+sinetable = arange(tablelen + 1, dtype = 'float32')
+sinetable = 0.7 * sin(twopi * sinetable/tablelen)
+sinetone = zeros((duration,), dtype = 'float32')
+
+# compute sinetone at floating point period
+for i in range(duration):
+    x = int((i % period) / float(period) * tablelen)
+    sinetone[i] = (sinetable[x] + sinetable[x+1]) / 2
+
+# apply some envelope
+float_ramp = arange(duration, dtype = 'float32')
+sinetone *= exp( - e * float_ramp / duration / decay)
+sinetone[:attack] *= exp( e * ( float_ramp[:attack] / attack - 1 ) )
+
+if 0:
+    import matplotlib.pyplot as plt
+    plt.plot(sinetone)
+    plt.show()
+
+my_sink = sink(sys.argv[1], samplerate)
+
+total_frames = 0
+while total_frames + blocksize < duration:
+    my_sink(sinetone[total_frames:total_frames+blocksize], blocksize)
+    total_frames += blocksize
+my_sink(sinetone[total_frames:duration], duration - total_frames)