Python de grabación de audio pyaudio

Aug 31 2020

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

1 Azr Sep 08 2020 at 03:31

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.

user0814 Sep 15 2020 at 09:00

Al usar print(sd.query_devices()), veo una lista de dispositivos como la siguiente:

  1. Microsoft Sound Mapper - Entrada, MME (2 entradas, 0 salidas)
  2. Micrófono (AudioHubNano2D_V1.5, MME (2 entradas, 0 salidas)
  3. Micrófono interno (Conexant S, MME (2 entradas, 0 salidas)
  4. ...

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?