title: Python - Get waveform/amplitude of mp3
body: <p>I was hoping I could find a way to get the amplitude data from an mp3 in python. Similar to audacity but I do not want a visual, a simple array of values will do. I want my code to react to sound at certain points when it gets louder. I am using pygame to play the audio and was trying to convert it to a sndarray but it was only giving me the first 0.00018 seconds. Anyway I can get the whole mp3? It does not have to be real time as I would like to be able to react ahead of time anyway and will keep track of my position using pygame.</p>
  
  <p>I am building <a href="http://www.makeuseof.com/tag/build-cloud-lamp-sound-reactive-lightning/" rel="nofollow">this cloud</a> using a raspberry pi instead for other features. I already have the lighting work and need it to react to the lightning, lightshowpi is not an option sadly. Any help would be greatly appreciated</p>
  
  <p>Edit:
  So this is what I have so far thanks to coder-don. It works, but i hangs on the while loop. I do not know why. The mp3 I am using is rather long, could that be the issue?</p>
  
  <pre><code>import os, sys
  from gi.repository import Gst, GObject
  Gst.init()
  GObject.threads_init()
  
  def get_peaks(filename):
  global do_run
  
  pipeline_txt = (
      'filesrc location="%s" ! decodebin ! audioconvert ! '
      'audio/x-raw,channels=1,rate=22050,endianness=1234,'
      'width=32,depth=32,signed=(bool)TRUE !'
      'level name=level interval=1000000000 !'
      'fakesink' % filename)
  pipeline = Gst.parse_launch(pipeline_txt)
  
  level = pipeline.get_by_name('level')
  bus = pipeline.get_bus()
  bus.add_signal_watch()
  
  peaks = []
  do_run = True
  
  def show_peak(bus, message):
      global do_run
      if message.type == Gst.MESSAGE_EOS:
          pipeline.set_state(Gst.State.NULL)
          do_run = False
          return
      # filter only on level messages
      if message.src is not level or \
         not message.structure.has_key('peak'):
          return
      peaks.append(message.structure['peak'][0])
  
  # connect the callback
  bus.connect('message', show_peak)
  
  # run the pipeline until we got eos
  pipeline.set_state(Gst.State.PLAYING)
  ctx = GObject.MainContext()
  while ctx and do_run:
      ctx.iteration()
  
  return peaks
  
  def normalize(peaks):
      _min = min(peaks)
      print(_min)
      _max = max(peaks)
      print(_max)
      d = _max - _min
      return [(x - _min) / d for x in peaks]
  
  if __name__ == '__main__':
      filename = os.path.realpath(sys.argv[1])
      peaks = get_peaks(filename)
  
      print('Sample is %d seconds' % len(peaks))
      print('Minimum is', min(peaks))
      print('Maximum is', max(peaks))
  
      peaks = normalize(peaks)
      print(peaks)
  </code></pre>