Using a microphone as a sensor

From XPUB & Lens-Based wiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Uses Python and Gstreamer, requires "gstreamer python bindings" (sudo apt-get install python-gst0.10).

Reading the mike level

The following program uses GStreamer & Python to read the microphone, and prints out numbers of the current microphone "level" (the "loudness" / volume). It also maintains the minimum and maximum values. The output is simply lines of data to the screen (stdout); so the next step is to feed these numbers (with a shell pipe) into a PyGame program to visualise it.

import gst, pygst, struct

(pmin, pmax) = (None, None)

# gboolean message_handler (GstBus * bus, GstMessage * message, gpointer data)
def listener_on_message (bus, message, data):
	global pmin, pmax
	s = message.structure
	if s and s.get_name() == "level":
		rms = s['rms']
		# also available, but not used here
		# peak = s['peak']; decay = s['decay']
		
		# numbers are in pairs (left, right) -- we use just the first one (left?)
		p = rms[0]
		
		# check against/update min and max
		if (pmin==None or p<pmin): pmin = p
		if (pmax==None or p>pmax): pmax = p
		print "level", p, pmin, pmax

	return True

listener_desc = 'alsasrc ! level ! fakesink'
listener = gst.parse_launch(listener_desc)
listener.get_bus().add_watch(listener_on_message, None)

import gobject
mainloop = gobject.MainLoop()
listener.set_state(gst.STATE_PLAYING)

try:
	mainloop.run()
except: # an interruption from Ctrl-C
	print "stopping"

# cleanup
listener.set_state(gst.STATE_NULL)


Displaying the data with PyGame

A PyGame program that reads numbers from stdin (sent by the level program above), and makes a simple visualisation.

#!/usr/bin/python

import sys, pygame, thread

def reader ():
    while True:
        line = sys.stdin.readline()
        evt = pygame.event.Event(pygame.USEREVENT, {"msg" : line.strip()})
        pygame.event.post(evt)

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
pygame.display.set_caption("python")
clock = pygame.time.Clock()
level, lo, hi = (0, 0, 1)    
thread.start_new_thread(reader, ())

while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT or \
        (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            sys.exit()
        elif event.type == pygame.USEREVENT:
            # print event
            level = event.msg
            msg = event.msg.split()
            cmd = msg[0]
            level = float(msg[1])
            lo = float(msg[2])
            hi = float(msg[3])
    s = (level - lo) / (hi - lo)
    pos = int(640 * s)
    screen.fill((0, 0, 0))
    pygame.draw.rect(screen, (255, 255, 255), (pos, 0, 10, 480), 0)
    pygame.display.update()
    clock.tick(30)


Putting the two together

To run this, you pipe the output of the first program into the second. Note that the "-u" option is very important -- it tells Python to not buffer (unbufferd) stdin/out. This is important to do "realtime" processing in this case.

python -u level.py | python -u level_viz.py

Attachments