Spectrum.py

From XPUB & Lens-Based wiki

File:Spectrum.zip

Getting the data from gstreamer

import pygst
pygst.require("0.10")
import gst, gobject
import time, thread

class Spectrum:

	def __init__(self):
		# Create a gstreamer pipeline, listen to it's messages via on_message callback
		# listener_desc = 'alsasrc ! spectrum ! fakesink'
		listener_desc = 'alsasrc ! spectrum bands=64 ! fakesink'
		self.listener = gst.parse_launch(listener_desc)
		bus = self.listener.get_bus()
		bus.add_signal_watch()
		bus.connect("message", self.on_message)

	def on_message (self, bus, message):
		""" callback function for gstreamer messages """
		s = message.structure
		# print "message.name", s.get_name()
		# print "message.structure.keys", s.keys()
		if s and s.get_name() == "spectrum":
			# spectrum messages have 'endtime', 'timestamp', 'stream-time', 'running-time', 'duration', 'magnitude'
			# print len(s['magnitude'])
			print "data: " + " ".join([str(x) for x in s['magnitude']])
		return True

	def start(self):
		self.listener.set_state(gst.STATE_PLAYING)
		while True:
			time.sleep(1)


# Run the Spectrum object in it's own thread, then start the gobject.MainLoop as required
spectrum = Spectrum()
thread.start_new_thread(spectrum.start, ())
gobject.threads_init()
loop = gobject.MainLoop()
loop.run()

Visualizing the data with PyGame

Pipe the level data into a PyGame script, that uses RelativeValue.py to filter and display the data.

To run, we pipe the data from the above into the below, using "unbuffered" python...

python -u spectrum.py | python -u spectrum_display.py
#!/usr/bin/python

import sys
import pygame
from pygame.locals import *
from pygame.time import Clock
from time import sleep
import thread

from RelativeValue import RelativeValue

def main():
	pygame.init()
	rvals = []
	NUM_BANDS = 64
	for i in range(NUM_BANDS):
		rvals.append(RelativeValue())
	
	# screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32)
	screen = pygame.display.set_mode((640, 480), 0, 32)
	SCREEN_WIDTH = screen.get_width()
	SCREEN_HEIGHT = screen.get_height()

	BAR_WIDTH = SCREEN_WIDTH / NUM_BANDS

	pygame.display.set_caption("spectrum")
	clock = Clock()
	level = 0.0
	while True:
		# TIMING
		clock.tick(30)
		
		# PROCESS EVENTS
		for event in pygame.event.get():
			if event.type==QUIT or \
			(event.type == KEYDOWN and event.key == K_ESCAPE):
				sys.exit()
			elif event.type == KEYDOWN and event.key == K_f:
				pygame.display.toggle_fullscreen()
			elif event.type == USEREVENT:
				for (i, val) in enumerate(event.data):
					rvals[i].setvalue(val)

		screen.fill((0, 0, 0))
		# if mfullimage: screen.blit(subimage, (mx, my))
		for (i, rval) in enumerate(rvals):
			max_height = SCREEN_HEIGHT / 2
			bar_height = rval.slider * max_height
			bar_rect = (i*BAR_WIDTH, SCREEN_HEIGHT / 2, BAR_WIDTH-1, bar_height)
			bar_color = (255, 0, 0)
			pygame.draw.rect(screen, bar_color, bar_rect)
		pygame.display.update()

# Start the PyGame display in it's own thread...
thread.start_new_thread(main, ())

# ... and then READ DATA FROM STDIN, sending data to PyGame as "events"
print "Press ctrl-c to stop..."
while 1:
	line = sys.stdin.readline()
	if (not line): break
	line = line.strip()
	try:
		if line.startswith("data:"):
			data = line.split()[1:]
			data = [float(x) for x in data] # parse data as floats
			# create a custom "event" and send it (post it) to the pygame loop
			evt = pygame.event.Event(USEREVENT, {"data" : data})
			pygame.event.post(evt)
	except ValueError:
		print "bad data", line