Advertisement
Guest User

Python script to output a Shepard tone

a guest
May 13th, 2012
918
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.11 KB | None | 0 0
  1. #!/usr/bin/python
  2. from __future__ import division
  3. import sys, os
  4. from math import cos, pi
  5. twopi = 2.0 * pi # a much more useful constant - http://tauday.com/tau-manifesto
  6.  
  7. srate = 48000
  8. length = 90
  9. numsamples = srate * length
  10.  
  11. numchannels = 7
  12. channeltheta = [0.0] * numchannels
  13. def gensample(freqamps): # freqamps is [(channel 0 frequency, channel 0 amplitude), (chan 1 freq, chan 1 amp), ...]
  14.     sample = 0.0
  15.     for i in xrange(numchannels):
  16.         channeltheta[i] += freqamps[i][0] / srate
  17.         channeltheta[i] %= 1.0
  18.        
  19.         sample += freqamps[i][1] * cos(channeltheta[i] * twopi)
  20.     return sample
  21.  
  22. basefreq = 25.0
  23. def genfreqamp(n, chan):
  24.     x = n / srate
  25.    
  26.     if x < 3: # ramp in for first 3 seconds
  27.         x = x ** 2 / 6 + 1.5 # so that the value and first derivative are equal at the cutover
  28.    
  29.     if x >= length - 5 and x < length - 2: # ramp out for last 5 seconds
  30.         x = length - 2 - 1.5 - (length - 2 - x) ** 2 / 6
  31.     if x >= length - 2:
  32.         x = length - 2 - 1.5
  33.    
  34.     x /= 10.0
  35.     x += chan
  36.     x %= float(numchannels)
  37.    
  38.     freq = basefreq * (2 ** x)
  39.     amp = 1 - cos(x / numchannels * twopi) # ranges from 0 at min frequency, up to 2, down to 0 at max frequency
  40.     return (freq, amp)
  41.  
  42. def main():
  43.     samples = []
  44.     maxsample = 0.0
  45.    
  46.     for i in xrange(numsamples):
  47.         if i % srate == 0:
  48.             print "\rGenerating: %3.0f%%" % (i / numsamples * 100.0),
  49.             sys.stdout.flush()
  50.         freqamps = [genfreqamp(i, c) for c in xrange(numchannels)]
  51.         samples.append(gensample(freqamps))
  52.         if abs(samples[-1]) > maxsample:
  53.             maxsample = abs(samples[-1])
  54.     print "\rGenerating: 100%   "
  55.     sys.stdout.flush()
  56.    
  57.     # Generate the audio as a raw output file, and then use SoX to convert it to WAV
  58.     with open("out.raw", "wb") as fp:
  59.         for i,x in enumerate(samples):
  60.             if i % srate == 0:
  61.                 print "\rWriting: %3.0f%%" % (i / numsamples * 100.0),
  62.             sys.stdout.flush()
  63.             n = int(round(x / maxsample * 32767))
  64.             if n < 0:
  65.                 n += 65536
  66.             fp.write(chr(n % 256) + chr(n // 256))
  67.     print "\rWriting: 100%   "
  68.     sys.stdout.flush()
  69.     os.system("sox -t raw -r %d -b 16 -c 1 -e signed-integer --endian little out.raw out.wav" % (srate))
  70.     os.unlink("out.raw")
  71.  
  72. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement