He tenido algunos problemas al intentar reproducir y grabar audio sincrónicamente hacia/desde un dispositivo, en este caso, los parlantes y el micrófono de mi computadora portátil.
El problema
Intenté implementar esto usando los módulos de Python: "dispositivo de sonido" y "pyaudio"; pero ambas implementaciones tienen este extraño problema en el que los primeros cuadros de audio grabado siempre son cero. ¿Alguien más ha experimentado este tipo de problema? Este problema parece ser independiente del tamaño de fragmento que se utiliza (es decir, siempre la misma cantidad de muestras es cero).
¿Hay algo que pueda hacer para evitar que esto suceda?
Código
import queue import matplotlib.pyplot as plt import numpy as np import pyaudio import soundfile as sf FRAME_SIZE = 512 excitation, fs = sf.read("excitation.wav", dtype=np.float32) # Instantiate PyAudio p = pyaudio.PyAudio() q = queue.Queue() output_idx = 0 mic_buffer = np.zeros((excitation.shape[0] + FRAME_SIZE - (excitation.shape[0] % FRAME_SIZE), 1)) def rec_play_callback(in_data, framelength, time_info, status): global output_idx # print status of playback in case of event if status: print(f"status: {status}") chunksize = min(excitation.shape[0] - output_idx, framelength) # write data to output buffer out_data = excitation[output_idx:output_idx + chunksize] # write input data to input buffer inputsamples = np.frombuffer(in_data, dtype=np.float32) if not np.sum(inputsamples): print("Empty frame detected") # send input data to buffer for main thread q.put(inputsamples) if chunksize < framelength: out_data[chunksize:] = 0 return (out_data.tobytes(), pyaudio.paComplete) output_idx += chunksize return (out_data.tobytes(), pyaudio.paContinue) # Define playback and record stream stream = p.open(rate=fs, channels=1, frames_per_buffer=FRAME_SIZE, format=pyaudio.paFloat32, input=True, output=True, input_device_index=1, # Macbook Pro microphone output_device_index=2, # Macbook Pro speakers stream_callback=rec_play_callback) stream.start_stream() input_idx = 0 while stream.is_active(): data = q.get(timeout=1) mic_buffer[input_idx:input_idx + FRAME_SIZE, 0] = data input_idx += FRAME_SIZE stream.stop_stream() stream.close() p.terminate() # Plot captured microphone signal plt.plot(mic_buffer) plt.show()Producción
Empty frame detected
Editar: ejecutar esto en MacOS usando CoreAudio. Esto podría ser relevante, como lo señaló @ 2e0byo.
Esta es una pregunta general y nos falta una vista completa de su arquitectura. Así que lo mejor que podemos hacer es señalar algunos conceptos generales.
En los sistemas de procesamiento de señales digitales, muy a menudo hay un espacio en blanco inicial y un retraso constante en la señal procesada. Esto suele estar relacionado con el tamaño de un búfer y la tasa de muestreo. En algunos sistemas, es posible que ni siquiera sepa que el búfer está allí, por ejemplo, como parte de un controlador de dispositivo al que no puede acceder la API de nivel de usuario.
Para reducir un desplazamiento debido al almacenamiento en búfer, debe hacer que el búfer sea más pequeño o que la muestra sea más rápida. Luego, su sistema tiene que procesar paquetes más pequeños pero con más frecuencia, y los cambios en el tamaño del paquete o en el reloj de muestreo pueden afectar el procesamiento de la señal, según el contenido de la señal y el tipo de procesamiento de la señal que esté realizando. Por lo tanto, hacer cualquiera de estos cambios conlleva un aumento en la sobrecarga por datos procesados a través del sistema y también puede afectar el rendimiento de otras maneras.
Un enfoque que utilizo para depurar problemas de este tipo es tratar de encontrar el búfer que está configurando el desplazamiento, rastreando el código fuente si es necesario, y luego ver si puede ajustar el tamaño o la frecuencia de muestreo y aun así lograr el rendimiento que necesita. en términos de rendimiento y precisión.