python pyloudnorm get RMS values (loudness metering) for PCM WAV

Question:

Currently I am using this code:

import sys
import soundfile as sf
import pyloudnorm as pyln

f = open( "c:\temp\wav_analysis.txt", "w" )
data, rate = sf.read(sys.argv[1]) # load audio (with shape (samples, channels))
meter = pyln.Meter( rate ) # create BS.1770 meter
loudness = meter.integrated_loudness(data) # measure loudness
'''output analysis data'''
for i in range(1, len(data)):
    if abs(data[i]) > 0.4:
        f.write(str( i / rate ) + "," + str(abs(data[ i ])) + "n")

The WAV file is passed in as an argument, it’s read in and then analyzed for loudness across all of "data".

I don’t want that.
I want to analyze 100ms windows of data (i.e. 4410 samples at a time, while shifting my window by 50 milliseconds, thus creating lots of loudness values.

Is there a way to call meter.integrated_loundess() in such a way that it does that?

Or do I need to somehow create a bunch of 4410-value long data arrays derived from "data" and then feed each one of those to meter.integrated_loudness() one by one?

(The stuff below ”’output analysis data”’ is just a place holder. I want to replace it with what I need.)

EDIT: See the "slicing" answer below. Also, keep in mind that through trial and error I discovered that integrated_loudness requires the data to be at least 17640 samples long (i.e. 400ms at 44100).

EDIT2: During random searching for something else, I came across this site:https://pysoundfile.readthedocs.io/en/0.8.0/

There, this code snippet was exactly what I was initially looking for for quickly getting the RMS values of the WAV file:

import numpy as np
import soundfile as sf

rms = [np.sqrt(np.mean(block**2)) for block in
       sf.blocks('myfile.wav', blocksize=1024, overlap=512)]

Not only is it much faster, but it is also not limited by the "0.4second" window limit that I ran into with meter.integrated_loudness.

Asked By: a1s2d3f4

||

Answers:

If I understand your question correctly, perhaps you can slice the data doing something like the following:

import sys
import soundfile as sf
import pyloudnorm as pyln

with open("c:\temp\wav_analysis.txt", "w") as f:
    data, rate = sf.read(sys.argv[1]) # load audio (with shape (samples, channels))
    meter = pyln.Meter(rate) # create BS.1770 meter

    window_size = int(rate * 0.1) # window size of 100ms in samples
    hop_size = int(rate * 0.05) # hop size of 50ms in samples

    for i in range(0, len(data)-window_size, hop_size):
        window = data[i:i+window_size] # extract a 100ms window of data
        loudness = meter.integrated_loudness(window) # measure loudness of the window
        f.write(f"{str(i / rate)},{str(loudness)}" + "n")
Answered By: Plonetheus
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.