Spaces:
Running on Zero
Running on Zero
| 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) | |