The code below is what I use to record audio until the "Enter" key is pressed it returns an exception,
import pyaudio
import wave
import curses
from time import gmtime, strftime
import sys, select, os
# Name of sub-directory where WAVE files are placed
current_experiment_path = os.path.dirname(os.path.realpath(__file__))
subdir_recording = '/recording/'
# print current_experiment_path + subdir_recording
# Variables for Pyaudio
chunk = 1024
format = pyaudio.paInt16
channels = 2
rate = 48000
# Set variable for the labelling of the recorded WAVE file.
timestamp = strftime("%Y-%m-%d-%H:%M:%S", gmtime())
#wave_output_filename = '%s.wav' % self.get('subject_nr')
wave_output_filename = '%s.wav' % timestamp
print current_experiment_path + subdir_recording + wave_output_filename
# pyaudio recording stuff
p = pyaudio.PyAudio()
stream = p.open(format = format,
channels = channels,
rate = rate,
input = True,
frames_per_buffer = chunk)
print "* recording"
# Create an empty list for audio recording
frames = []
# Record audio until Enter is pressed
i = 0
while True:
os.system('cls' if os.name == 'nt' else 'clear')
print "Recording Audio. Press Enter to stop recording and save file in " + wave_output_filename
print i
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
line = raw_input()
# Record data audio data
data = stream.read(chunk)
# Add the data to a buffer (a list of chunks)
frames.append(data)
break
i += 1
print("* done recording")
# Close the audio recording stream
stream.stop_stream()
stream.close()
p.terminate()
# write data to WAVE file
wf = wave.open(current_experiment_path + subdir_recording + wave_output_filename, 'wb')
wf.setnchannels(channels)
wf.setsampwidth(p.get_sample_size(format))
wf.setframerate(rate)
wf.writeframes(''.join(frames))
wf.close()
The exception produced is this
Recording Audio. Press Enter to stop recording and save file in 2015-11-20-22:15:38.wav
925
Traceback (most recent call last):
File "audio-record-timestamp.py", line 51, in <module>
data = stream.read(chunk)
File "/Library/Python/2.7/site-packages/pyaudio.py", line 605, in read
return pa.read_stream(self._stream, num_frames)
IOError: [Errno Input overflowed] -9981
What is producing the exception? I tried changing the chunk size (512,256,8192) it doesn't work. Changed the while loop condition and it didn't work.
I had a similar problem; there are 3 ways to solve it (that I could find)
set rate=24000
add option "exception_on_overflow=False" to the "read()" call, that is, make it "stream.read(chunk, exception_on_overflow=False)"
use callbacks
Here is, for your convenience, an example o "using callbacks"
#!/usr/bin/python
import sys, os, math, time, pyaudio
try:
import numpy
except:
numpy = None
rate=48000
chan=2
sofar=0
p = pyaudio.PyAudio()
def callback(in_data, frame_count, time_info, status):
global sofar
sofar += len(in_data)
if numpy:
f = numpy.fromstring(in_data, dtype=numpy.int16)
sys.stderr.write('length %6d sofar %6d std %4.1f \r' % \
(len(in_data), sofar, numpy.std(f)))
else:
sys.stderr.write('length %6d sofar %6d \r' % \
(len(in_data), sofar))
data = None
return (data, pyaudio.paContinue)
stream = p.open(format=pyaudio.paInt16, channels=chan, rate=rate,
input=True, stream_callback=callback)
while True:
time.sleep(1)
Related
I am using python 2 in asterisk 2 there is a section where code listen to callers audio and process the audio. During the process there is a silence of 15 sec before the audio is played. I want to add a music during the processing of audio. Is there a way to do this.
the extension.config is like this
[autoattendant2]
exten => 5555,1,same=>n,Answer()
same=> n, AGI(/root/code_base/Queue/code2.py)
same=>n,hangup()
Below is the python code
#!/usr/bin/env python2
import sys
import re
import time
import random
import subprocess
import requests
import json
from datetime import datetime
env = {}
tests = 0;
while 1:
line = sys.stdin.readline().strip()
if line == '':
break
key,data = line.split(':')
if key[:4] <> 'agi_':
#skip input that doesn't begin with agi_
sys.stderr.write("Did not work!\n");
sys.stderr.flush()
continue
key = key.strip()
data = data.strip()
if key <> '':
env[key] = data
sys.stderr.write("AGI Environment Dump:\n");
sys.stderr.flush()
for key in env.keys():
sys.stderr.write(" -- %s = %s\n" % (key, env[key]))
sys.stderr.flush()
def checkresult (params):
params = params.rstrip()
if re.search('^200',params):
result = re.search('result=(\d+)',params)
if (not result):
sys.stderr.write("FAIL ('%s')\n" % params)
sys.stderr.flush()
return -1
else:
result = result.group(1)
#debug("Result:%s Params:%s" % (result, params))
sys.stderr.write("PASS (%s)\n" % result)
sys.stderr.flush()
return result
else:
sys.stderr.write("FAIL (unexpected result '%s')\n" % params)
sys.stderr.flush()
return -2
def change_file(path, cid):
# one of the process example
filename = 'complain{0}'.format(cid)
#filename =
input_file = path + '/' + filename + '.gsm'
output_file = path + '/' + filename + '.wav'
#command = "sox {} -r 8000 -c 1 {}".format(input_file, output_file)
command = "sox {} -b 16 -r 44100 -c 1 {} trim 0 7 vol 2".format(input_file, output_file)
subprocess.call(command, shell=True)
pbcheck = requests.get("http://127.0.0.1:8000/STT_complaint/", params = {"address" : output_file, "lang" : language, "cid":cid, "phone":callerid, "start_time":now})
res = pbcheck.content
res2 = res.replace('"', "")
return res2
def run_cmd(cmd):
#This runs the general command
sys.stderr.write(cmd)
sys.stderr.flush()
sys.stdout.write(cmd)
sys.stdout.flush()
result = sys.stdin.readline().strip()
checkresult(result)
#language = "ben"
# asking problem recorded audio
cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/{0}/plz_tell_problem \"\"\n".format(language, language)
run_cmd(cmd_streaming)
# listening to caller / recording caller voice
cmd_record = "RECORD FILE {0}/complain{1} gsm 1234 {2} s=3 \"\"\n".format(fixed_path, cid, 15)
run_cmd(cmd_record)
#processing audio
processed_output = change_file(path , cid) # while this is executing ad giving output i want to play wait_music and then stop to run
# while processing play this
cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/wait_music \"\"\n".format(language, language)
run_cmd(cmd_streaming)
# once output received (processed_output) play next audio
cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/next_instruction \"\"\n")
run_cmd(cmd_streaming)
For that asterisk AGI have the special command "SET MUSIC ON"
https://wiki.asterisk.org/wiki/display/AST/Asterisk+18+AGICommand_set+music
Set waiting tone for asterisk agi function processing
I have python code that acquires serial data from 2 devices and writes to a .txt file. Every 4-15 minutes there is approx 30-45 seconds of data missing in the .txt file and this is not acceptable for our use case. I've spent hours googling and searching SO about multiprocessing and serial port data acquisition and haven't come up with a solution.
Here is my code
gpsser = input(("Enter GPS comport as 'COM_': "))
ser = serial.Serial(port=gpsser,
baudrate=38400,
timeout=2,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS)
root = Tk()
root.title("DualEM DAQ")
path = filedialog.asksaveasfilename() + ".txt"
file = glob.glob(path)
filename = path
with open(filename, 'wb') as f:
w = csv.writer(f, dialect='excel')
w.writerow(['header'])
def sensor():
while True:
try:
NMEA1 = dser.readline().decode("ascii")
while dser.inWaiting() == 0:
pass
NMEA1_array = NMEA1.split(',')
NMEA2_array = NMEA2.split(',')
NMEA3_array = NMEA3.split(',')
NMEA4_array = NMEA4.split(',')
if NMEA1_array[0] == '$PDLGH':
value1 = NMEA1_array[2]
value2 = NMEA1_array[4]
if NMEA1_array[0] == '$PDLG1':
value3 = NMEA1_array[2]
value4 = NMEA1_array[4]
if NMEA1_array[0] == '$PDLG2':
value5 = NMEA1_array[2]
value6 = NMEA1_array[4]
return (float(value1), float(value2), float(value3),
float(value4), float(value5), float(value6),
except (IndexError, NameError, ValueError, UnicodeDecodeError):
pass
def gps():
while True:
try:
global Status, Latitude, Longitude, Speed, Truecourse, Date
global GPSQuality, Satellites, HDOP, Elevation, Time
while ser.inWaiting() == 0:
pass
msg = ser.readline()
pNMEA = pynmea2.parse(msg)
if isinstance(pNMEA, pynmea2.types.talker.RMC):
Latitude = pynmea2.dm_to_sd(pNMEA.lat)
Longitude = -(pynmea2.dm_to_sd(pNMEA.lon))
Date = pNMEA.datestamp
Time = datetime.datetime.now().time()
if () is not None:
return (Longitude, Latitude, Date, Time)
except (ValueError, UnboundLocalError, NameError):
pass
while True:
try:
with open(filename, "ab") as f:
data = [(gps() + sensor())]
writer = csv.writer(f, delimiter=",", dialect='excel')
writer.writerows(data)
f.flush()
print(data)
except (AttributeError, TypeError) as e:
pass
The program is writing to the file but I need help understanding why I'm losing 30-45 seconds of data every so often. Where is my bottle neck that is causing this to happen?
Here is an example of where the breaks are, note the breaks are approx 50 seconds in this case.
Breaks in writing data to csv
DB
Back when I used PySerial, I did this:
nbytes = ser.inWaiting()
if nbytes > 0:
indata = ser.read(nbytes)
#now parse bytes in indata to look for delimiter, \n in your case
#and if found process the input line(s) until delimiter not found
else:
#no input yet, do other processing or allow other things to run
#by using time.sleep()
Also note that new versions (3.0+) of PySerial have .in_waiting as a property not a method, so no (), it used to be .inWaiting().
You should not flush the serial port input. Data is arriving on its own timing into a buffer in the driver, not when your read happens, so you are throwing away data with your flush. You may need to add code to synchronize with the input stream.
I used threading with a queue and changed my mainloop to look like this.
while True:
try:
with open(filename, "ab") as f:
writer = csv.writer(f, delimiter=",", dialect='excel')
data = []
data.extend(gpsdata())
data.extend(dualemdata())
writer.writerows([data])
f.flush()
f.close()
dser.flushInput()
ser.flushInput()
print(data)
sleep(0.05)
except (AttributeError, TypeError) as e:
pass
I had to flush the serial port input data before the looping back to the read functions so it was reading new realtime data(this eliminated any lag of the incoming data stream). I've ran a 30 minute test and the time gaps appear to have go away. Thankyou to Cmaster for giving me some diagnostic ideas.
I have generated sequence of frequency sound from text file using :
import mmap
import math
import pyaudio
fh = open('/home/jay/Documents/try.txt', 'rb')
m = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ)
ba = bytearray(m)
#sudo apt-get install python-pyaudio
PyAudio = pyaudio.PyAudio
#See http://en.wikipedia.org/wiki/Bit_rate#Audio
BITRATE = 16000 #number of frames per second/frameset.
for freq in ba:
#See http://www.phy.mtu.edu/~suits/notefreqs.html
FREQUENCY = 300 + freq #Hz, waves per second, 261.63=C4-note.
LENGTH = 1 #seconds to play sound
NUMBEROFFRAMES = int(BITRATE * LENGTH)
RESTFRAMES = NUMBEROFFRAMES % BITRATE
WAVEDATA = ''
for x in xrange(NUMBEROFFRAMES):
WAVEDATA = WAVEDATA+chr(int(math.sin(x/((BITRATE/FREQUENCY)/math.pi))*127+128))
#fill remainder of frameset with silence
for x in xrange(RESTFRAMES):
WAVEDATA = WAVEDATA+chr(128)
p = PyAudio()
stream = p.open(format = p.get_format_from_width(1),
channels = 1,
rate = BITRATE,
output = True)
stream.write(WAVEDATA)
stream.stop_stream()
stream.close()
p.terminate()
(try.txt can be any text file you want)
But its having some noise in between frequency sound how can i remove it and save sequence of all frequncy played in .wave or .mp3 file?
Sorry i am still learning so if i am not clear in asking.
Thanks,
Jay
Biggest problem here is that you open/close audio stream at each frequency.
Instead, keep the stream open and you'll get a lot less "clicks". That doesn't mean you'll get no clicks, probably because processing time is sometimes too long and the stream is interrupted. The best way would be to multithread generation and write to be more reactive, but that's another story...
I also added .wav save capacity. My output filenames. Works very well.
Fixed code (runs with Python 3)
import mmap
import math
import pyaudio,wave
import array
fh = open('K:\out.txt', 'rb')
m = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ)
ba = bytearray(m)
#ba = [300,400,500,400,200]
#sudo apt-get install python-pyaudio
PyAudio = pyaudio.PyAudio
#See http://en.wikipedia.org/wiki/Bit_rate#Audio
BITRATE = 16000 #number of frames per second/frameset.
p = PyAudio()
stream = p.open(format = p.get_format_from_width(1),
channels = 1,
rate = BITRATE,
output = True)
wf=wave.open("K:\wavout.wav","wb")
wf.setnchannels(1)
wf.setsampwidth(p.get_sample_size(pyaudio.paInt8)) # byte = 8 bits else trashed
wf.setframerate(BITRATE)
for freq in ba:
#See http://www.phy.mtu.edu/~suits/notefreqs.html
FREQUENCY = 300 + freq #Hz, waves per second, 261.63=C4-note.
print('freq '+str(FREQUENCY))
LENGTH = 1 #seconds to play sound
NUMBEROFFRAMES = int(BITRATE * LENGTH)
RESTFRAMES = NUMBEROFFRAMES % BITRATE
WAVEDATA = list()
for x in range(NUMBEROFFRAMES):
v = int(math.sin(x/((BITRATE/FREQUENCY)/math.pi))*127+128)
WAVEDATA.append(v)
#fill remainder of frameset with silence
WAVEDATA+=[128]*RESTFRAMES
b = array.array('B', WAVEDATA).tostring()
wf.writeframes(b)
stream.write(b)
#print data
wf.close()
stream.stop_stream()
stream.close()
p.terminate()
import sys
import serial
import numpy as np
import matplotlib.pyplot as plt
from collections import deque
port = "COM11"
baud = 9600
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
a1 = deque([0.0]*100)
#ax = plt.axes(xlim=(0, 100), ylim=(0, 1000))
line, = plt.plot(a1)
plt.ion()
plt.ylim([0,1000])
try:
ser.open()
except:
sys.stderr.write("Error opening serial port %s\n" % (ser.portstr) )
sys.exit(1)
#ser.setRtsCts(0)
while 1:
# Read from serial port, blocking
data = ser.read(1)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data = data + ser.read(n)
#sys.stdout.write(data)
print(a1)
a1.appendleft((data))
datatoplot = a1.pop()
line.set_ydata(a1)
plt.draw()
I am getting a plot between serial port values and sample points. I want to plot serial plot values vs time. Is there a way to convert sample points to time values, something like how to we convert sample point to frequency values using freqs = scipy.fftpack.fftfreq(n, d)
Thanks
If you want to plot the data against time from the start of the program, then:
import time
t0 = time.time()
tlist = deque([np.nan] * 100)
while 1:
# read the serial data ...
# when you have read a sample, capture the time difference
# and put it into a queue (similarly to the data values)
deltat = time.time() - t0
dlist.appendleft((deltat))
# remember to pop the data, as well
dlist.pop()
a1.pop()
# set the x and y data
line.set_xdata(tlist)
line.set_ydata(a1)
# draw it
plt.draw()
Now you have the number of seconds from the start of the program on the X axis.
If you want to have the real time shown, then use datetime.datetime objects:
import datetime
dlist = deque([datetime.datetime.now()] * 100)
while 1:
# capture the serial data ...
dilst.appendleft((datetime.datetime.now()))
# everything else as above
This should give you a plot with real time on the X axis.
import sys
import serial
import numpy as np
import matplotlib.pyplot as plt
import time
from collections import deque
from scipy import arange
port = "COM13"
baud = 9600
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
t0=time.time()
tlist = deque([np.nan]*10)
a1 = deque([0.0]*10)
#ax = plt.axes(xlim=(0, 100), ylim=(0, 1000))
line, = plt.plot(a1)
plt.ion()
plt.ylim([-100,100])
plt.grid(b=True,which= 'major' , color= 'g' , linestyle= '--')
#plt.grid(b=True,which= 'minor' , color= '-m' , linestyle= '--')
try:
ser.open()
except:
sys.stderr.write("Error opening serial port %s\n" % (ser.portstr) )
sys.exit(1)
#ser.setRtsCts(0)
while 1:
# Read from serial port, blocking
data = ser.read(1)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data = data + ser.read(n)
#sys.stdout.write(data)
#print(a1)
#data1=int(data)-128
deltat = time.time() - t0
tlist.appendleft((deltat1))
datatoplot = tlist.pop()
a1.appendleft((data))
datatoplot = a1.pop()
line.set_xdata(tlist)
line.set_ydata(a1)
plt.hold(False)
plt.draw()
This is the complete code I used, and yes I had already changed that line.pop . But as I explained earlier in the comment I am not able to get the time values in x axis
i want readings of present GPS location, when i run the below code in raspberry pi, program prints 10-12 outputs and then it displays the error as below:
Traceback (most recent call last):
File "simplegpsparsing.py", line 24, in
get_present_gps()
File "simplegpsparsing.py", line 16, in get_present_gps
lat, _, lon= line.split(',')[2:5]
ValueError: need more than 0 values to unpack
i want present value of GPS( buffers should be updated with immediate GPS) so that present GPS values can be known.
my code goes as below :
import os
import serial
def get_present_gps:
ser= serial.Serial('/dev/ttyAMA0',9600)
ser.open()
while True :
f=open('/home/pi/Desktop/gps1','w')
data=ser.read(ser.inWaiting()) # read no.of bytes in waiting
f.write(data) #write data into file
f.flush() # flush(method) from buffer into os buffer
os.fsync(f.fileno()) #ensure to write from os buffer(internal buffers)into disk
f = open('/home/pi/Desktop/gps1','r') # fetch the required file
for line in f.read().split('\n') :
if line.startswith( '$GPGGA' ) :
lat, _, lon = line.strip().split(',')[2:5]
try :
lat = float( lat )
lon = float( lon )
print lat
print lon
except :
pass
# something wrong happens with your data, print some error messages
get_present_gps()
if the serial port is left open without closing, will it create any problem? will the above code meet my requirement i.e getting the instantaneous value?
Here is a thought: parse the data string into chunks that are newline terminated; leave "unfinished" strings in the buffer until the next time around the loop. Untested, this will look something like this:
keepThis = ''
while True :
data=keepThis + ser.read(ser.inWaiting()) # read no.of bytes in waiting
m = data.split("\n") # get the individual lines from input
if len(m[-1]==0): # true if only complete lines present (nothing after last newline)
processThis = m
keepThis = ''
else:
processThis = m[0:-1] # skip incomplete line
keepThis = m[-1] # fragment
# process the complete lines:
for line in processThis:
if line.startswith( '$GPGGA' ) :
try :
lat, _, lon = line.strip().split(',')[2:5] # move inside `try` just in case...
lat = float( lat )
lon = float( lon )
print lat
print lon
except :
pass