Python de grabación de audio pyaudio
Estoy intentando grabar audio desde el micrófono con Python. Y tengo el siguiente código:
import pyaudio
import wave
import threading
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
CHUNK = 1024
WAVE_OUTPUT_FILENAME = "file.wav"
stop_ = False
audio = pyaudio.PyAudio()
stream = audio.open(format=FORMAT, channels=CHANNELS,
rate=RATE, input=True,
frames_per_buffer=CHUNK)
def stop():
global stop_
while True:
if not input('Press Enter >>>'):
print('exit')
stop_ = True
t = threading.Thread(target=stop, daemon=True).start()
frames = []
while True:
data = stream.read(CHUNK)
frames.append(data)
if stop_:
break
stream.stop_stream()
stream.close()
audio.terminate()
waveFile = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
waveFile.setnchannels(CHANNELS)
waveFile.setsampwidth(audio.get_sample_size(FORMAT))
waveFile.setframerate(RATE)
waveFile.writeframes(b''.join(frames))
waveFile.close()
Mi código funciona bien, pero cuando reproduzco mi grabación, no escucho ningún sonido en mi archivo de salida final ( file.wav).
¿Por qué surgen problemas aquí y cómo los soluciono?
Respuestas
Tu código funciona bien. El problema al que se enfrenta se debe a los derechos de administrador. El archivo de audio tiene datos 0 constantes, por lo tanto, no puede escuchar el sonido en el archivo wav generado. Supongo que su dispositivo de micrófono está instalado y funcionando correctamente. Si no está seguro del estado de la instalación de audio, siga estos pasos según el sistema operativo:
MAC OS: Preferencias del sistema-> Sonido-> Entrada y allí puedes visualizar las barras como hacer algún sonido. Asegúrese de que el tipo de dispositivo seleccionado sea Integrado.
Sistema operativo Windos: configuración de sonido y micrófono de prueba haciendo clic en escuchar este dispositivo, más tarde puede desmarcarlo porque volverá su voz a los altavoces y creará grandes ruidos.
Lo más probable es que esté utilizando Mac OS. Tuve un problema similar, porque estaba usando el editor Atom para ejecutar el código Python. Intente ejecutar su código desde el terminal de Mac OS (o Power Shell si está usando Windows), (en caso de que aparezca una ventana emergente para acceder al micrófono en Mac OS, presione Ok). ¡Eso es! su código se grabará bien. Como probador, ejecute el código a continuación para verificar si puede visualizar el sonido y asegúrese de ejecutarlo a través de Terminal (sin editores ni IDE).
import queue
import sys
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
import sounddevice as sd
# Lets define audio variables
# We will use the default PC or Laptop mic to input the sound
device = 0 # id of the audio device by default
window = 1000 # window for the data
downsample = 1 # how much samples to drop
channels = [1] # a list of audio channels
interval = 30 # this is update interval in miliseconds for plot
# lets make a queue
q = queue.Queue()
# Please note that this sd.query_devices has an s in the end.
device_info = sd.query_devices(device, 'input')
samplerate = device_info['default_samplerate']
length = int(window*samplerate/(1000*downsample))
# lets print it
print("Sample Rate: ", samplerate)
# Typical sample rate is 44100 so lets see.
# Ok so lets move forward
# Now we require a variable to hold the samples
plotdata = np.zeros((length,len(channels)))
# Lets look at the shape of this plotdata
print("plotdata shape: ", plotdata.shape)
# So its vector of length 44100
# Or we can also say that its a matrix of rows 44100 and cols 1
# next is to make fig and axis of matplotlib plt
fig,ax = plt.subplots(figsize=(8,4))
# lets set the title
ax.set_title("PyShine")
# Make a matplotlib.lines.Line2D plot item of color green
# R,G,B = 0,1,0.29
lines = ax.plot(plotdata,color = (0,1,0.29))
# We will use an audio call back function to put the data in queue
def audio_callback(indata,frames,time,status):
q.put(indata[::downsample,[0]])
# now we will use an another function
# It will take frame of audio samples from the queue and update
# to the lines
def update_plot(frame):
global plotdata
while True:
try:
data = q.get_nowait()
except queue.Empty:
break
shift = len(data)
plotdata = np.roll(plotdata, -shift,axis = 0)
# Elements that roll beyond the last position are
# re-introduced
plotdata[-shift:,:] = data
for column, line in enumerate(lines):
line.set_ydata(plotdata[:,column])
return lines
ax.set_facecolor((0,0,0))
# Lets add the grid
ax.set_yticks([0])
ax.yaxis.grid(True)
""" INPUT FROM MIC """
stream = sd.InputStream( device = device, channels = max(channels), samplerate = samplerate, callback = audio_callback)
""" OUTPUT """
ani = FuncAnimation(fig,update_plot, interval=interval,blit=True)
with stream:
plt.show()
Guarde este archivo como voice.py en una carpeta (digamos AUDIO). Luego cd a la carpeta AUDIO desde el comando de terminal y luego ejecútelo usando:
python3 voice.py
o
python voice.py
dependiendo de su nombre de env de Python.
Al usar print(sd.query_devices()), veo una lista de dispositivos como la siguiente:
- Microsoft Sound Mapper - Entrada, MME (2 entradas, 0 salidas)
- Micrófono (AudioHubNano2D_V1.5, MME (2 entradas, 0 salidas)
- Micrófono interno (Conexant S, MME (2 entradas, 0 salidas)
- ...
Sin embargo, si lo uso device = 0, todavía puedo recibir sonido del micrófono USB, que es el dispositivo número 1. ¿De forma predeterminada, toda la señal de audio va al Sound Mapper? Eso significa que si lo uso device = 0, obtendré toda la señal de audio de todas las entradas de audio; y si solo quiero entrada de audio de un dispositivo en particular, necesito elegir su número x como device = x.
Tengo otra pregunta: ¿es posible capturar la señal de audio del dispositivo 1 y 2 en una aplicación pero de manera separada?