From: Alex Sadleir Date: Thu, 20 Dec 2012 10:58:33 +0000 Subject: parallelise serial port usage and I/O for writing sounds files X-Git-Url: https://maxious.lambdacomplex.org/git/?p=scannr.git&a=commitdiff&h=b0c1e6e2f1691bf40788c3462281a84ca0e77276 --- parallelise serial port usage and I/O for writing sounds files --- --- a/scannr.py +++ b/scannr.py @@ -12,60 +12,102 @@ #python -m serial.tools.miniterm -p COM20 -e -b 115200 --cr import psycopg2 import csv -import sys,os +import sys +import os sys.path.insert(0, os.path.join(os.path.dirname(__file__) or '.', 'pynma')) import pynma filename = "demo.wav" +last_call = (None, None, None) MIN_LENGTH = 90000 +lock = threading.RLock() -def worker(filename, length): +def get_call(): + global lock + with lock: + ser.write("GLG\r") + line = ser.readline() # read a '\n' terminated line + print line + reader = csv.reader([line]) + for row in reader: + #GLG,40078,NFM,0,0,CanberraBlackMnt,AustralianCapita,SES Ops 1,1,0 + #,NONE,NONE,NONE + if (row[0] != 'GLG' or row[1] == ''): + print "uh oh" + return (None, None, None) + if (row[1] != ''): + tgid = row[1] + #nma.push("scannr", "ping", filename, "http://www.google.com") + tgname = row[7] + sitename = row[5] + return (tgid, tgname, sitename) + +def log_recording(tgid, tgname, sitename, filename, length): + cur = conn.cursor() + cur.execute("INSERT INTO recordings \ + (tgid, tgname, sitename, filename, length)\ + VALUES (%s, %s, %s, %s, %s)",( tgid, tgname, sitename, filename, length)) + conn.commit() + cur.close() + + +def tgid_worker(): + global last_call + last_call = get_call() + + +def save_worker(filename, length): + global last_call """thread worker function http://www.doughellmann.com/PyMOTW/threading/ https://github.com/uskr/pynma ffmpeg -i 2012-09-29-1348911268.34-demo.wav -ar 8000 -ab 4.75k test.3gp -http://stackoverflow.com/questions/2559746/getting-error-while-converting-wav-to-amr-using-ffmpeg +http://stackoverflow.com/questions/2559746/getting-error-while-converting- +wav-to-amr-using-ffmpeg """ - print 'Worker for '+filename - ser.write("GLG\r") - line = ser.readline() # read a '\n' terminated line - print line - reader = csv.reader([line]) - for row in reader: - #GLG,40078,NFM,0,0,CanberraBlackMnt,AustralianCapita,SES Ops 1,1,0,NONE,NONE,NONE - if (row[0] != 'GLG'): - print "uh oh" - if (row[1] != ''): - tgid = row[1] - #nma.push("scannr", "ping", filename, "http://www.google.com") - tgname = row[7] - sitename = row[5] - """http://initd.org/psycopg/docs/usage.html""" - cur = conn.cursor() - cur.execute("INSERT INTO recordings (filename,tgid,tgname,sitename,length) VALUES (%s, %s,%s, %s, %s)",(filename,tgid,tgname,sitename, length)) - conn.commit() - cur.close() + print 'Worker for ' + filename + (oldtgid, oldtgname, oldsitename) = last_call + (tgid, tgname, sitename) = get_call() + if oldtgid == tgid: + if tgid == None or tgid == '': + print filename + " has no TGID" else: - print filename+" has no TGID" + log_recording(tgid, tgname, sitename, filename, length) + else: + if tgid == None or tgid == '': + print filename + " has no TGID" + else: + log_recording(tgid, tgname, sitename, filename, length) + if oldtgid == None or oldtgid == '': + print filename + " has no old TGID" + else: + log_recording(oldtgid, oldtgname, oldsitename, filename, length) + return - return def filenameMaker(): global filename filename = date.today().isoformat()+'-'+str(time.time())+'-demo.wav' -def record_to_async_file(): - "Records from the microphone and outputs the resulting data to `path`" +def do_record(): sample_width, data = snd.record() - print str(len(data)) + thr = threading.Thread(target=record_to_async_file, args=(sample_width,data,filename)) + thr.start() + + +def record_to_async_file(sample_width,data,filename): + "Records from the microphone and outputs the resulting data to `filename`" + print "Recording complete" if len(data) > MIN_LENGTH: + print "Recording being saved..." + dispatcher.send( signal='FILE_CREATED', sender=filename, filename=filename, length=len(data)) + print str(len(data)) data = snd.pack('<' + ('h'*len(data)), *data) path = "./data/"+filename - dispatcher.send( signal='FILE_CREATED', sender=filename, filename=filename, length=len(data)) wf = wave.open(path, 'wb') wf.setnchannels(2) wf.setsampwidth(sample_width) @@ -77,20 +119,23 @@ del data dispatcher.connect( filenameMaker, signal='SND_STARTED', sender=dispatcher.Any ) -dispatcher.connect( worker, signal='FILE_CREATED', sender=dispatcher.Any ) +dispatcher.connect( tgid_worker, signal='SND_STARTED', sender=dispatcher.Any ) +dispatcher.connect( save_worker, signal='FILE_CREATED', sender=dispatcher.Any ) print "Opening serial port..." if sys.platform.startswith('darwin'): - ser = serial.Serial('/dev/tty.usbserial-FTB3VL83', 112500, timeout=1) + ser = serial.Serial('/dev/tty.usbserial-FTB3VL83', 112500, timeout=1) elif sys.platform.startswith('win32'): - ser = serial.Serial('COM20', 112500, timeout=1) + ser = serial.Serial('COM20', 112500, timeout=1) print "Loading notifymyandroid..." -nma = pynma.PyNMA( "a6f50f76119eda33befe4325b4b9e1dd25eef7bad2868e4f") +nma = pynma.PyNMA( "a6f50f76119eda33befe4325b4b9e1dd25eef7bad2868e4f") print "Connecting database..." conn = psycopg2.connect("dbname=scannr user=postgres password=snmc") print "Scannr started." while True: print "ready to record again" - record_to_async_file() + do_record() ser.close() + + --- a/snd.py +++ b/snd.py @@ -1,15 +1,12 @@ -""" Record a few seconds of audio and save to a WAVE file. +""" Record a few seconds of audio and save to a WAVE file. Based on http://stackoverflow.com/questions/892199/detect-record-audio-in-python/6743593#6743593 """ import pyaudio import wave import sys -import audioop # http://docs.python.org/library/audioop -from os.path import exists from array import array from struct import unpack, pack -import threading from pydispatch import dispatcher THRESHOLD = 500 @@ -21,7 +18,7 @@ elif sys.platform.startswith('win32'): CHANNELS = 1 -MAX_SILENT = 60 +MAX_SILENT = 80 def is_silent(L): "Returns `True` if below the 'silent' threshold" @@ -72,16 +69,16 @@ def record(): """ - Record a word or words from the microphone and + Record a word or words from the microphone and return the data as an array of signed shorts. - Normalizes the audio, trims silence from the - start and end, and pads with 0.5 seconds of - blank sound to make sure VLC et al can play + Normalizes the audio, trims silence from the + start and end, and pads with 0.5 seconds of + blank sound to make sure VLC et al can play it without getting chopped off. """ p = pyaudio.PyAudio() - stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, + stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK_SIZE) @@ -110,6 +107,8 @@ dispatcher.send( signal='SND_STARTED') snd_started = True print snd_started + if snd_started and not silent: + num_silent = 0 if snd_started: LRtn.extend(L) if snd_started and num_silent > MAX_SILENT: