Source code for lhotse.dataset.cut_transforms.lowpass

import math
import random
from dataclasses import dataclass
from typing import List, Literal, Optional, Tuple, Union

from lhotse import CutSet
from lhotse.dataset.dataloading import resolve_seed


[docs]@dataclass class LowpassUsingResampling: """ Applies a low-pass filter to each Cut in a CutSet by resampling the audio back and forth. """ p: float = 0.5 frequencies_interval: Tuple[float, float] = (3500, 8000) seed: Union[int, Literal["trng", "randomized"]] = 42 rng: Optional[random.Random] = None preserve_id: bool = False def __post_init__(self) -> None: if self.rng is not None and self.seed is not None: raise ValueError("Either rng or seed must be provided, not both") if self.rng is None: self.rng = random.Random(resolve_seed(self.seed)) def __call__(self, cuts: CutSet) -> CutSet: lowpassed_cuts = [] for cut in cuts: if self.rng.random() <= self.p: low, high = self.frequencies_interval if high > cut.sampling_rate // 2: raise ValueError( f"Upper frequency limit {high} is greater than sampling rate / 2 ({cut.sampling_rate // 2})" ) # sampling from log-uniform[low, high] distribution cutoff_frequency = math.exp( self.rng.uniform(math.log(low), math.log(high)) ) cutoff_frequency = int(cutoff_frequency) new_cut = cut.resample(cutoff_frequency * 2).resample(cut.sampling_rate) if not self.preserve_id: new_cut.id = f"{cut.id}_lowpassed{cutoff_frequency:.0f}" lowpassed_cuts.append(new_cut) else: lowpassed_cuts.append(cut) return CutSet(lowpassed_cuts)