RareUI

Untitled

Jul 27th, 2014
83
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # https://codegolf.stackexchange.com/questions/34540/print-the-lyrics-to-twinkle-twinkle-little-star
  2. # https://en.wikipedia.org/wiki/File:Twinkle_Twinkle_Little_Star_plain.ogg
  3.  
  4. import pyaudio
  5. from array import array
  6. import scipy.signal
  7. import numpy
  8. import math
  9. import sys
  10.  
  11. MIN_AMPLITUDE = -52
  12. FRAMERATE = 44100
  13.  
  14. # This function is a little
  15. # Why is pred here anyways?
  16. def first(list, pred):
  17.     for i in range(len(list)):
  18.         if(list[i] > 0):
  19.             return i;
  20.     return 0;
  21. # You would usually want to write it like this:
  22. def first(list, pred):
  23.     for x in list:
  24.         if x > 0:
  25.             return x
  26.     return 0
  27. # Note that use of ; delimiter is only necessary if you
  28. # have multiple statements in one line. That's never.
  29. # I removed them from rest of the code.
  30.  
  31. # Based on: https://en.wikipedia.org/wiki/Decibel#Acoustics
  32. def getAmplitude(sig):
  33.     total = 0
  34.     elems = float(len(sig))
  35.     for x in sig:
  36.         total += numpy.abs(x) / elems
  37.     if(total == 0):
  38.         return -99
  39.     else:
  40.         return 20 * math.log(total / 32768., 10)    
  41.  
  42. # Based on: https://en.wikipedia.org/wiki/Piano_key_frequencies
  43. def getNote(freq):
  44.     return int(12 * math.log(freq / 440, 2) + 49)
  45.  
  46. # --------------------------------------------------------------------------
  47. # This is stolen straight from here w/ very slight modifications: https://gist.github.com/endolith/255291
  48. def parabolic(f, x):
  49.     return 1/2. * (f[x-1] - f[x+1]) / (f[x-1] - 2 * f[x] + f[x+1]) + x
  50.  
  51. def getFrequency(sig):
  52.     # Calculate autocorrelation (same thing as convolution, but with
  53.     # one input reversed in time), and throw away the negative lags
  54.     corr = scipy.signal.fftconvolve(sig, sig[::-1], mode='full')
  55.     corr = corr[len(corr)/2:]
  56.  
  57.     # Find the first low point
  58.     diffs = numpy.diff(corr)
  59.  
  60.      # Find the next peak after the low point (other than 0 lag). This bit is
  61.     # not reliable for long signals, due to the desired peak occurring between
  62.     # samples, and other peaks appearing higher.
  63.     # Should use a weighting function to de-emphasize the peaks at longer lags.
  64.     start = first(diffs, lambda x: x > 0)
  65.     peak = numpy.argmax(corr[start:]) + start
  66.     return parabolic(corr, peak) * (FRAMERATE / len(sig))
  67. # --------------------------------------------------------------------------
  68.  
  69. # These are the wrong keys (ie it is detecting middle C as an A), but I'm far too lazy to figure out why.
  70. # Anyway, these are what are detected from the Wikipedia .ogg file:
  71. notes = [73,          66,           64,       66,         68,       69,        71,          73,       66,     68,          69,         71,         66,        68,         69,        71      ]
  72. words = ["Twinkle, ", "twinkle, ", "little ", "star,\n",  "How I ", "wonder ", "what you ", "are.\n", "Up a", "bove the ", "world so ", "high,\n", "Like a ", "diamond ", "in the ", "sky.\n"]
  73. notes += notes[:8]
  74. words += words[:8]
  75.  
  76. pa = pyaudio.PyAudio()
  77. stream = pa.open(format=pyaudio.paInt16, channels = 1, rate = FRAMERATE, input = True, frames_per_buffer = 4096)
  78. idx = 0
  79.  
  80. # Note how I removed braces after while and if
  81. while idx < len(notes):
  82.     # Read signal
  83.     sig = array('h', stream.read(4096))
  84.     if getAmplitude(sig) > MIN_AMPLITUDE:
  85.         note = getNote(getFrequency(sig))
  86.         if note == notes[idx]:
  87.             print(words[idx], end='') # Note, no sys needed
  88.             idx += 1
RAW Paste Data