pyaudio callback called only once - python-3.x

I try use pyaudio with the callback option, and I want to yield the data instead of reading from a file. When I use the callback option, it gets called only once.
There is another question with the same problem, but it doesn't have an answer. I have made a minimal reproducable example. The code works when blocking is used.
import time
import numpy as np
import scipy.signal
import sounddevice as sd
import pyaudio
sample_rate=44100
max_amp = 2**(15)-1
f0 = 500
duration = 1
f1 = 3000
x = np.arange(0, duration, 1/sample_rate)
y_float = max_amp*scipy.signal.chirp(x, f0, duration, f1)
y = y_float.astype(np.int16)
data = y.tostring()
def create_data_generator(data):
periodsize = 1000
for i in range(int(len(data)/(periodsize))):
chunk = data[periodsize*i:periodsize*(i+1)]
yield chunk
data_generator = create_data_generator(data)
def callback(in_data, frame_count, time_info, status):
data = next(data_generator)
return (data, pyaudio.paContinue)
# -------- blocking------------------
# periodsize = 1000
# p = pyaudio.PyAudio()
# stream = p.open(format=pyaudio.paInt16,
# channels=1,
# rate=sample_rate,
# output=True)
# start = time.time()
# for i in range(int(len(data)/(periodsize))):
# chunk, status = callback(0, 0, 0, 0)
# stream.write(chunk)
# time.sleep(duration-(time.time()-start))
# stream.stop_stream()
# stream.close()
# p.terminate()
# -------- callback ------------------
periodsize = 1000
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16,
channels=1,
rate=sample_rate,
output=True,
stream_callback=callback)
# start the stream (4)
stream.start_stream()
# wait for stream to finish (5)
while stream.is_active():
time.sleep(0.1)
# stop stream (6)
stream.stop_stream()
stream.close()
# close PyAudio (7)
p.terminate()

Related

Transmit buffer full

I am executing a python and can code to make a data log but when I run it I get the error Transmit buffer full
This is the code
#!/usr/bin/python3
#
## obdii_logger.py
#
# This python3 program sends out OBDII request then logs the reply to the sd card.
# For use with PiCAN boards on the Raspberry Pi
# http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html
#
# Make sure Python-CAN is installed first http://skpang.co.uk/blog/archives/1220
#
# 24-08-16 SK Pang
#
import RPi.GPIO as GPIO
import can
import time
import os
import queue
from threading import Thread
led = 22
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(led,GPIO.OUT)
GPIO.output(led,True)
# For a list of PIDs visit https://en.wikipedia.org/wiki/OBD-II_PIDs
ENGINE_COOLANT_TEMP = 0x05
ENGINE_RPM = 0x0C
VEHICLE_SPEED = 0x0D
MAF_SENSOR = 0x10
O2_VOLTAGE = 0x14
THROTTLE = 0x11
PID_REQUEST = 0x7DF
PID_REPLY = 0x7E8
outfile = open('log.txt','w')
print('\n\rCAN Rx test')
print('Bring up CAN0....')
# Bring up can0 interface at 500kbps
os.system("sudo /sbin/ip link set can0 up type can bitrate 500000")
time.sleep(0.1)
print('Ready')
try:
bus = can.interface.Bus(channel='can0', bustype='socketcan')
except OSError:
print('Cannot find PiCAN board.')
GPIO.output(led,False)
exit()
def can_rx_task(): # Receive thread
while True:
message = bus.recv()
if message.arbitration_id == PID_REPLY:
q.put(message) # Put message into queue
def can_tx_task(): # Transmit thread
while True:
GPIO.output(led,True)
# Sent a Engine coolant temperature request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,ENGINE_COOLANT_TEMP,0x00,0x00,0x00,0x00,0x00], is_extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Engine RPM request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,ENGINE_RPM,0x00,0x00,0x00,0x00,0x00], is_extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Vehicle speed request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,VEHICLE_SPEED,0x00,0x00,0x00,0x00,0x00],is_extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Throttle position request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,THROTTLE,0x00,0x00,0x00,0x00,0x00],is_extended_id=False)
bus.send(msg)
time.sleep(0.05)
GPIO.output(led,False)
time.sleep(0.1)
q = queue.Queue()
rx = Thread(target = can_rx_task)
rx.start()
tx = Thread(target = can_tx_task)
tx.start()
temperature = 0
rpm = 0
speed = 0
throttle = 0
c = ''
count = 0
# Main loop
try:
while True:
for i in range(4):
while(q.empty() == True): # Wait until there is a message
pass
message = q.get()
c = '{0:f},{1:d},'.format(message.timestamp,count)
if message.arbitration_id == PID_REPLY and message.data[2] == ENGINE_COOLANT_TEMP:
temperature = message.data[3] - 40 #Convert data into temperature in degree C
if message.arbitration_id == PID_REPLY and message.data[2] == ENGINE_RPM:
rpm = round(((message.data[3]*256) + message.data[4])/4) # Convert data to RPM
if message.arbitration_id == PID_REPLY and message.data[2] == VEHICLE_SPEED:
speed = message.data[3] # Convert data to km
if message.arbitration_id == PID_REPLY and message.data[2] == THROTTLE:
throttle = round((message.data[3]*100)/255) # Conver data to %
c += '{0:d},{1:d},{2:d},{3:d}'.format(temperature,rpm,speed,throttle)
print('\r {} '.format(c))
print(c,file = outfile) # Save data to file
count += 1
except KeyboardInterrupt:
#Catch keyboard interrupt
GPIO.output(led,False)
outfile.close() # Close logger file
os.system("sudo /sbin/ip link set can0 down")
print('\n\rKeyboard interrtupt')
I tried the command sudo ifconfig can0 txqueuelen 1000 but I still keep getting the same error Transmit buffer full

How can I transcribe audio in real time with pyaudio

I'm having a hard time implementing real time audio transcriptions with a microphone using the pyaudio library. I've developed my own speech recognition model with pytorch. The model is given wrong predictions most of the time. This is the sample code:
import torch
import pyaudio as pa
import numpy as np
from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC,AutoTokenizer
processor = Wav2Vec2Processor.from_pretrained("facebook/wav2vec2- base-960h")
model = Wav2Vec2ForCTC.from_pretrained("facebook/wav2vec2-base-960h")
frames_per_buffer = 3200
format = pyaudio.paInt16
channel = 1
rate = 16000
p = pyaudio.PyAudio()
def record_microphone():
stream = p.open(rate=rate,channels=channel,format = format,\
input=True,frames_per_buffer=frames_per_buffer)
frames = []
seconds=1
for i in range(0,int(rate/frames_per_buffer * seconds)):
data = stream.read(frames_per_buffer)
frames.append(data)
stream.stop_stream()
stream.close()
return np.frombuffer(b''.join(frames),dtype=np.int16)
def terminate():
p.terminate()
def predict():
audio = record_microphone()
input_values = processor(torch.FloatTensor(audio),sampling_rate=16_000,
return_tensors="pt", padding="longest").input_values
logits = model(input_values).logits
pred = torch.argmax(logits,dim=-1)
pred_word = processor.batch_decode(pred)[0]
print(pred_word.lower()+" ",end="")
return pred_word
if "__name__" == "__main__":
try:
predict()
finally:
terminate()

How to make a function that breaks a while loop that recording audio?

I'm trying to make a python gui that has 2 buttons, one for recording audio and one to stop recording. the code runs on a raspberry pi 3 with a usb mic connected already.
I've done the recording button, and now I'm stuck on the stop recording button.
the recording button runs in a while loop and I need that the 'stop' button will simply stop the while loop and save the recording to a file.
from sense_hat import SenseHat
import time
import Tkinter
import ttk
import pyaudio
import wave
sense = SenseHat()
sense.clear()
snsui = Tkinter.Tk()
snsui.style = ttk.Style()
snsui.style.theme_use("classic")
snsui.geometry('130x150')
snsui.resizable(0,0)
#img = PhotoImage(file='/home/pi/sensehat/fav.ico')
#snsui.Tkinter.call('wm', 'iconphoto', root._w, img)
#snsui.iconbitmap(default = "/home/pi/sensehat/image.png")
snsui.title("Sensors UI")
snsui.configure(background='light gray')
snsui.style.configure("TButton", padding=6, relief="flat",
background="turquoise",fieldbackground="black", foreground='royal blue')
form_1 = pyaudio.paInt16 # 16-bit resolution
chans = 1 # 1 channel
samp_rate = 44100 # 44.1kHz sampling rate
chunk = 4096 # 2^12 samples for buffer
record_secs = 3 # seconds to record
dev_index = 2 # device index found by p.get_device_info_by_index(ii)
audio = pyaudio.PyAudio() # create pyaudio instantiation
# create pyaudio stream
stream = audio.open(format = form_1,rate = samp_rate,channels = chans, \
input_device_index = dev_index,input = True, \
frames_per_buffer=chunk)
recording = True
def record(recording,s,a,c,ch,sr):
if recording == False:
recording = True
print('start recording')
else:
recording = False
print('trying to stop')
frames = []
# loop through stream and append audio chunks to frame array
# ii in range(0,int((samp_rate/chunk)*record_secs)):
while recording:
data = stream.read(chunk)
frames.append(data)
print("finished recording")
# stop the stream, close it, and terminate the pyaudio instantiation
stream.stop_stream()
stream.close()
audio.terminate()
wav_output_filename = 'test1.wav' # name of .wav file
# save the audio frames as .wav file
wavefile = wave.open(wav_output_filename,'wb')
wavefile.setnchannels(chans)
wavefile.setsampwidth(audio.get_sample_size(form_1))
wavefile.setframerate(samp_rate)
wavefile.writeframes(b''.join(frames))
wavefile.close()
B_recording = ttk.Button(snsui, text =" Record ", command = record(recording,stream,audio,chunk,chans,samp_rate))
B_recording.pack()
snsui.mainloop()
You can create boolean flag which value is changed by stop button. Then just add if statement to your while loop, and break when the flag have desired value.

Continuesly streaming audio signal real time infinitely, Python

I have a simple question, while streaming audio signal from audio jack in Python, using pyaudio library how can I keep streaming the audio signal until I choose to "stop" the program.
Example: The way we capture our web camera frames infinitely under a infinite while loop.
For example: In this code(take from link)that records the stream just for 5 seconds what will be the modification that will serve my purpose
import pyaudio
import wave
import numpy as np
CHUNK = 44100
FORMAT = pyaudio.paInt32
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
print("* recording")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
audio_data = np.fromstring(data, dtype=np.int32)
print(data)
print(audio_data)
frames.append(data)
print("* done recording")
stream.stop_stream()
stream.close()
p.terminate()
Also the code given on this link (Handling audio data using callback mode) records it for 4-5 seconds.
I will be really grateful if someone could help me with this!!
Well , Meanwhile I figured out solution
import pyaudio
import numpy as np
import pylab
import time
import sys
import matplotlib.pyplot as plt
RATE = 44100
CHUNK = int(RATE/20) # RATE / number of updates per second
def soundplot(stream):
t1=time.time()
#use np.frombuffer if you face error at this line
data = np.fromstring(stream.read(CHUNK),dtype=np.int16)
print(data)
if __name__=="__main__":
p=pyaudio.PyAudio()
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,
frames_per_buffer=CHUNK)
for i in range(sys.maxsize**10):
soundplot(stream)
stream.stop_stream()
stream.close()
p.terminate()
And this post here will help you in simple and concrete way
Hello this is my code with which audio and video is recorded separately and pause the audio and video I hope it helps you
import cv2
import numpy as np
from datetime import datetime
import gtk
import keyboard
import pyaudio
import wave
import sys
flagrecord=True
#chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
ropen=True
chunk = int(RATE/20)
def show_webcam(flagrecord):
cam = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
frame_width = int(cam.get(3))
frame_height = int(cam.get(4))
FONT = cv2.FONT_HERSHEY_PLAIN
filename = datetime.now().strftime("%Y-%m-%d_%H.%M.%S") + ".avi"
filenamea = datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
p = pyaudio.PyAudio()
stream = p.open(format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True,
frames_per_buffer = chunk)
out = cv2.VideoWriter(filename,fourcc, 20, (frame_width,frame_height))
all = []
aux = []
stream.start_stream()
flagaudio=False
while True:
ret_val, img = cam.read()
title = datetime.now().strftime("%Y-%m-%d*%H:%M:%S")
if flagrecord:
img = cv2.flip(img,1)
cv2.putText(img, "REC", (40,40), FONT, 3 , (0,0,255), 3)
cv2.circle(img, (20,20), 10 , (0,0,255), -1)
cv2.rectangle(img, (30,430),(600,480),(0,0,0), -1)
cv2.putText(img, title, (40,470), FONT, 3 , (255,255,255), 2)
cv2.imshow('Grabacion de Audiencias', img)
data = stream.read(chunk)
aux.append(data)
out.write(img)
else:
img = cv2.flip(img,1)
cv2.putText(img, "PAUSE", (40,40), FONT, 3 , (255,0,0), 3)
cv2.circle(img, (20,20), 10 , (255,0,0), -1)
cv2.rectangle(img, (50,430),(570,480),(0,0,0), -1)
cv2.putText(img, "Audiencias En Pausa", (60,470), FONT, 3 , (255,0,0), 2)
cv2.imshow('Grabacion de Audiencias', img)
if flagaudio:
all+=aux
del aux[:]
data= 0
stream.stop_stream()
else:
pass
q=cv2.waitKey(1)
if q == 27:
break
if q == ord('p'):
flagrecord=False
flagaudio = True
if q == ord('c'):
flagrecord=True
flagaudio=False
stream.start_stream()
if q == ord('q'):
break
cam.release()
out.release()
cv2.destroyAllWindows()
stream.close()
p.terminate()
all+=aux
data = ''.join(all)
wf = wave.open(filenamea, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(data)
wf.close()
def main():
show_webcam(mirror=True)
if __name__ == '__main__':
main()

Filling queue from python iterator

I would like to create a queue which is filled from an iterator. In the following MWE however, always the same value is enqueued:
import tensorflow as tf
import numpy as np
# data
imgs = [np.random.randn(i,i) for i in [2,3,4,5]]
# iterate through data infinitly
def data_iterator():
while True:
for img in imgs:
yield img
it = data_iterator()
# create queue for data
q = tf.FIFOQueue(capacity=5, dtypes=[tf.float64])
# feed next element from iterator
enqueue_op = q.enqueue(list(next(it)))
# setup queue runner
numberOfThreads = 1
qr = tf.train.QueueRunner(q, [enqueue_op] * numberOfThreads)
tf.train.add_queue_runner(qr)
# dequeue
dequeue_op = q.dequeue()
dequeue_op = tf.Print(dequeue_op, data=[dequeue_op], message="dequeue()")
# We start the session as usual ...
with tf.Session() as sess:
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
for i in range(10):
data = sess.run(dequeue_op)
print(data)
.
coord.request_stop()
coord.join(threads)
Do I necessarily have to use a feed_dict? If yes, how do I have to used it in combination with the QueueRunner?
When running
enqueue_op = q.enqueue(list(next(it)))
tensorflow will execute list(next(it)) exactly one time. Thereafter it will save this first list and add it to q every time you run enqueue_op. To avoid this you must use a placeholder. Feeding placeholders is not compatible with tf.train.QueueRunner. Instead use this:
import tensorflow as tf
import numpy as np
import threading
# data
imgs = [np.random.randn(i,i) for i in [2,3,4,5]]
# iterate through data infinitly
def data_iterator():
while True:
for img in imgs:
yield img
it = data_iterator()
# create queue for data
q = tf.FIFOQueue(capacity=5, dtypes=[tf.float64])
# feed next element from iterator
img_p = tf.placeholder(tf.float64, [None, None])
enqueue_op = q.enqueue(img_p)
dequeue_op = q.dequeue()
with tf.Session() as sess:
coord = tf.train.Coordinator()
def enqueue_thread():
with coord.stop_on_exception():
while not coord.should_stop():
sess.run(enqueue_op, feed_dict={img_p: list(next(it))})
numberOfThreads = 1
for i in range(numberOfThreads):
threading.Thread(target=enqueue_thread).start()
for i in range(3):
data = sess.run(dequeue_op)
print(data)

Resources