Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

Python script to output a Shepard tone

By: a guest on May 13th, 2012  |  syntax: Python  |  size: 2.11 KB  |  views: 403  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  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()