3

I am having trouble with converting the array of samples to decibels. Here's the code I've tried.

from pydub import AudioSegment
audio=AudioSegment.from_mp3('am_voice.mp3')
samples=audio.get_array_of_samples()
import math
def convert_to_decibel(arr):
    if arr!=0:
        return 10 * math.log10(abs(arr))    
    else:
        return -60
data=[convert_to_decibel(i) for i in samples]

This returns all positive data. Whereas, the decibel value should be always negative. Here's the data I want to create :

percentile=np.percentile(data,[25,50,75])
print(f"1st Quartile : {percentile[0]}")
print(f"2nd Quartile : {percentile[1]}")
print(f"3rd Quartile : {percentile[2]}")
print(f"Mean : {np.mean(data)}")
print(f"Median : {np.median(data)}")
print(f"Standard Deviation : {np.std(data)}")
print(f"Variance : {np.var(data)}")

Any help would be appreciated.

PS: I have tried librosa and other libraries too.

shekhar chander
  • 600
  • 8
  • 14

1 Answers1

4

The magnitude of signal let's say a, such that 0<a<1, in terms of y=log10(a), will be -inf<y<0. The negative spikes can be replaced by some negative numbers just like you are doing as -60 dB. To get the negative dB values the samples should have values less than 1. Please note that, dB levels tells the relation to some reference signal value. The audio (acoustics) signals consist of various reference values, which should be specified as ref. In digital audio signals the samples are mostly specified in less than 1. The term db Full Scale (dbFS) is used for ref=1 in the digital audio signals. Below is the modification of your code in terms of using audio signal in range -1 to 1 from soundfile, which is in contrast to the AudioSegment library.

from pydub import AudioSegment
import numpy as np
import soundfile as sfile
import math
import matplotlib.pyplot as plt
filename = 'Alesis-Sanctuary-QCard-Crickets.wav'
# https://freewavesamples.com/files/Alesis-Sanctuary-QCard-Crickets.wav

audio=AudioSegment.from_mp3(filename)
signal, sr = sfile.read(filename)
samples=audio.get_array_of_samples()
samples_sf=0
try:
    samples_sf = signal[:, 0]  # use the first channel for dual
except:
    samples_sf=signal  # for mono


def convert_to_decibel(arr):
    ref = 1
    if arr!=0:
        return 20 * np.log10(abs(arr) / ref)
        
    else:
        return -60

data=[convert_to_decibel(i) for i in samples_sf]
percentile=np.percentile(data,[25,50,75])
print(f"1st Quartile : {percentile[0]}")
print(f"2nd Quartile : {percentile[1]}")
print(f"3rd Quartile : {percentile[2]}")
print(f"Mean : {np.mean(data)}")
print(f"Median : {np.median(data)}")
print(f"Standard Deviation : {np.std(data)}")
print(f"Variance : {np.var(data)}")


plt.figure()
plt.subplot(3, 1, 1)
plt.plot(samples)
plt.xlabel('Samples')
plt.ylabel('Data: AudioSegment')

plt.subplot(3, 1, 2)
plt.plot(samples_sf)
plt.xlabel('Samples')
plt.ylabel('Data: Soundfile')
plt.subplot(3, 1, 3)
plt.plot(data)
plt.xlabel('Samples')
plt.ylabel('dB Full Scale (dB)')
plt.tight_layout()
plt.show()

Output

1st Quartile : -51.7206201849085
2nd Quartile : -35.31427238781313
3rd Quartile : -22.110336232568464
Mean : -37.76500744850379
Median : -35.31427238781313
Standard Deviation : 18.848883199155107
Variance : 355.2803978553917

enter image description here

Trees
  • 1,245
  • 10
  • 20
  • You saved me. I just needed the formula. Thanks for such great explanation. By the way, is there any difference in np.log10 and math.log10? I am an idiot. Also, I am getting different values than yours : meandb":-40.09160582798414,"mediandb":-37.65021502094619,"quartile1":-54.098386736984395,"quartile3":-24.44025826193268,"variation":354.752286778196. I used wave to read the wav file. Does this make any difference? – shekhar chander Feb 12 '21 at 04:28
  • 1
    Hi! no problem, in fact you can use math and np both will work. However, np is better for working with vectors and large computations. On the other hand math is a standard lib in Python for basic operations. – Trees Feb 12 '21 at 04:34
  • The signal should be normalized in range 0 to 1 by taking abs(signal)/(maximum of datatype), plot the signal from wave lib you will find the difference in values. – Trees Feb 12 '21 at 04:48
  • @Trees Thanks for this explanation/answer. It really helped me. Is there a way to plot the dBFS plot differently? Like in my question [here](https://stackoverflow.com/questions/72082674/time-series-dbfs-plot-output-modification-current-output-plot-not-as-expected)? – skrowten_hermit May 02 '22 at 12:23