mirror of
https://github.com/RVC-Boss/GPT-SoVITS.git
synced 2025-10-07 23:48:48 +08:00
177 lines
5.0 KiB
Python
177 lines
5.0 KiB
Python
import logging
|
|
import os
|
|
import random
|
|
import warnings
|
|
from functools import partial
|
|
|
|
import numpy as np
|
|
import torch
|
|
|
|
try:
|
|
import augment
|
|
except ImportError:
|
|
raise ImportError(
|
|
"augment is not installed, please install it first using:"
|
|
"\npip install git+https://github.com/facebookresearch/WavAugment@54afcdb00ccc852c2f030f239f8532c9562b550e"
|
|
)
|
|
|
|
from .base import Effect
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
_DEBUG = bool(os.environ.get("DEBUG", False))
|
|
|
|
|
|
class AttachableEffect(Effect):
|
|
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
|
raise NotImplementedError
|
|
|
|
def apply(self, wav: np.ndarray, sr: int):
|
|
chain = augment.EffectChain()
|
|
chain = self.attach(chain)
|
|
tensor = torch.from_numpy(wav)[None].float() # (1, T)
|
|
tensor = chain.apply(tensor, src_info={"rate": sr}, target_info={"channels": 1, "rate": sr})
|
|
wav = tensor.numpy()[0] # (T,)
|
|
return wav
|
|
|
|
|
|
class SoxEffect(AttachableEffect):
|
|
def __init__(self, effect_name: str, *args, **kwargs):
|
|
self.effect_name = effect_name
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
|
|
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
|
_logger.debug(f"Attaching {self.effect_name} with {self.args} and {self.kwargs}")
|
|
if not hasattr(chain, self.effect_name):
|
|
raise ValueError(f"EffectChain has no attribute {self.effect_name}")
|
|
return getattr(chain, self.effect_name)(*self.args, **self.kwargs)
|
|
|
|
|
|
class Maybe(AttachableEffect):
|
|
"""
|
|
Attach an effect with a probability.
|
|
"""
|
|
|
|
def __init__(self, prob: float, effect: AttachableEffect):
|
|
self.prob = prob
|
|
self.effect = effect
|
|
if _DEBUG:
|
|
warnings.warn("DEBUG mode is on. Maybe -> Must.")
|
|
self.prob = 1
|
|
|
|
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
|
if random.random() > self.prob:
|
|
return chain
|
|
return self.effect.attach(chain)
|
|
|
|
|
|
class Chain(AttachableEffect):
|
|
"""
|
|
Attach a chain of effects.
|
|
"""
|
|
|
|
def __init__(self, *effects: AttachableEffect):
|
|
self.effects = effects
|
|
|
|
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
|
for effect in self.effects:
|
|
chain = effect.attach(chain)
|
|
return chain
|
|
|
|
|
|
class Choice(AttachableEffect):
|
|
"""
|
|
Attach one of the effects randomly.
|
|
"""
|
|
|
|
def __init__(self, *effects: AttachableEffect):
|
|
self.effects = effects
|
|
|
|
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
|
return random.choice(self.effects).attach(chain)
|
|
|
|
|
|
class Generator:
|
|
def __call__(self) -> str:
|
|
raise NotImplementedError
|
|
|
|
|
|
class Uniform(Generator):
|
|
def __init__(self, low, high):
|
|
self.low = low
|
|
self.high = high
|
|
|
|
def __call__(self) -> str:
|
|
return str(random.uniform(self.low, self.high))
|
|
|
|
|
|
class Randint(Generator):
|
|
def __init__(self, low, high):
|
|
self.low = low
|
|
self.high = high
|
|
|
|
def __call__(self) -> str:
|
|
return str(random.randint(self.low, self.high))
|
|
|
|
|
|
class Concat(Generator):
|
|
def __init__(self, *parts: Generator | str):
|
|
self.parts = parts
|
|
|
|
def __call__(self):
|
|
return "".join([part if isinstance(part, str) else part() for part in self.parts])
|
|
|
|
|
|
class RandomLowpassDistorter(SoxEffect):
|
|
def __init__(self, low=2000, high=16000):
|
|
super().__init__("sinc", "-n", Randint(50, 200), Concat("-", Uniform(low, high)))
|
|
|
|
|
|
class RandomBandpassDistorter(SoxEffect):
|
|
def __init__(self, low=100, high=1000, min_width=2000, max_width=4000):
|
|
super().__init__("sinc", "-n", Randint(50, 200), partial(self._fn, low, high, min_width, max_width))
|
|
|
|
@staticmethod
|
|
def _fn(low, high, min_width, max_width):
|
|
start = random.randint(low, high)
|
|
stop = start + random.randint(min_width, max_width)
|
|
return f"{start}-{stop}"
|
|
|
|
|
|
class RandomEqualizer(SoxEffect):
|
|
def __init__(self, low=100, high=4000, q_low=1, q_high=5, db_low: int = -30, db_high: int = 30):
|
|
super().__init__(
|
|
"equalizer",
|
|
Uniform(low, high),
|
|
lambda: f"{random.randint(q_low, q_high)}q",
|
|
lambda: random.randint(db_low, db_high),
|
|
)
|
|
|
|
|
|
class RandomOverdrive(SoxEffect):
|
|
def __init__(self, gain_low=5, gain_high=40, colour_low=20, colour_high=80):
|
|
super().__init__("overdrive", Uniform(gain_low, gain_high), Uniform(colour_low, colour_high))
|
|
|
|
|
|
class RandomReverb(Chain):
|
|
def __init__(self, deterministic=False):
|
|
super().__init__(
|
|
SoxEffect(
|
|
"reverb",
|
|
Uniform(50, 50) if deterministic else Uniform(0, 100),
|
|
Uniform(50, 50) if deterministic else Uniform(0, 100),
|
|
Uniform(50, 50) if deterministic else Uniform(0, 100),
|
|
),
|
|
SoxEffect("channels", 1),
|
|
)
|
|
|
|
|
|
class Flanger(SoxEffect):
|
|
def __init__(self):
|
|
super().__init__("flanger")
|
|
|
|
|
|
class Phaser(SoxEffect):
|
|
def __init__(self):
|
|
super().__init__("phaser")
|