Spaces:
Sleeping
Sleeping
File size: 6,338 Bytes
1a3ce68 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | import soundfile as sf
import torchaudio
def read_wav_segment(file_path, start=None, end=None, dtype="float32"):
"""
Reads a specific segment from a .wav file efficiently.
Args:
file_path (str): Path to the .wav file.
start (int): Start frame index.
end (int): End frame index.
Returns:
numpy.ndarray: Audio data for the specified segment.
int: Sample rate of the audio file.
"""
# Open the .wav file
if start is None or end is None:
data, samplerate = sf.read(file_path, dtype=dtype)
else:
with sf.SoundFile(file_path) as audio_file:
# Read only the required frames
audio_file.seek(start)
data = audio_file.read(frames=end-start, dtype=dtype)
samplerate = audio_file.samplerate
return data, samplerate
def get_audio_length(file_path):
"""
Retrieves the length of an audio file in seconds and frames.
Args:
file_path (str): Path to the audio file.
Returns:
float: Length of the audio file in seconds.
int: Total number of frames in the audio file.
int: Sample rate of the audio file.
"""
with sf.SoundFile(file_path) as audio_file:
total_frames = len(audio_file) # Total number of frames
samplerate = audio_file.samplerate # Sample rate
duration = total_frames / samplerate # Duration in seconds
return duration, total_frames, samplerate
def taxonomy2track(input_class, num_instr=8):
assert num_instr==8, "num_instr should be 8 for this function, the rest is not implemented yet"
if input_class is None:
return 'unknown'
if num_instr == 8:
mapping = {0000: 'other', 1100: 'drums', 1200: 'drums', 1300: 'other', 2000: 'bass', 3000: 'guitar', 4100: 'piano', 4200: 'piano', 4300: 'piano', 4400: 'other', 4500: 'other', 4600: 'other', 4700: 'other', 4900: 'other', 5000: 'brass', 6100: 'strings', 6210: 'brass', 6220: 'brass', 8100: 'guitar', 8200: 'brass', 9000: 'vocals'}
else:
raise NotImplementedError()
code_length = len(str(input_class))
if code_length < 4:
#pad zeros to the right to make it 4 digits
input_class = int(str(input_class) + "0" * (4 - code_length))
class_str = str(input_class)
for i in range(len(class_str), 0, -1):
general_class = int(class_str[:i] + "0" * (len(class_str) - i))
if general_class in mapping:
return mapping[general_class]
try:
raise ValueError(f"No mapping found for input class {input_class} with num_instr {num_instr}")
except ValueError as e:
print(f"Error: {e}")
return "other" # Return a default value if no mapping is found
import torch
def efficient_roll(x, shift, dims=-1):
"""
Efficiently roll tensor elements along a dimension without creating a full copy.
Args:
x: Input tensor
shift: Number of places to roll (negative for left roll)
dim: Dimension along which to roll
Returns:
Rolled tensor view where possible, minimal copy where necessary
"""
if shift == 0:
return x
# Get the size of the dimension
dim_size = x.size(dims)
# Handle shift larger than dimension size
shift = shift % dim_size
if shift < 0:
shift += dim_size
# Create indices for the roll
indices = torch.cat([torch.arange(dim_size-shift, dim_size),
torch.arange(0, dim_size-shift)])
# Use index_select for the roll
return torch.index_select(x, dims, indices)
#import loudness
import numpy as np
def apply_loud_normalization(x, lufs=-23, sample_rate=44100,device=None):
"""
x shaPe: (batch_size, channels, time)
"""
in_shape= x.shape
if x.ndim != 3:
x=x.view(-1, in_shape[-2], in_shape[-1]) # Ensure x is 3D
B, C, T = x.shape
if device is None:
device = x.device
x_out = torch.zeros_like(x)
#for b in range(B):
# x_i=x[b].cpu().numpy().T
# lufs_in=loudness.integrated_loudness(x_i, sample_rate)
# delta_loudness= lufs - lufs_in
# gain=np.power(10, delta_loudness / 20) # Convert dB to linear gain
# x_out[b] = torch.tensor(x_i.T * gain, device=device)
x=x.view(B* C,1, T) # Ensure x is 3D
loudness=torchaudio.functional.loudness(x+1e-5, sample_rate=sample_rate)
delta_loudness = lufs - loudness
gain= torch.pow(10, delta_loudness / 20) # Convert dB to linear gain
if gain.isnan().any():
print("NaN detected in gain, setting to -30 dB")
gain = torch.nan_to_num(gain, nan=-30.0)
x_out = x * gain.view(B * C, 1, 1) # Apply gain to each channel
x_out = x_out.view(in_shape)
return x_out
from utils.feature_extractors.dsp_features import compute_log_rms_gated_max, compute_crest_factor, compute_stereo_width, compute_stereo_imbalance, compute_log_spread
def apply_RMS_normalization(x, RMS_norm=-25, device=None, use_gate=False):
if device is None:
device = x.device
RMS= torch.tensor(RMS_norm, device=device).view(1, 1, 1).repeat(x.shape[0],1,1) # Use fixed RMS for evaluation
x_RMS_ref=20*torch.log10(torch.sqrt(torch.mean(x**2, dim=(-1), keepdim=True).mean(dim=-2, keepdim=True)))
if use_gate:
x_RMS = compute_log_rms_gated_max(x).unsqueeze(-1)
else:
x_RMS=20*torch.log10(torch.sqrt(torch.mean(x**2, dim=(-1), keepdim=True).mean(dim=-2, keepdim=True)))
gain= RMS - x_RMS
gain_linear = 10 ** (gain / 20 + 1e-6) # Convert dB gain to linear scale, adding a small value to avoid division by zero
x=x* gain_linear
return x
import pyloudnorm as pyln
def loudness_normalize(audio, target_loudness=-23.0, sample_rate=44100):
"""
Normalize the loudness of the audio to a target level.
"""
pylnmeter = pyln.Meter(sample_rate) # Create a meter for 44100 Hz sampling rate
audio= np.array(audio, dtype=np.float32).T
loudness = pylnmeter.integrated_loudness(audio)
# loudness normalize audio to -12 dB LUFS
loudness_normalized_audio = pyln.normalize.loudness(audio, loudness, -14.0)
return torch.tensor(loudness_normalized_audio.T, dtype=torch.float32)
|