I have this Python script that I'm running on my Ubuntu laptop to get the live ambient noise levels from the microphone on the laptop. I don't think this script works well though and I can't figure out why. I suspected it might just be a long period size but I'm not sure if that's it. Can someone help me understand what's wrong with this script? Thank you!
import alsaaudio
import audioop
import time
import math
# Set the audio parameters
device = 'default'
channels = 1 # mono
sample_rate = 44100 # 44.1 kHz
format = alsaaudio.PCM_FORMAT_S16_LE
# Open the audio input stream
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, device)
inp.setchannels(channels)
inp.setrate(sample_rate)
inp.setformat(format)
inp.setperiodsize(256)
# Main loop to continuously print audio levels
try:
while True:
# Read audio data from the microphone
_, data = inp.read()
# Calculate the peak audio level in decibels
rms = audioop.rms(data, 2) # 2 for sample width 16-bit
# Print the decibel level without dynamic range adjustment
decibels = 20 * math.log10(rms)
print(f"Decibels: {decibels:.2f} dB")
time.sleep(0.01) # Adjust the sleep duration as needed
except KeyboardInterrupt:
print("Stopping the script.")
I expect this script to be sensitive and show an immediate jump in the decibel values if I make a sound. That unfortunately is not the case right now and I'm not sure why. I used the sounddevice library and it seems to work well but I can't get the same result with pyalsaaudio.
EDIT: Based on comments by @fdcpp, I have modified my script and I get negative values and don't know why
import alsaaudio
import audioop
import math
import struct
# Set the audio parameters
device = 'default'
channels = 1 # mono
sample_rate = 44100 # 44.1 kHz
format = alsaaudio.PCM_FORMAT_S16_LE
# Open the audio input stream
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, device, channels=channels, rate=sample_rate, format=format, periodsize=1024)
# Main loop to continuously print audio levels
try:
while True:
# Read audio data from the microphone
_, data = inp.read()
# Convert byte data to 16-bit integer format. Have tried with and without this and get the same result.
samples = struct.unpack('<' + ('h' * (len(data) // 2)), data)
# Calculate the peak audio level in decibels
peak_amplitude = max(map(abs, samples))
# Convert amplitude to decibels
decibels = 20 * math.log10(peak_amplitude / 32767) # Assuming 16-bit audio
print(f"Decibels: {decibels:.2f} dB")
except KeyboardInterrupt:
print("Stopping the script.")
Based on @fdcpp's comments, this seems to work well.
import alsaaudio
import audioop
import math
# Set the audio parameters
device = 'default'
sample_rate = 44100 # 44.1 kHz
# Open the audio input stream
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, device, channels=1, rate=sample_rate, format=alsaaudio.PCM_FORMAT_S16_LE, periodsize=1024)
# Main loop to continuously print audio levels
try:
while True:
# Read audio data from the microphone
_, data = inp.read()
# Calculate the peak audio level in decibels
peak_amplitude = audioop.max(data, 2)
# Convert amplitude to decibels
decibels = 20 * math.log10(peak_amplitude) # Assuming 16-bit audio
print(f"Decibels: {decibels:.2f} dB")
except KeyboardInterrupt:
print("Stopping the script.")