MEGAMI / utils /feature_extractors /dsp_features.py
Vansh Chugh
initial deploy
1a3ce68
Raw
History Blame Contribute Delete
3.69 kB
import torch
def compute_rms(x: torch.Tensor, **kwargs):
"""Compute root mean square energy.
Args:
x: (bs, 1, seq_len)
Returns:
rms: (bs, )
"""
rms = torch.sqrt(torch.mean(x**2, dim=-1).clamp(min=1e-8))
return rms
def compute_log_rms_gated_max(x: torch.Tensor, sample_rate=44100, **kwargs):
"""Compute gated log RMS energy.
Frames the signal in 400 ms windows with 75% overlap, computes RMS,
discards frames with RMS < -60 dBFS, and averages the log-RMS.
If all frames in a given (batch, channel) are below -60 dBFS,
returns -60 for that entry.
Args:
x: Tensor of shape (bs, c, seq_len)
Returns:
log_rms: Tensor of shape (bs, c)
"""
seg_size = int(sample_rate * 0.4)
hop_size = int(sample_rate * 0.1)
# (bs, c, num_frames, seg_size)
B, C, L = x.size()
assert C==1 or C==2
x_frames = x.unfold(2, seg_size, hop_size) # (bs, c, num_frames, seg_size)
# RMS over last dimension (seg_size)
rms = torch.sqrt((x_frames ** 2).mean(dim=-1)) # (bs, c, num_frames)
# dB conversion
rms_db = 20 * torch.log10(rms.clamp(min=1e-8)) # (bs, c, num_frames)
#print("rms db shape", rms_db.shape)
#take the maximum RMS across all frames
rms_max = rms_db.max(dim=2)[0] # (bs, c)
#print(f"RMS max shape: {rms_max.shape}")
return rms_max
def compute_log_rms(x: torch.Tensor, **kwargs):
"""Compute root mean square energy.
Args:
x: (bs, 1, seq_len)
Returns:
rms: (bs, )
"""
rms=compute_rms(x)
return 20 * torch.log10(rms.clamp(min=1e-8))
def compute_crest_factor(x: torch.Tensor, **kwargs):
"""Compute crest factor as ratio of peak to rms energy in dB.
Args:
x: (bs, 2, seq_len)
"""
num = torch.max(torch.abs(x), dim=-1)[0]
den = compute_rms(x).clamp(min=1e-8)
cf = 20 * torch.log10((num / den).clamp(min=1e-8))
return cf
def compute_log_spread(x: torch.Tensor, **kwargs):
"""Compute log spread as the mean difference between log magnitude of samples and log RMS.
Args:
x: (bs, 1, seq_len)
Returns:
log_spread: (bs, )
"""
# Compute log RMS
log_rms = compute_log_rms(x).unsqueeze(-1) # (bs, 1, 1)
# Compute log magnitude of each sample
log_magnitude = 20 * torch.log10(torch.abs(x).clamp(min=1e-8)) # (bs, 1, seq_len)
# Compute the difference and take the mean
log_spread = torch.mean(log_magnitude - log_rms, dim=-1).squeeze(1) # (bs, )
return log_spread
def compute_stereo_width(x: torch.Tensor, **kwargs):
"""Compute stereo width as ratio of energy in sum and difference signals.
Args:
x: (bs, 2, seq_len)
"""
bs, chs, seq_len = x.size()
assert chs == 2, "Input must be stereo"
# compute sum and diff of stereo channels
x_sum = x[:, 0, :] + x[:, 1, :]
x_diff = x[:, 0, :] - x[:, 1, :]
# compute power of sum and diff
sum_energy = torch.mean(x_sum**2, dim=-1)
diff_energy = torch.mean(x_diff**2, dim=-1)
# compute stereo width as ratio
stereo_width = diff_energy / sum_energy.clamp(min=1e-8)
return stereo_width
def compute_stereo_imbalance(x: torch.Tensor, **kwargs):
"""Compute stereo imbalance as ratio of energy in left and right channels.
Args:
x: (bs, 2, seq_len)
Returns:
stereo_imbalance: (bs, )
"""
left_energy = torch.mean(x[:, 0, :] ** 2, dim=-1)
right_energy = torch.mean(x[:, 1, :] ** 2, dim=-1)
stereo_imbalance = (right_energy - left_energy) / (
right_energy + left_energy
).clamp(min=1e-8)
return stereo_imbalance