@staticmethod
def calculate_volumes(channel: Channel, win_len: float=0.01) -> list:
"""Estimate the volume values of an audio channel.
Computes the Root Mean Square (RMS) values of audio frames in a given
channel over specified time windows. It handles corrupted audio by
logging warnings and using the previous RMS value for negative RMS
readings.
Flow:
1. Calculate the number of frames per window and the total number of windows.
2. Initialize a list to store RMS values and set the initial previous_rms to 0.
3. Loop through each window, extract frames, and compute the RMS value.
4. If the RMS value is positive, store it; if negative, log a warning and use the previous RMS value.
5. Return the list of RMS values.
:example:
>>> channel = Channel(framerate=16000, sampwidth=2, frames=b'\x01\x00\x02\x00\x03\x00\x04\x00')
>>> volumes = ChannelVolume.calculate_volumes(channel, win_len=0.01)
>>> print(volumes)
[2.74]
:param channel: (Channel) The channel to work on.
:param win_len: (float) Window length to estimate the volume.
:return: (list) The volume values.
"""
nb_frames = int(win_len * channel.get_framerate())
nb_vols = int(channel.get_duration() / win_len) + 1
volumes = [0.0] * nb_vols
previous_rms = 0
for i in range(nb_vols):
frames = channel.get_frames(nb_frames)
a = AudioFrames(frames, channel.get_sampwidth(), 1)
rms = a.rms()
if rms > 0:
volumes[i] = rms
elif rms < 0:
volumes[i] = previous_rms
logging.warning("Corrupted audio? The RMS shouldn't be a negative value but got {}".format(rms))
previous_rms = rms
if len(volumes) > 0 and volumes[-1] == 0:
volumes.pop()
return volumes