Using a microphone as a sensor
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