3

I am trying to record audio from the microphone with Python. And I have following code:

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

My code works fine, but when I play my recording, I don't hear any sound in my final output file (file.wav).

Why do problems occur here and how do I fix them?

4
  • What is the track here? Are you saying if there is external audio being played, you don't get any output? Or are you referring to track as the final recording itself? Commented Sep 4, 2020 at 0:16
  • If you meant that you play audio track and final results file.wav should have it recorded. Make sure, your mic was set up and when you run program, the recording starts. When you press enter it stops. So have some time in between to get it recorded. Commented Sep 4, 2020 at 3:14
  • @Haazeen, How can i find out did my mic be set up?
    – Nikto
    Commented Sep 4, 2020 at 5:35
  • 1
    when dealing with a possible hardware slant its helpful to mention in your question what OS you're on Commented Sep 7, 2020 at 11:09

2 Answers 2

1

Your code is working fine. The problem you are facing is due to the admin rights. The audio file has constant 0 data, therefore, you can't listen to sound in the generated wav file. I suppose your microphone device is installed and working properly. If you are not sure about the audio installation status, then as per operating system do these steps:

MAC OS: System Preferences->Sound->Input and there you can visualize the bars as make some sound. Make sure the selected device type is Built-in.

enter image description here

Windos OS: Sound settings and test Microphone by click listen to this device, you may later uncheck it because it will loop back your voice to speakers and will create big noises.

enter image description here

Most probably you are using Mac OS. I had the similar issue, because I was using Atom editor to run the python code. Try to run your code from the terminal of Mac OS (or Power Shell if you are using windows), (in case a popup appears for access to microphone on Mac OS, press Ok). Thats it! your code will record fine. As a tester, please run the code below to check if you can visualize the sound, and make sure to run it through Terminal (No editors or IDEs).

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

Save this file as voice.py to a folder (let say AUDIO). Then cd to AUDIO folder from the terminal command and then execute it using:

python3 voice.py

or

python voice.py

depending on your python env name.

enter image description here

3
  • How to split channel data in the display, I mean one channel one signal line? And is there a way to select audio sources? For example, besides the build-in microphone, I have a USB-microphone plugged-in my computer, which I want to use as audio source.
    – djsg
    Commented Sep 12, 2020 at 9:25
  • 1) Change the list of audio channels in above code to: channels = [1,2]. Then plotdata will be of shape (44100,2), where first column is of channel 1 data and second is channel 2 data. To select channel 1: plotdata = plotdata[:,0] # 0 for ch1 , 1 for ch2 and then: plotdata = plotdata.reshape(plotdata.shape[0],1) .
    – Trees
    Commented Sep 13, 2020 at 1:47
  • 2) To select device, you need to know the index of device using sounddevice: import sounddevice as sd print(sd.query_devices()) , in my case it prints > 0 Built-in Microphone, Core Audio (2 in, 0 out) < 1 Built-in Output, Core Audio (0 in, 2 out) 2 EpocCam Microphone, Core Audio (2 in, 2 out), so the index 0 is for my built-in microphone. In above code device = 0, is for built-in, in case to select EpocCam, device = 2. I hope that will be helpful :)
    – Trees
    Commented Sep 13, 2020 at 1:49
0

By using print(sd.query_devices()), I see a list of devices as below:

  1. Microsoft Sound Mapper - Input, MME (2 in, 0 out)
  2. Microphone (AudioHubNano2D_V1.5, MME (2 in, 0 out)
  3. Internal Microphone (Conexant S, MME (2 in, 0 out)
  4. ...

However, if i use device = 0, I can still receive sound from the USB-microphone, which is device number 1. Is it by default, all the audio signal goes to the Sound Mapper? That means if I use device = 0, I will get all audio signal from all audio inputs; and if I just want audio input from one particular device, I need to choose its number x as device = x.

I have another question: is it possible to capture audio signal from device 1 and 2 in one application but in separate manner?

1
  • Try sd.default.device = 2, also make sure the device has permission from OS for the input resources. The terminal is better option in that case to run the code, than running through any editor.
    – Trees
    Commented Nov 9, 2020 at 7:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.