Advertisement
Guest User

Untitled

a guest
Jul 27th, 2010
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.02 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: Latin-1 -*-
  3.  
  4. """Module containing classes used for audio visualization.
  5. """
  6.  
  7. from __future__ import division
  8. import os
  9. import threading
  10. import sys
  11. from struct import unpack
  12.  
  13. import cairo
  14. import gobject
  15. import gst
  16. import gtk
  17. from numpy import abs
  18. from numpy import fft
  19.  
  20.  
  21. class Visualizer(gtk.Window):
  22.     """Base class used by inheritance from the various specific visualizers.
  23.    """
  24.  
  25.     def __init__(self):
  26.         """Constructor.
  27.        
  28.        Create a drawing area used to display audio visualizations.
  29.        """
  30.         super(Visualizer, self).__init__()
  31.  
  32.         self.connect('delete-event', self.delete_cb)
  33.        
  34.         darea = gtk.DrawingArea()
  35.         darea.connect('configure-event', self.configure_cb)
  36.         darea.connect('expose-event', self.expose_cb)
  37.         self.add(darea)
  38.        
  39.         self.show_all()
  40.  
  41.     def delete_cb(self, window, event):
  42.         """Close the window and quit the mainloop.
  43.        """
  44.         gtk.main_quit()
  45.        
  46.     def configure_cb(self, darea, event):
  47.         """Update the cairo context used for the drawing actions.
  48.        """
  49.         _, _, self.width, self.height = darea.get_allocation()
  50.         self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
  51.                                           self.width,
  52.                                           self.height)
  53.         return True
  54.    
  55.     def expose_cb(self, darea, event):
  56.         """Redraw either the whole window or a part of it.
  57.        """
  58.         cr = darea.window.cairo_create()
  59.         cr.rectangle(event.area.x, event.area.y,
  60.                      event.area.width, event.area.height)
  61.         cr.clip()
  62.         cr.set_source_surface(self.surface, 0, 0)
  63.         cr.paint()
  64.         self.queued_draw = False
  65.         return False
  66.  
  67.     def threaded_handoff_cb(self, fakesink, buff, pad):
  68.         """Call handoff_cb inside a new thread.
  69.        """
  70.         self.worker = threading.Thread(target=self.handoff_cb,
  71.                                        args=(fakesink, buff, pad)).start()
  72.  
  73.     def handoff_cb(self, fakesink, buff, pad):
  74.         """Invoked when the fakesink collected a new buffer of data.
  75.        
  76.        Process the input stream and draw the result on a new surface, then
  77.        schedule an expose event.
  78.        """
  79.         samples = buff.size // 2
  80.  
  81.         fmt = "<" + str(samples) + "h"
  82.         data = unpack(fmt, buff.data)
  83.        
  84.         if hasattr(self, 'draw'):
  85.             gobject.idle_add(self.refresh, self.draw(data))
  86.  
  87.     def refresh(self, surface):
  88.         """Refresh the content of the canvas with the given surface.
  89.        
  90.        Keywords:
  91.            surface Surface to copy on the internal one.
  92.        """
  93.         self.surface = surface
  94.         if not self.queued_draw:
  95.             self.queued_draw = True
  96.             self.queue_draw()
  97.  
  98.  
  99. class Analyzer(Visualizer):
  100.     """Display the spectrum analyzer of the input audio signal.
  101.    """
  102.    
  103.     def draw(self, data):
  104.         """
  105.        Compute the fft, normalize it by a coefficient of 2/N, then draw a
  106.        vertical line for each component of the signal.
  107.        
  108.        Keywords:
  109.            data List containing the values of the input signal.
  110.            
  111.        Return:
  112.            Surface containing the fft representation.
  113.        """
  114.         surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
  115.                                      self.width,
  116.                                      self.height)
  117.         cr = cairo.Context(surface)
  118.        
  119.         samples = len(data)
  120.         step = self.width / (samples // 2)
  121.         normalization = 2 / samples
  122.         fft_data = abs(fft.fft(data)[:samples // 2]) * normalization
  123.         for (i, value) in enumerate(fft_data):
  124.             x = i * step
  125.             y = - value / (1 << 15) * self.height
  126.             cr.move_to(x, self.height - 1)
  127.             cr.rel_line_to(0, y)
  128.             cr.stroke()
  129.            
  130.         return surface
  131.    
  132.    
  133. class Oscilloscope(Visualizer):
  134.     """Display the shape of the input audio signal.
  135.    """
  136.    
  137.     def draw(self, data):
  138.         """
  139.        Connect the points of the input signal by simple lines.
  140.        
  141.        Keywords:
  142.            data List containing the values of the input signal.
  143.            
  144.        Return:
  145.            Surface containing the signal representation.
  146.        """
  147.         surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
  148.                                      self.width,
  149.                                      self.height)
  150.         cr = cairo.Context(surface)
  151.        
  152.         samples = len(data)
  153.         step = (self.width - 1) / (samples // 2)
  154.         for (x, y) in enumerate(data):
  155.             y = -y / (1 << 15) * (self.height // 2)
  156.             if x == 0:
  157.                 cr.move_to(x * step, self.height // 2 + y)
  158.             else:
  159.                 cr.line_to(x * step, self.height // 2 + y)
  160.         cr.stroke()
  161.        
  162.         return surface
  163.  
  164.    
  165. if __name__ == '__main__':
  166.     if len(sys.argv) != 2:
  167.         print "Usage: {0} <file>".format(sys.argv[0])
  168.         sys.exit(1)
  169.    
  170.     location = sys.argv[1]
  171.     if not location.startswith('/'):
  172.         location = os.path.join(os.getcwd(), location)
  173.        
  174.     str_pipe = '''filesrc location={0} !
  175.                  decodebin !
  176.                  audioconvert !
  177.                  audio/x-raw-int,
  178.                    channels=1,
  179.                    rate=44100,
  180.                    width=16,
  181.                    depth=16,
  182.                    endianness=1234 !
  183.                  tee name=t !
  184.                  queue !
  185.                    fakesink name=fakesink signal-handoffs=true t. !
  186.                  queue !
  187.                    autoaudiosink
  188.               '''
  189.     pipeline = gst.parse_launch(str_pipe.format(location))
  190.    
  191.     vis = Analyzer()
  192.     fakesink = pipeline.get_by_name('fakesink')
  193.     fakesink.connect('handoff', vis.threaded_handoff_cb
  194.    
  195.     pipeline.set_state(gst.STATE_PLAYING)
  196.    
  197.     gobject.threads_init()
  198.     gtk.main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement