enregistrement audio pyaudio python

Aug 31 2020

J'essaye d'enregistrer l'audio du microphone avec Python. Et j'ai le code suivant:

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()

Mon code fonctionne bien, mais lorsque je joue mon enregistrement, je n'entends aucun son dans mon fichier de sortie final ( file.wav).

Pourquoi des problèmes surviennent-ils ici et comment les résoudre?

Réponses

1 Azr Sep 08 2020 at 03:31

Votre code fonctionne correctement. Le problème auquel vous êtes confronté est dû aux droits d'administrateur. Le fichier audio a des données constantes 0, par conséquent, vous ne pouvez pas écouter le son dans le fichier wav généré. Je suppose que votre microphone est installé et fonctionne correctement. Si vous n'êtes pas sûr de l'état de l'installation audio, procédez comme suit selon le système d'exploitation:

MAC OS: Préférences Système-> Son-> Entrée et là, vous pouvez visualiser les barres comme faisant du son. Assurez-vous que le type de périphérique sélectionné est Intégré.

Windos OS: Paramètres du son et test du microphone en cliquant sur écoutez cet appareil, vous pourrez le décocher plus tard car il rebouclera votre voix vers les haut-parleurs et créera de gros bruits.

Vous utilisez très probablement Mac OS. J'ai eu le même problème, car j'utilisais l'éditeur Atom pour exécuter le code python. Essayez d'exécuter votre code à partir du terminal de Mac OS (ou de Power Shell si vous utilisez Windows), (au cas où une fenêtre contextuelle apparaît pour accéder au microphone sous Mac OS, appuyez sur OK). C'est ça! votre code enregistrera bien. En tant que testeur, veuillez exécuter le code ci-dessous pour vérifier si vous pouvez visualiser le son et assurez-vous de l'exécuter via Terminal (pas d'éditeurs ni d'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()

Enregistrez ce fichier sous le nom voice.py dans un dossier (disons AUDIO). Ensuite, accédez au dossier AUDIO à partir de la commande du terminal, puis exécutez-le en utilisant:

python3 voice.py

ou

python voice.py

en fonction de votre nom d'environnement python.

user0814 Sep 15 2020 at 09:00

En utilisant print(sd.query_devices()), je vois une liste d'appareils comme ci-dessous:

  1. Microsoft Sound Mapper - Entrée, MME (2 entrées, 0 sortie)
  2. Microphone (AudioHubNano2D_V1.5, MME (2 entrées, 0 sortie)
  3. Microphone interne (Conexant S, MME (2 entrées, 0 sortie)
  4. ...

Cependant, si j'utilise device = 0, je peux toujours recevoir le son du microphone USB, qui est le numéro de périphérique 1. Est-ce par défaut, tout le signal audio est transmis au Sound Mapper? Cela signifie que si j'utilise device = 0, j'obtiendrai tout le signal audio de toutes les entrées audio; et si je veux juste une entrée audio d'un périphérique particulier, je dois choisir son numéro x comme device = x.

J'ai une autre question: est-il possible de capturer le signal audio des appareils 1 et 2 dans une seule application mais de manière séparée?