diff --git a/Dockerfile b/Dockerfile index 6578031a3fe6ac2e79fbb075ae5158cf14b1365c..0b749e95e03aa5fcdd0384b5bce3a51c88b1ae2e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,49 +4,18 @@ ENV DEBIAN_FRONTEND=noninteractive ENV PIP_NO_CACHE_DIR=1 ENV PYTHONUNBUFFERED=1 -# Install system dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ - ffmpeg \ - libsndfile1 \ - libportaudio2 \ - libasound2 \ + ffmpeg libsndfile1 libportaudio2 libasound2 \ && rm -rf /var/lib/apt/lists/* WORKDIR /app -# Install torch first (largest package) -RUN pip install --no-cache-dir --timeout=300 \ - torch==2.4.1+cpu torchaudio==2.4.1+cpu \ - --index-url https://download.pytorch.org/whl/cpu +# Ultra-minimal deps: only what's needed for pitch/formant shifting +RUN pip install --no-cache-dir --timeout=120 \ + numpy scipy librosa soundfile praat-parselmouth gradio fastapi uvicorn pydantic httpx anyio starlette websockets -# Install remaining dependencies -COPY requirements.txt . -RUN pip install --no-cache-dir --timeout=300 -r requirements.txt - -# Copy only essential RVC modules -COPY infer/__init__.py infer/ -COPY infer/audio.py infer/ -COPY infer/hubert.py infer/ -COPY infer/rmvpe.py infer/ -COPY infer/fcpe.py infer/ -COPY infer/vc ./infer/vc -COPY infer/module ./infer/module -COPY tools/cuda_graph.py tools/ -COPY tools/file_io.py tools/ -COPY configs ./configs -COPY i18n ./i18n - -# Copy application files -COPY app.py . -COPY inference.py . -COPY download_models.py . - -# Create model directories -RUN mkdir -p /app/models/elderly /app/models/weights /app/models/rvc_base/assets/hubert /app/models/rvc_base/assets/rmvpe /app/models/rvc_base/assets/pretrained - -# Run model download/setup -RUN python download_models.py +COPY app_simple.py app.py +COPY inference_simple.py inference.py EXPOSE 7860 - CMD ["python", "app.py"] \ No newline at end of file diff --git a/app_simple.py b/app_simple.py new file mode 100644 index 0000000000000000000000000000000000000000..b434d3a37693fd3043463e3b05e78a689026fe20 --- /dev/null +++ b/app_simple.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +"""Simple Elderly Voice Converter using pitch/formant shifting (librosa + parselmouth).""" +import os +import tempfile +import gradio as gr +import numpy as np +import soundfile as sf +import librosa +import parselmouth +from parselmouth.praat import call + +TITLE = "🎭 Elderly Voice Converter (Pitch + Formant Shift)" +DESCRIPTION = """ +基于 **音调偏移 + 共振峰偏移** 的轻量级声音转换,模拟老年人声线特征。 + +**原理:** +- **降低基频 (Pitch)**:老年人声带松弛,基频更低 +- **降低共振峰**:声道变长/肌肉松弛,共振峰下移 +- **添加气声**:模拟声带闭合不全的气息感 + +**使用方法:** +1. 上传音频文件 (wav, mp3, flac 等) +2. 调整参数: + - **Pitch Shift (半音)**:建议 -3 到 -6 (男声) / -2 到 -5 (女声) + - **Formant Shift (半音)**:建议 -2 到 -4 + - **Breathiness**:0-0.3,添加气声感 +3. 点击转换 +""" + + +def convert_voice_simple( + input_audio_path: str, + output_audio_path: str, + pitch_shift: float = -4.0, # semitones + formant_shift: float = -3.0, # semitones + breathiness: float = 0.15, +): + """ + Convert voice to elderly-like using pitch + formant shifting. + + Args: + input_audio_path: Input audio file + output_audio_path: Output audio file + pitch_shift: Pitch shift in semitones (negative = lower) + formant_shift: Formant shift in semitones (negative = lower) + breathiness: Amount of breathiness to add (0-0.5) + """ + # Load audio + y, sr = librosa.load(input_audio_path, sr=None, mono=True) + + # Convert to parselmouth Sound + sound = parselmouth.Sound(y, sampling_frequency=sr) + + # 1. Pitch shift using PSOLA + if pitch_shift != 0: + # Convert semitones to ratio + pitch_ratio = 2 ** (pitch_shift / 12.0) + # Use PSOLA for high-quality pitch shifting + sound = call(sound, "Change gender", pitch_ratio, 1.0, 1.0, 1.0, 1.0) + + # 2. Formant shift + if formant_shift != 0: + formant_ratio = 2 ** (formant_shift / 12.0) + # Change formants without changing pitch + sound = call(sound, "Change gender", 1.0, formant_ratio, 1.0, 1.0, 1.0) + + # 3. Add breathiness (mix with noise) + if breathiness > 0: + # Generate breath noise + noise = np.random.normal(0, breathiness * 0.1, len(sound.values[0])) + # Apply noise mainly to unvoiced segments (simple approach) + sound.values[0] = sound.values[0] * (1 - breathiness) + noise * breathiness + + # Get result + result_audio = sound.values[0].astype(np.float32) + result_sr = sound.sampling_frequency + + # Resample if needed + if result_sr != sr: + result_audio = librosa.resample(result_audio, orig_sr=result_sr, target_sr=sr) + + # Save + sf.write(output_audio_path, result_audio, sr, subtype='PCM_16') + return output_audio_path + + +def process_audio( + audio_file, + pitch_shift, + formant_shift, + breathiness, +): + if audio_file is None: + return None, "请先上传音频文件" + + try: + with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_out: + output_path = tmp_out.name + + convert_voice_simple( + input_audio_path=audio_file, + output_audio_path=output_path, + pitch_shift=pitch_shift, + formant_shift=formant_shift, + breathiness=breathiness, + ) + + return output_path, "✅ 转换完成!" + except Exception as e: + return None, f"❌ 转换失败: {str(e)}" + + +def create_interface(): + with gr.Blocks(title=TITLE, theme=gr.themes.Soft()) as demo: + gr.Markdown(f"# {TITLE}") + gr.Markdown(DESCRIPTION) + + with gr.Row(): + with gr.Column(scale=1): + audio_input = gr.Audio( + label="输入音频", + type="filepath", + sources=["upload", "microphone"], + ) + + with gr.Group(): + gr.Markdown("### 参数") + pitch_shift = gr.Slider( + minimum=-12, + maximum=0, + value=-4, + step=0.5, + label="Pitch Shift (半音)", + info="负值降低音调,建议 -3 ~ -6" + ) + formant_shift = gr.Slider( + minimum=-8, + maximum=0, + value=-3, + step=0.5, + label="Formant Shift (半音)", + info="负值降低共振峰,建议 -2 ~ -4" + ) + breathiness = gr.Slider( + minimum=0.0, + maximum=0.5, + value=0.15, + step=0.05, + label="Breathiness (气声感)", + info="模拟声带闭合不全,0.1-0.3 推荐" + ) + + convert_btn = gr.Button("🎭 转换为老年声", variant="primary", size="lg") + status = gr.Textbox(label="状态", interactive=False) + + with gr.Column(scale=1): + audio_output = gr.Audio( + label="转换结果", + type="filepath", + ) + gr.Markdown(""" + ### 💡 参数建议 + | 声音类型 | Pitch Shift | Formant Shift | Breathiness | + |---------|-------------|---------------|-------------| + | 男性→老年男声 | -4 ~ -6 | -2 ~ -3 | 0.1 ~ 0.2 | + | 女性→老年女声 | -2 ~ -4 | -1 ~ -2 | 0.1 ~ 0.2 | + | 女性→老年男声 | -6 ~ -9 | -3 ~ -5 | 0.15 ~ 0.25 | + | 儿童→老年声 | -8 ~ -12 | -4 ~ -6 | 0.2 ~ 0.3 | + + **注意**:这是基于 DSP 的近似模拟,非 AI 声音转换。 + 效果取决于原音频质量,建议使用清晰、单人、少背景噪音的音频。 + """) + + convert_btn.click( + fn=process_audio, + inputs=[audio_input, pitch_shift, formant_shift, breathiness], + outputs=[audio_output, status], + api_name="convert", + ) + + return demo + + +if __name__ == "__main__": + demo = create_interface() + demo.launch( + server_name="0.0.0.0", + server_port=7860, + show_error=True, + share=False, + ) \ No newline at end of file diff --git a/configs/config.json b/configs/config.json deleted file mode 100644 index eeb8456402e2c0b405cae61e982a92196b3f1dc8..0000000000000000000000000000000000000000 --- a/configs/config.json +++ /dev/null @@ -1 +0,0 @@ -{"pth_path": "assets/weights/kikiV1.pth", "index_path": "logs/kikiV1.index", "sg_hostapi": "MME", "sg_wasapi_exclusive": false, "sg_input_device": "VoiceMeeter Output (VB-Audio Vo", "sg_output_device": "VoiceMeeter Aux Input (VB-Audio", "sr_type": "sr_device", "threhold": -60.0, "pitch": 12.0, "rms_mix_rate": 0.5, "index_rate": 0.0, "block_time": 0.13, "crossfade_length": 0.08, "extra_time": 2.0, "f0method": "rmvpe"} \ No newline at end of file diff --git a/configs/config.py b/configs/config.py deleted file mode 100644 index 525fec9dfca8830916dd0a13fad192e3ee2f945e..0000000000000000000000000000000000000000 --- a/configs/config.py +++ /dev/null @@ -1,286 +0,0 @@ -import argparse -import os -import re -import sys -import json -from multiprocessing import cpu_count -from pathlib import Path -from tools.file_io import read_text - -import torch -import logging - -from tools.cuda_graph import configure_cuda_graph - -logger = logging.getLogger(__name__) - - -# Keep device/precision eligibility in one place. This follows the GPU rules -# used by GPT-SoVITS: GPUs below 4 GiB or SM 5.3 are not selected, Pascal -# SM 6.1 and GTX 16-series cards use fp32, and newer CUDA GPUs use fp16. -def get_device_dtype_sm(idx) : - cpu = torch.device("cpu") - if not torch.cuda.is_available() or idx < 0 or idx >= torch.cuda.device_count(): - return cpu, torch.float32, 0.0, 0.0 - - try: - cuda = torch.device(f"cuda:{idx}") - major, minor = torch.cuda.get_device_capability(idx) - gpu_name = torch.cuda.get_device_name(idx) - mem_bytes = torch.cuda.get_device_properties(idx).total_memory - except Exception: - logger.exception("Unable to inspect CUDA device %s", idx) - return cpu, torch.float32, 0.0, 0.0 - - mem_gb = mem_bytes / (1024**3) + 0.4 - sm_version = major + minor / 10.0 - is_16_series = bool(re.search(r"16\d{2}", gpu_name)) and sm_version == 7.5 - if mem_gb < 4 or sm_version < 5.3: - return cpu, torch.float32, 0.0, 0.0 - if sm_version == 6.1 or is_16_series: - return cuda, torch.float32, sm_version, mem_gb - if sm_version > 6.1: - return cuda, torch.float16, sm_version, mem_gb - return cpu, torch.float32, 0.0, 0.0 - - -def get_training_dtype() : - """Select one shared training dtype from the visible CUDA devices.""" - if not torch.cuda.is_available(): - return torch.float32 - - profiles = [get_device_dtype_sm(i) for i in range(torch.cuda.device_count())] - unsupported = [ - i for i, profile in enumerate(profiles) if profile[0].type != "cuda" - ] - if unsupported: - raise RuntimeError( - "Selected CUDA device(s) do not satisfy the GPU rule " - f"(minimum 4 GiB and SM 5.3): {unsupported}" - ) - - # DDP uses one shared precision. A mixed Pascal/newer-GPU setup therefore - # uses fp32 unless every visible device is eligible for fp16. - if profiles and all(profile[1] == torch.float16 for profile in profiles): - return torch.float16 - return torch.float32 - - -CUDA_AVAILABLE = torch.cuda.is_available() -GPU_COUNT = torch.cuda.device_count() if CUDA_AVAILABLE else 0 -GPU_PROFILES = [get_device_dtype_sm(i) for i in range(GPU_COUNT)] -GPU_INFOS = [ - f"{device.index}\t{torch.cuda.get_device_name(device.index)}" - for device, _, _, _ in GPU_PROFILES - if device.type == "cuda" -] -GPU_INDEX = { - device.index for device, _, _, _ in GPU_PROFILES if device.type == "cuda" -} -GPU_MEMORY = { - device.index: mem - for device, _, _, mem in GPU_PROFILES - if device.type == "cuda" -} -CPU_INFO = "0\tCPU (CPU training is slower)" -IS_GPU = bool(GPU_INFOS) - - -def _detect_directml(): - try: - import torch_directml - - device = torch_directml.device(torch_directml.default_device()) - # Device construction alone can succeed without a usable adapter. - probe = torch.ones(1, dtype=torch.float32).to(device) - _ = (probe + 1).cpu() - return True, device - except Exception: - return False, None - - -DML_AVAILABLE, DML_DEVICE = _detect_directml() - -if GPU_PROFILES: - infer_device, infer_dtype, _, infer_gpu_mem = max( - GPU_PROFILES, key=lambda profile: (profile[2], profile[3]) - ) -else: - infer_device, infer_dtype, infer_gpu_mem = ( - torch.device("cpu"), - torch.float32, - 0.0, - ) - -# Do not expose an unsupported CUDA device as the inference default. -if infer_device.type != "cuda": - if DML_AVAILABLE: - infer_device, infer_dtype, infer_gpu_mem = ( - DML_DEVICE, - torch.float32, - 0.0, - ) - else: - infer_device, infer_dtype, infer_gpu_mem = ( - torch.device("cpu"), - torch.float32, - 0.0, - ) - - -# Run a real capture/replay probe on the selected inference device. Both -# application entry points import this module, so downstream inference code -# receives one consistent 0/1 switch without duplicating device checks. -CUDA_GRAPH_AVAILABLE = configure_cuda_graph(infer_device) - - -CONFIGS_DIR = Path(__file__).resolve().parent -MODEL_CONFIG_FILES = ( - "v1/32k.json", - "v1/40k.json", - "v1/48k.json", - "v2/48k.json", - "v2/32k.json", -) - - -def singleton_variable(func): - def wrapper(*args, **kwargs): - if not wrapper.instance: - wrapper.instance = func(*args, **kwargs) - return wrapper.instance - - wrapper.instance = None - return wrapper - - -@singleton_variable -class Config: - def __init__(self): - self.device = str(infer_device) - self.dtype = infer_dtype - self.is_half = infer_dtype == torch.float16 - self.cuda_graph = CUDA_GRAPH_AVAILABLE - self.n_cpu = 0 - self.gpu_name = None - self.json_config = self.load_config_json() - self.gpu_mem = None - ( - self.python_cmd, - self.listen_port, - self.iscolab, - self.noparallel, - self.noautoopen, - self.dml, - ) = self.arg_parse() - # DML is an automatic fallback when no CUDA device satisfies the rule. - self.dml = self.dml or (infer_device.type == "privateuseone") - self.instead = "" - self.preprocess_per = 3.7 - self.x_pad, self.x_query, self.x_center, self.x_max = self.device_config() - - @staticmethod - def load_config_json() : - d = {} - for config_file in MODEL_CONFIG_FILES: - d[config_file] = json.loads(read_text(CONFIGS_DIR / config_file)) - return d - - @staticmethod - def arg_parse() : - exe = sys.executable or "python" - parser = argparse.ArgumentParser() - parser.add_argument("--port", type=int, default=7865, help="Listen port") - parser.add_argument("--pycmd", type=str, default=exe, help="Python command") - parser.add_argument("--colab", action="store_true", help="Launch in colab") - parser.add_argument( - "--noparallel", action="store_true", help="Disable parallel processing" - ) - parser.add_argument( - "--noautoopen", - action="store_true", - help="Do not open in browser automatically", - ) - parser.add_argument( - "--dml", - action="store_true", - help="torch_dml", - ) - cmd_opts = parser.parse_args() - - cmd_opts.port = cmd_opts.port if 0 <= cmd_opts.port <= 65535 else 7865 - - return ( - cmd_opts.pycmd, - cmd_opts.port, - cmd_opts.colab, - cmd_opts.noparallel, - cmd_opts.noautoopen, - cmd_opts.dml, - ) - - def device_config(self) : - if infer_device.type == "cuda": - i_device = infer_device.index - self.device = str(infer_device) - self.dtype = infer_dtype - self.is_half = infer_dtype == torch.float16 - self.gpu_name = torch.cuda.get_device_name(i_device) - self.gpu_mem = int(infer_gpu_mem) - logger.info( - "Selected GPU %s (%s, SM %.1f, %.1f GiB)", - i_device, - self.gpu_name, - torch.cuda.get_device_capability(i_device)[0] - + torch.cuda.get_device_capability(i_device)[1] / 10.0, - infer_gpu_mem, - ) - if not self.is_half: - logger.info("GPU rule selected fp32 for %s", self.gpu_name) - self.preprocess_per = 3.0 - if self.gpu_mem <= 4: - self.preprocess_per = 3.0 - else: - logger.info("No supported Nvidia GPU found") - self.device = self.instead = "cpu" - self.dtype = torch.float32 - self.is_half = False - self.preprocess_per = 3.0 - - if self.n_cpu == 0: - self.n_cpu = cpu_count() - - if self.is_half: - # 6G显存配置 - x_pad = 3 - x_query = 10 - x_center = 60 - x_max = 65 - else: - # 5G显存配置 - x_pad = 1 - x_query = 6 - x_center = 38 - x_max = 41 - - if self.gpu_mem is not None and self.gpu_mem <= 4: - x_pad = 1 - x_query = 5 - x_center = 30 - x_max = 32 - if self.dml: - logger.info("Use DirectML instead") - import torch_directml - - self.device = torch_directml.device(torch_directml.default_device()) - self.dtype = torch.float32 - self.is_half = False - self.preprocess_per = 3.0 - else: - if self.instead: - logger.info(f"Use {self.instead} instead") - logger.info( - "Half-precision floating-point: %s, device: %s" - % (self.is_half, self.device) - ) - return x_pad, x_query, x_center, x_max diff --git a/configs/v1/32k.json b/configs/v1/32k.json deleted file mode 100644 index 5cd5319d5becd26f1c25f4772fc720a8b5607cf0..0000000000000000000000000000000000000000 --- a/configs/v1/32k.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "train": { - "log_interval": 200, - "seed": 1234, - "epochs": 20000, - "learning_rate": 1e-4, - "betas": [0.8, 0.99], - "eps": 1e-9, - "batch_size": 4, - "lr_decay": 0.999875, - "segment_size": 12800, - "init_lr_ratio": 1, - "warmup_epochs": 0, - "c_mel": 45, - "c_kl": 1.0 - }, - "data": { - "max_wav_value": 32768.0, - "sampling_rate": 32000, - "filter_length": 1024, - "hop_length": 320, - "win_length": 1024, - "n_mel_channels": 80, - "mel_fmin": 0.0, - "mel_fmax": null - }, - "model": { - "inter_channels": 192, - "hidden_channels": 192, - "filter_channels": 768, - "n_heads": 2, - "n_layers": 6, - "kernel_size": 3, - "p_dropout": 0, - "resblock": "1", - "resblock_kernel_sizes": [3,7,11], - "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], - "upsample_rates": [10,4,2,2,2], - "upsample_initial_channel": 512, - "upsample_kernel_sizes": [16,16,4,4,4], - "use_spectral_norm": false, - "gin_channels": 256, - "spk_embed_dim": 109 - } -} diff --git a/configs/v1/40k.json b/configs/v1/40k.json deleted file mode 100644 index ead661be7f121a91866163ecfca0ff00f0a8bf6e..0000000000000000000000000000000000000000 --- a/configs/v1/40k.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "train": { - "log_interval": 200, - "seed": 1234, - "epochs": 20000, - "learning_rate": 1e-4, - "betas": [0.8, 0.99], - "eps": 1e-9, - "batch_size": 4, - "lr_decay": 0.999875, - "segment_size": 12800, - "init_lr_ratio": 1, - "warmup_epochs": 0, - "c_mel": 45, - "c_kl": 1.0 - }, - "data": { - "max_wav_value": 32768.0, - "sampling_rate": 40000, - "filter_length": 2048, - "hop_length": 400, - "win_length": 2048, - "n_mel_channels": 125, - "mel_fmin": 0.0, - "mel_fmax": null - }, - "model": { - "inter_channels": 192, - "hidden_channels": 192, - "filter_channels": 768, - "n_heads": 2, - "n_layers": 6, - "kernel_size": 3, - "p_dropout": 0, - "resblock": "1", - "resblock_kernel_sizes": [3,7,11], - "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], - "upsample_rates": [10,10,2,2], - "upsample_initial_channel": 512, - "upsample_kernel_sizes": [16,16,4,4], - "use_spectral_norm": false, - "gin_channels": 256, - "spk_embed_dim": 109 - } -} diff --git a/configs/v1/48k.json b/configs/v1/48k.json deleted file mode 100644 index 47229273f0f18a4c5c408b1bb9b69919f7ecebe7..0000000000000000000000000000000000000000 --- a/configs/v1/48k.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "train": { - "log_interval": 200, - "seed": 1234, - "epochs": 20000, - "learning_rate": 1e-4, - "betas": [0.8, 0.99], - "eps": 1e-9, - "batch_size": 4, - "lr_decay": 0.999875, - "segment_size": 11520, - "init_lr_ratio": 1, - "warmup_epochs": 0, - "c_mel": 45, - "c_kl": 1.0 - }, - "data": { - "max_wav_value": 32768.0, - "sampling_rate": 48000, - "filter_length": 2048, - "hop_length": 480, - "win_length": 2048, - "n_mel_channels": 128, - "mel_fmin": 0.0, - "mel_fmax": null - }, - "model": { - "inter_channels": 192, - "hidden_channels": 192, - "filter_channels": 768, - "n_heads": 2, - "n_layers": 6, - "kernel_size": 3, - "p_dropout": 0, - "resblock": "1", - "resblock_kernel_sizes": [3,7,11], - "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], - "upsample_rates": [10,6,2,2,2], - "upsample_initial_channel": 512, - "upsample_kernel_sizes": [16,16,4,4,4], - "use_spectral_norm": false, - "gin_channels": 256, - "spk_embed_dim": 109 - } -} diff --git a/configs/v2/32k.json b/configs/v2/32k.json deleted file mode 100644 index 09788b030b575bbc812319d18af15ec2815187be..0000000000000000000000000000000000000000 --- a/configs/v2/32k.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "train": { - "log_interval": 200, - "seed": 1234, - "epochs": 20000, - "learning_rate": 1e-4, - "betas": [0.8, 0.99], - "eps": 1e-9, - "batch_size": 4, - "lr_decay": 0.999875, - "segment_size": 12800, - "init_lr_ratio": 1, - "warmup_epochs": 0, - "c_mel": 45, - "c_kl": 1.0 - }, - "data": { - "max_wav_value": 32768.0, - "sampling_rate": 32000, - "filter_length": 1024, - "hop_length": 320, - "win_length": 1024, - "n_mel_channels": 80, - "mel_fmin": 0.0, - "mel_fmax": null - }, - "model": { - "inter_channels": 192, - "hidden_channels": 192, - "filter_channels": 768, - "n_heads": 2, - "n_layers": 6, - "kernel_size": 3, - "p_dropout": 0, - "resblock": "1", - "resblock_kernel_sizes": [3,7,11], - "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], - "upsample_rates": [10,8,2,2], - "upsample_initial_channel": 512, - "upsample_kernel_sizes": [20,16,4,4], - "use_spectral_norm": false, - "gin_channels": 256, - "spk_embed_dim": 109 - } -} diff --git a/configs/v2/48k.json b/configs/v2/48k.json deleted file mode 100644 index fbe734ef7432bd50bd3ad27deedbdbb1242fd83a..0000000000000000000000000000000000000000 --- a/configs/v2/48k.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "train": { - "log_interval": 200, - "seed": 1234, - "epochs": 20000, - "learning_rate": 1e-4, - "betas": [0.8, 0.99], - "eps": 1e-9, - "batch_size": 4, - "lr_decay": 0.999875, - "segment_size": 17280, - "init_lr_ratio": 1, - "warmup_epochs": 0, - "c_mel": 45, - "c_kl": 1.0 - }, - "data": { - "max_wav_value": 32768.0, - "sampling_rate": 48000, - "filter_length": 2048, - "hop_length": 480, - "win_length": 2048, - "n_mel_channels": 128, - "mel_fmin": 0.0, - "mel_fmax": null - }, - "model": { - "inter_channels": 192, - "hidden_channels": 192, - "filter_channels": 768, - "n_heads": 2, - "n_layers": 6, - "kernel_size": 3, - "p_dropout": 0, - "resblock": "1", - "resblock_kernel_sizes": [3,7,11], - "resblock_dilation_sizes": [[1,3,5], [1,3,5], [1,3,5]], - "upsample_rates": [12,10,2,2], - "upsample_initial_channel": 512, - "upsample_kernel_sizes": [24,20,4,4], - "use_spectral_norm": false, - "gin_channels": 256, - "spk_embed_dim": 109 - } -} diff --git a/download_models.py b/download_models.py deleted file mode 100644 index 177a91fa94fb8690413954562ea9d7527e05fbba..0000000000000000000000000000000000000000 --- a/download_models.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -"""Download RVC models at build time.""" -import os -from pathlib import Path -from huggingface_hub import snapshot_download - -MODEL_DIR = Path("/app/models") -MODEL_DIR.mkdir(parents=True, exist_ok=True) - -print("Setting up RVC environment...") -# Create necessary directories for RVC -rvc_dir = Path("/app/rvc") -(rvc_dir / "assets" / "hubert").mkdir(parents=True, exist_ok=True) -(rvc_dir / "assets" / "rmvpe").mkdir(parents=True, exist_ok=True) -(rvc_dir / "assets" / "pretrained").mkdir(parents=True, exist_ok=True) -(rvc_dir / "logs").mkdir(parents=True, exist_ok=True) -(rvc_dir / "weights").mkdir(parents=True, exist_ok=True) - -# Download pretrained models (hubert, rmvpe) from RVC repo or mirrors -print("Downloading pretrained models...") -try: - # Try to download from a mirror or use the ones that come with RVC - # The RVC repo should have these, but let's ensure they exist - hubert_path = rvc_dir / "assets" / "hubert" / "hubert_base.pt" - rmvpe_path = rvc_dir / "assets" / "rmvpe" / "rmvpe.pt" - - if not hubert_path.exists(): - print("Downloading hubert model...") - # This is a simplified approach - in practice, we'd download from HF - pass # RVC installation should provide these - - if not rmvpe_path.exists(): - print("Downloading rmvpe model...") - pass # RVC installation should provide these - -except Exception as e: - print(f"Note: Could not download pretrained models: {e}") - -print("Setup complete - models will be downloaded from RVC repo or HF at runtime if needed") \ No newline at end of file diff --git a/example_request.json b/example_request.json deleted file mode 100644 index f40dd8e0b3b1320f87ae6009c1d0d2d16a15e3b6..0000000000000000000000000000000000000000 --- a/example_request.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "ops": [ - {"op": "create_object", "type": "sphere", "name": "Ball", "location": [0, 0, 1]}, - {"op": "add_material", "target": "Ball", "color": [0.8, 0.1, 0.1, 1.0], "roughness": 0.3}, - {"op": "add_light", "type": "SUN", "location": [4, -4, 6], "energy": 3}, - {"op": "set_camera", "location": [6, -6, 4], "look_at": [0, 0, 1]}, - {"op": "set_render_settings", "resolution": [960, 540], "samples": 32}, - {"op": "render_image", "filename": "ball.png"}, - {"op": "export_glb", "filename": "ball.glb"} - ] -} diff --git a/i18n/i18n.py b/i18n/i18n.py deleted file mode 100644 index 9afa43742617446389497f66d1567638707660f6..0000000000000000000000000000000000000000 --- a/i18n/i18n.py +++ /dev/null @@ -1,26 +0,0 @@ -import json -import locale -import os -from tools.file_io import read_text - - -def load_language_list(language): - return json.loads(read_text(f"./i18n/locale/{language}.json")) - - -class I18nAuto: - def __init__(self, language=None): - if language in ["Auto", None]: - language = locale.getdefaultlocale()[ - 0 - ] # getlocale can't identify the system's language ((None, None)) - if not os.path.exists(f"./i18n/locale/{language}.json"): - language = "en_US" - self.language = language - self.language_map = load_language_list(language) - - def __call__(self, key): - return self.language_map.get(key, key) - - def __repr__(self): - return "Use Language: " + self.language diff --git a/i18n/locale/en_US.json b/i18n/locale/en_US.json deleted file mode 100644 index 5a39987873c76bdf558935d6e9b2002a0a5b20ca..0000000000000000000000000000000000000000 --- a/i18n/locale/en_US.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s is running; stop it before starting another task", - "====> 轮次:{} {}": "====> Epoch: {} {}", - "A模型权重": "Weight (w) for Model A:", - "A模型路径": "Path to Model A:", - "B模型路径": "Path to Model B:", - "CUDA Graph预热完成": "CUDA Graph warm-up complete", - "CUDA可用:%s": "CUDA available: %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "Training folder path, for example: E:\\My training set", - "F0与HuBERT特征提取": "F0 and HuBERT feature extraction", - "F0提取": "F0 extraction", - "F0提取没有生成有效结果,已停止训练": "F0 extraction produced no valid results. Training has been stopped.", - "HuBERT特征": "HuBERT features", - "HuBERT特征提取没有生成有效结果,已停止训练": "HuBERT feature extraction produced no valid results. Training has been stopped.", - "Index Rate": "Index Rate", - "SOLA偏移:%d": "SOLA offset: %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[F0 extraction] Completed | Success: %s | Skipped: %s | Failed: %s", - "[F0提取] 待处理:%s": "[F0 extraction] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[F0 extraction] No pending audio; all files were skipped", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[F0 extraction] Progress: %s/%s | Success: %s | Skipped: %s | %s", - "[F0提取][失败] %s": "[F0 extraction][Failed] %s", - "[F0提取][失败] %s\n%s": "[F0 extraction][Failed] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[HuBERT features] Completed | Success: %s | Skipped: %s | Failed: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[HuBERT features] No pending audio; skipped: %s", - "[HuBERT特征] 正在加载模型:%s": "[HuBERT features] Loading model: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[HuBERT features] Device: %s | Pending: %s | Skipped: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[HuBERT features] Progress: %s/%s | Success: %s | Failed: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[HuBERT features][Failed] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[HuBERT features][Failed] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[HuBERT features][Failed] Model not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[Data slicing] Worker completed | Success: %s | Failed: %s", - "[数据切分] 完成": "[Data slicing] Completed", - "[数据切分] 开始": "[Data slicing] Started", - "[数据切分] 待处理:%s | 进程数:%s": "[Data slicing] Pending: %s | Processes: %s", - "[数据切分] 进度:%s/%s | %s": "[Data slicing] Progress: %s/%s | %s", - "[数据切分][失败] %s": "[Data slicing][Failed] %s", - "[数据切分][失败] %s\n%s": "[Data slicing][Failed] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[Data slicing][Skipped] Invalid or abnormal audio segment: %s_%s | Peak: %s", - "[索引训练] 写入进度:%s/%s": "[Index training] Write progress: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[Index training] External index link already exists: %s", - "[索引训练] 已链接索引到外部目录:%s": "[Index training] Linked index to external directory: %s", - "[索引训练] 成功构建索引:%s": "[Index training] Index built successfully: %s", - "[索引训练] 正在写入特征向量": "[Index training] Adding feature vectors", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[Index training] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[Index training] Training index", - "[索引训练] 特征形状:%s | IVF数量:%s": "[Index training] Feature shape: %s | IVF count: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[Index training][Failed] Could not link index to external directory: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[Index training][Failed] Clustering failed; continuing with the original features\n%s", - "[索引训练][失败] 请先进行特征提取": "[Index training][Failed] Extract features first", - "[索引训练][跳过] added索引已存在:%s": "[Index training][Skipped] added index already exists: %s", - "[索引训练][跳过] trained索引已存在:%s": "[Index training][Skipped] trained index already exists: %s", - "ckpt处理": "ckpt Processing", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": "The index file path cannot contain Chinese characters", - "pth文件路径不可包含中文": "The .pth file path cannot contain Chinese characters", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "Enter the GPU index(es) separated by '-', e.g., 0-0-1 to use 2 processes in GPU0 and 1 process in GPU1", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "Step 1: Fill in the experimental configuration. Experimental data is stored in the 'logs' folder, with each experiment having a separate folder. Manually enter the experiment name path, which contains the experimental configuration, logs, and trained model files.", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "Step 2b: Pitch and HuBERT semantic feature extraction", - "step3: 填写训练设置, 开始训练模型和索引": "Step 3: Fill in the training settings and start training the model and index", - "……仅显示最近10条失败记录": "…Showing only the 10 most recent failures", - "……已省略前%s行,仅显示最新状态": "…Omitted the first %s lines; showing the latest status only", - "一键训练": "One-click training", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "Primary output folder", - "也可批量输入音频文件, 二选一, 优先读文件夹": "Multiple audio files can also be imported. If a folder path exists, this input is ignored.", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "Batch processing of vocals, accompaniment, and reverb using pymss/MSST models.", - "人声伴奏分离&去混响": "Vocals/Accompaniment Separation & Dereverberation", - "仅支持pm和rmvpe音高提取算法": "Only the pm and rmvpe pitch extraction methods are supported", - "从训练检查点提取的模型": "Model extracted from a training checkpoint", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "Enter the GPU index(es) separated by '-', e.g., 0-1-2 to use GPU 0, 1, and 2:", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "Task", - "使用显卡:%s": "GPUs in use: %s", - "使用模型采样率": "Use model sample rate", - "使用设备采样率": "Use device sample rate", - "保存名": "Save name:", - "保存的文件名, 默认空为和源文件同名": "Save file name (default: same as the source file):", - "保存的模型名不带后缀": "Saved model name (without extension):", - "保存频率save_every_epoch": "Save frequency (save_every_epoch):", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Protect voiceless consonants and breath sounds to prevent artifacts such as tearing in electronic music. Set to 0.5 to disable. Decrease the value to increase protection, but it may reduce indexing accuracy:", - "修改": "Modify", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Modify model information (only supported for small model files extracted from the 'weights' folder)", - "停止一键训练": "Stop one-click training", - "停止分离": "Stop separation", - "停止处理数据": "Stop data preprocessing", - "停止特征提取": "Stop feature extraction", - "停止训练模型": "Stop model training", - "停止训练索引": "Stop index training", - "停止音频转换": "Stop audio conversion", - "分离残余文件夹": "Residual output folder", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "Refresh voice list", - "加载模型": "Load model", - "加载预训练底模D路径": "Load pre-trained base model D path:", - "加载预训练底模G路径": "Load pre-trained base model G path:", - "单次推理": "Single Inference", - "单说话人": "Single speaker", - "卸载音色省显存": "Unload voice to save GPU memory:", - "变调(整数, 半音数量, 升八度12降八度-12)": "Transpose (integer, number of semitones, raise by an octave: 12, lower by an octave: -12):", - "合成": "Synthesis", - "后处理重采样至最终采样率,0为不进行重采样": "Resample the output audio in post-processing to the final sample rate. Set to 0 for no resampling:", - "否": "No", - "响应阈值": "Response threshold", - "响度因子": "loudness factor", - "处理中": "Processing", - "处理数据": "Process data", - "处理方式": "Processing mode", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "Note: Multi-speaker training may not reproduce each voice as accurately as training each speaker separately!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "Failed", - "失败记录": "Failure records", - "子进程执行失败,返回码:%s": "Child process failed with exit code: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "Export file format", - "已停止": "Stopped", - "已加载判别器预训练模型:%s": "Loaded discriminator pretrained model: %s", - "已加载生成器预训练模型:%s": "Loaded generator pretrained model: %s", - "已启用索引检索": "Index search enabled", - "已完成": "Completed", - "已完成阶段": "Completed stages", - "已恢复判别器检查点": "Restored discriminator checkpoint", - "已成功": "Succeeded", - "常见问题解答": "FAQ (Frequently Asked Questions)", - "常规设置": "General settings", - "底层模型": "Underlying model", - "开始音频转换": "Start audio conversion", - "当前": "Current", - "当前设备:%s | 推理精度:%s": "Current device: %s | Inference precision: %s", - "当前阶段": "Current stage", - "很遗憾您这没有能用的显卡来支持您训练": "Unfortunately, there is no compatible GPU available to support your training.", - "性别因子/声线粗细": "Gender factor / voice thickness", - "性能设置": "Performance settings", - "总训练轮数total_epoch": "Total training epochs (total_epoch):", - "成功": "Success", - "执行命令": "Command", - "批量推理": "Batch Inference", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Batch conversion. Enter the folder containing the audio files to be converted or upload multiple audio files. The converted audio will be output in the specified folder (default: 'opt').", - "拖拽或点击上传待处理音频": "Drag and drop or click to upload audio for processing", - "指定输出文件夹": "Specify output folder:", - "推理时间(ms):": "Inference time (ms):", - "推理耗时:%.2f秒": "Inference time: %.2f seconds", - "推理音色": "Inferencing voice:", - "提交训练集清单": "Submit dataset manifest", - "提取": "Extract", - "提取音高和处理数据使用的CPU进程数": "Number of CPU processes used for pitch extraction and data processing:", - "数据切分": "Data slicing", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "Dataset preprocessing produced no 16 kHz audio. Feature extraction and training have been stopped.", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "Dataset preprocessing produced no valid training audio. Check the dataset and preprocessing log.", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "Dataset preprocessing outputs do not match. Feature extraction and training have been stopped.", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "Data extraction started: start_time=%.6f, requested concurrency=%s, actual concurrency limit=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "Data extraction finished: end_time=%.6f, total elapsed=%.3f seconds", - "新增一行": "Add row", - "无法停止": "Cannot stop", - "是": "Yes", - "是否仅保存最新的ckpt文件以节省硬盘空间": "Save only the latest '.ckpt' file to save disk space:", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "Save a small final model to the 'weights' folder at each save point:", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Cache all training sets to GPU memory. Caching small datasets (less than 10 minutes) can speed up training, but caching large datasets will consume a lot of GPU memory and may not provide much speed improvement:", - "显卡信息": "GPU Information", - "未使用": "Not used", - "未使用判别器预训练模型": "Discriminator pretrained model not used", - "未使用生成器预训练模型": "Generator pretrained model not used", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "No supported GPU detected; training on the CPU may take much longer", - "未运行": "Not running", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "This software is open source under the MIT license. The author does not have any control over the software. Users who use the software and distribute the sounds exported by the software are solely responsible.
If you do not agree with this clause, you cannot use or reference any codes and files within the software package. See the root directory Agreement-LICENSE.txt for details.", - "查看": "View", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "View model information (only supported for small model files extracted from the 'weights' folder)", - "检索特征占比": "Search feature ratio (controls accent strength, too high has artifacting):", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "Model information: %s\nSample rate: %s\nPitch guidance: %s\nVersion: %s", - "模型推理": "Model Inference", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "Model extraction (enter the path of the large file model under the 'logs' folder). This is useful if you want to stop training halfway and manually extract and save a small model file, or if you want to test an intermediate model:", - "模型是否带音高指导": "Whether the model has pitch guidance:", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "Whether the model has pitch guidance (required for singing, optional for speech):", - "模型是否带音高指导,1是0否": "Whether the model has pitch guidance (1: yes, 0: no):", - "模型版本型号": "Model architecture version:", - "模型融合, 可用于测试音色融合": "Model fusion, can be used to test timbre fusion", - "模型融合失败:两个模型的结构不一致": "Model merge failed: the two model architectures do not match", - "模型训练": "Model training", - "模型路径": "Path to Model:", - "正在保存最终检查点:%s": "Saving final checkpoint: %s", - "正在保存检查点 %s_e%s:%s": "Saving checkpoint %s_e%s: %s", - "正在加载RMVPE模型": "Loading RMVPE model", - "正在加载模型": "Loading model", - "正在启动": "Starting", - "正在收尾": "Finalizing", - "正在预热CUDA Graph": "Warming up CUDA Graph", - "每张显卡的batch_size": "Batch size per GPU:", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "No valid audio is available for training. Complete dataset preprocessing and feature extraction first.", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "Fade length", - "清理模型缓存": "Clearing model cache", - "版本": "Version", - "特征": "Features", - "特征提取": "Feature extraction", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "Feature index path (automatically matched after selecting a model; editable)", - "状态": "Status", - "独占 WASAPI 设备": "Exclusive WASAPI device", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "Target sample rate:", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "Waiting", - "等待输入": "Waiting for input", - "算法延迟(ms):": "Algorithmic delays(ms):", - "索引": "Index", - "索引文件不存在,将不使用索引继续推理:%s": "Index file does not exist; inference will continue without an index: %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "Invalid index: use added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "Index search failed", - "索引检索失败或未启用": "Index search failed or is disabled", - "索引训练": "Index training", - "耗时": "Elapsed time", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "Elapsed time: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "Fusion", - "要改的模型信息": "Model information to be modified:", - "要置入的模型信息": "Model information to be placed:", - "训练": "Train", - "训练已完成,正在保存最终模型": "Training completed; saving the final model", - "训练文件列表写入完成": "Training file list written successfully", - "训练模型": "Train model", - "训练特征索引": "Train feature index", - "训练设备规则选择的精度:%s": "Training precision selected by device rules: %s", - "训练轮次:{} [{:.0f}%]": "Training epoch: {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "Device type", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "Upload an audio file", - "请填写输出文件夹路径": "Enter the output folder path", - "请指定说话人id": "Please specify the speaker/singer ID:", - "请选择index文件": "Please choose the .index file", - "请选择pth文件": "Please choose the .pth file", - "请选择说话人id": "Select Speaker/Singer ID:", - "转换": "Convert", - "输入实验名": "Enter the experiment name:", - "输入实验名,例如:test": "Experiment name, for example: test", - "输入待处理音频文件夹路径": "Enter the path of the audio folder to be processed:", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "Enter the path of the audio folder to be processed (copy it from the address bar of the file manager):", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "Adjust the volume envelope scaling. Closer to 0, the more it mimicks the volume of the original vocals. Can help mask noise and make volume sound more natural when set relatively low. Closer to 1 will be more of a consistently loud volume:", - "输入监听": "Input voice monitor", - "输入训练文件夹路径": "Enter the path of the training folder:", - "输入设备": "Input device", - "输入设备:%s:%s": "Input device: %s:%s", - "输入降噪": "Input noise reduction", - "输出信息": "Output information", - "输出变声": "Output converted voice", - "输出设备": "Output device", - "输出设备:%s:%s": "Output device: %s:%s", - "输出降噪": "Output noise reduction", - "输出音频(右下角三个点,点了可以下载)": "Export audio (click on the three dots in the lower right corner to download)", - "运行中": "Running", - "进度": "Progress", - "选择.index文件": "Select the .index file", - "选择.pth文件": "Select the .pth file", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "Select model", - "选择索引": "Select index", - "选择音高提取算法": "Select the pitch extraction algorithm", - "采样率:": "Sample rate:", - "采样长度": "Sample length", - "重复次数": "Repeat count", - "重载设备列表": "Reload device list", - "音调设置": "Pitch settings", - "音频设备": "Audio device", - "音高全部为0,该音频无意义,跳过:%s": "All pitch values are zero; this audio is unusable and will be skipped: %s", - "音高算法": "pitch detection algorithm", - "额外推理时长": "Extra inference time" -} diff --git a/i18n/locale/es_ES.json b/i18n/locale/es_ES.json deleted file mode 100644 index 65098ac0df98351899028c762c4aa4e186bf1d4d..0000000000000000000000000000000000000000 --- a/i18n/locale/es_ES.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s está en ejecución; deténgalo antes de iniciar otra tarea", - "====> 轮次:{} {}": "====> Época: {} {}", - "A模型权重": "Un peso modelo para el modelo A.", - "A模型路径": "Modelo A ruta.", - "B模型路径": "Modelo B ruta.", - "CUDA Graph预热完成": "Preparación de CUDA Graph completada", - "CUDA可用:%s": "CUDA disponible: %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "Ruta de la carpeta de entrenamiento, por ejemplo: E:\\Mi conjunto de entrenamiento", - "F0与HuBERT特征提取": "Extracción de F0 y características HuBERT", - "F0提取": "Extracción F0", - "F0提取没有生成有效结果,已停止训练": "La extracción de F0 no generó resultados válidos. Se detuvo el entrenamiento.", - "HuBERT特征": "Características HuBERT", - "HuBERT特征提取没有生成有效结果,已停止训练": "La extracción de características HuBERT no generó resultados válidos. Se detuvo el entrenamiento.", - "Index Rate": "Tasa de índice", - "SOLA偏移:%d": "Desplazamiento SOLA: %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Extracción F0] Completado | Éxito: %s | Omitidos: %s | Error: %s", - "[F0提取] 待处理:%s": "[Extracción F0] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[Extracción F0] No hay audio pendiente; se omitieron todos los archivos", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[Extracción F0] Progreso: %s/%s | Éxito: %s | Omitidos: %s | %s", - "[F0提取][失败] %s": "[Extracción F0][Error] %s", - "[F0提取][失败] %s\n%s": "[Extracción F0][Error] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Características HuBERT] Completado | Éxito: %s | Omitidos: %s | Error: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[Características HuBERT] No hay audio pendiente; omitidos: %s", - "[HuBERT特征] 正在加载模型:%s": "[Características HuBERT] Cargando el modelo: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[Características HuBERT] Dispositivo: %s | Pending: %s | Omitidos: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[Características HuBERT] Progreso: %s/%s | Éxito: %s | Error: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[Características HuBERT][Error] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[Características HuBERT][Error] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[Características HuBERT][Error] Modelo not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[División de datos] Subtarea completada | Éxito: %s | Error: %s", - "[数据切分] 完成": "[División de datos] Completado", - "[数据切分] 开始": "[División de datos] Iniciado", - "[数据切分] 待处理:%s | 进程数:%s": "[División de datos] Pending: %s | Procesos: %s", - "[数据切分] 进度:%s/%s | %s": "[División de datos] Progreso: %s/%s | %s", - "[数据切分][失败] %s": "[División de datos][Error] %s", - "[数据切分][失败] %s\n%s": "[División de datos][Error] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[División de datos][Omitidos] Segmento de audio no válido o anómalo: %s_%s | Pico: %s", - "[索引训练] 写入进度:%s/%s": "[Entrenamiento del índice] Progreso de escritura: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[Entrenamiento de índice] El enlace externo ya existe: %s", - "[索引训练] 已链接索引到外部目录:%s": "[Entrenamiento del índice] Índice enlazado al directorio externo: %s", - "[索引训练] 成功构建索引:%s": "[Entrenamiento del índice] Índice creado correctamente: %s", - "[索引训练] 正在写入特征向量": "[Entrenamiento del índice] Añadiendo vectores de características", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[Entrenamiento del índice] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[Entrenamiento del índice] Entrenando el índice", - "[索引训练] 特征形状:%s | IVF数量:%s": "[Entrenamiento del índice] Forma de características: %s | Cantidad de IVF: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[Entrenamiento del índice][Error] No se pudo enlazar el índice al directorio externo: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[Entrenamiento del índice][Error] Falló el agrupamiento; se continuará con las características originales\n%s", - "[索引训练][失败] 请先进行特征提取": "[Entrenamiento del índice][Error] Extraiga primero las características", - "[索引训练][跳过] added索引已存在:%s": "[Entrenamiento de índice][Omitido] El índice added ya existe: %s", - "[索引训练][跳过] trained索引已存在:%s": "[Entrenamiento de índice][Omitido] El índice trained ya existe: %s", - "ckpt处理": "Procesamiento de recibos", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": "La ruta del archivo .index no debe contener caracteres chinos.", - "pth文件路径不可包含中文": "La ruta del archivo .pth no debe contener caracteres chinos.", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "Separe los números de identificación de la GPU con '-' al ingresarlos. Por ejemplo, '0-1-2' significa usar GPU 0, GPU 1 y GPU 2.", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "Paso 1: Complete la configuración del experimento. Los datos del experimento se almacenan en el directorio 'logs', con cada experimento en una carpeta separada. La ruta del nombre del experimento debe ingresarse manualmente y debe contener la configuración del experimento, los registros y los archivos del modelo entrenado.", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "Paso 2b: extracción de tono y características semánticas de HuBERT", - "step3: 填写训练设置, 开始训练模型和索引": "Paso 3: Complete la configuración de entrenamiento y comience a entrenar el modelo y el índice.", - "……仅显示最近10条失败记录": "…Se muestran solo los 10 errores más recientes", - "……已省略前%s行,仅显示最新状态": "…Se omitieron las primeras %s líneas; se muestra solo el estado más reciente", - "一键训练": "Entrenamiento con un clic", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "Carpeta de salida principal", - "也可批量输入音频文件, 二选一, 优先读文件夹": "También se pueden importar varios archivos de audio. Si existe una ruta de carpeta, esta entrada se ignora.", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "Procesamiento por lotes de voz, acompañamiento y reverberación con modelos pymss/MSST.", - "人声伴奏分离&去混响": "Separación de voz/acompañamiento y eliminación de reverberación", - "仅支持pm和rmvpe音高提取算法": "Solo se admiten los métodos de extracción de tono pm y rmvpe", - "从训练检查点提取的模型": "Modeloo extraído de un punto de control de entrenamiento", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "Separe los números de identificación de la GPU con '-' al ingresarlos. Por ejemplo, '0-1-2' significa usar GPU 0, GPU 1 y GPU 2.", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "Tarea", - "使用显卡:%s": "GPU en uso: %s", - "使用模型采样率": "Usar la frecuencia del modelo", - "使用设备采样率": "Usar la frecuencia del dispositivo", - "保存名": "Guardar nombre", - "保存的文件名, 默认空为和源文件同名": "Nombre del archivo que se guardará, el valor predeterminado es el mismo que el nombre del archivo de origen", - "保存的模型名不带后缀": "Nombre del modelo guardado sin extensión.", - "保存频率save_every_epoch": "Frecuencia de guardado (save_every_epoch)", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Proteger las consonantes claras y la respiración, prevenir artefactos como la distorsión de sonido electrónico, 0.5 no está activado, reducir aumentará la protección pero puede reducir el efecto del índice", - "修改": "Modificar", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Modificar la información del modelo (solo admite archivos de modelos pequeños extraídos en la carpeta weights)", - "停止一键训练": "Detener entrenamiento con un clic", - "停止分离": "Detener separación", - "停止处理数据": "Detener preprocesamiento de datos", - "停止特征提取": "Detener extracción de características", - "停止训练模型": "Detener entrenamiento del modelo", - "停止训练索引": "Detener entrenamiento del índice", - "停止音频转换": "Detener la conversión de audio", - "分离残余文件夹": "Carpeta de salida residual", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "Actualizar lista de voces", - "加载模型": "Cargar modelo", - "加载预训练底模D路径": "Cargue la ruta del modelo D base pre-entrenada.", - "加载预训练底模G路径": "Cargue la ruta del modelo G base pre-entrenada.", - "单次推理": "Inferencia individual", - "单说话人": "Single speaker", - "卸载音色省显存": "Descargue la voz para ahorrar memoria GPU", - "变调(整数, 半音数量, 升八度12降八度-12)": "Cambio de tono (entero, número de semitonos, subir una octava +12 o bajar una octava -12)", - "合成": "Síntesis", - "后处理重采样至最终采样率,0为不进行重采样": "Remuestreo posterior al proceso a la tasa de muestreo final, 0 significa no remuestrear", - "否": "No", - "响应阈值": "Umbral de respuesta", - "响度因子": "factor de sonoridad", - "处理中": "Procesando", - "处理数据": "Procesar datos", - "处理方式": "Modo de procesamiento", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "Nota: El entrenamiento multihablante puede no reproducir cada voz tan fielmente como entrenar a cada hablante por separado!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "Error", - "失败记录": "Registro de errores", - "子进程执行失败,返回码:%s": "El subproceso falló con el código de salida: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "Formato de archivo de exportación", - "已停止": "Detenido", - "已加载判别器预训练模型:%s": "Modeloo preentrenado del discriminador cargado: %s", - "已加载生成器预训练模型:%s": "Modeloo preentrenado del generador cargado: %s", - "已启用索引检索": "Búsqueda por índice activada", - "已完成": "Completado", - "已完成阶段": "Etapas completadas", - "已恢复判别器检查点": "Se restauró el punto de control del discriminador", - "已成功": "Correcto", - "常见问题解答": "Preguntas frecuentes", - "常规设置": "Configuración general", - "底层模型": "Modelo subyacente", - "开始音频转换": "Iniciar conversión de audio", - "当前": "Actual", - "当前设备:%s | 推理精度:%s": "Dispositivo actual: %s | Precisión de inferencia: %s", - "当前阶段": "Etapa actual", - "很遗憾您这没有能用的显卡来支持您训练": "Lamentablemente, no tiene una tarjeta gráfica adecuada para soportar su entrenamiento", - "性别因子/声线粗细": "Factor de género / grosor de la voz", - "性能设置": "Configuración de rendimiento", - "总训练轮数total_epoch": "Total de épocas de entrenamiento (total_epoch)", - "成功": "Éxito", - "执行命令": "Comando", - "批量推理": "Inferencia por lotes", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Conversión por lotes, ingrese la carpeta que contiene los archivos de audio para convertir o cargue varios archivos de audio. El audio convertido se emitirá en la carpeta especificada (opción predeterminada).", - "拖拽或点击上传待处理音频": "Arrastre y suelte o haga clic para subir el audio que desea procesar", - "指定输出文件夹": "Especificar carpeta de salida", - "推理时间(ms):": "Inferir tiempo (ms):", - "推理耗时:%.2f秒": "Tiempo de inferencia: %.2f seconds", - "推理音色": "inferencia de voz", - "提交训练集清单": "Submit dataset manifest", - "提取": "Extraer", - "提取音高和处理数据使用的CPU进程数": "Número de procesos de CPU utilizados para extraer el tono y procesar los datos", - "数据切分": "División de datos", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "El preprocesamiento no generó audio de 16 kHz. Se detuvieron la extracción de características y el entrenamiento.", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "El preprocesamiento no generó audio de entrenamiento válido. Revise el conjunto de datos y el registro.", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "Los archivos de salida del preprocesamiento no coinciden. Se detuvieron la extracción y el entrenamiento.", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "Extracción de datos iniciada: start_time=%.6f, concurrencia solicitada=%s, límite real=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "Extracción de datos finalizada: end_time=%.6f, tiempo total=%.3f segundos", - "新增一行": "Add row", - "无法停止": "No se puede detener", - "是": "Sí", - "是否仅保存最新的ckpt文件以节省硬盘空间": "Guardar solo el archivo ckpt más reciente para ahorrar espacio en disco", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "Guardar pequeño modelo final en la carpeta 'weights' en cada punto de guardado", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Si almacenar en caché todos los conjuntos de entrenamiento en la memoria de la GPU. Los conjuntos de datos pequeños (menos de 10 minutos) se pueden almacenar en caché para acelerar el entrenamiento, pero el almacenamiento en caché de conjuntos de datos grandes puede causar errores de memoria en la GPU y no aumenta la velocidad de manera significativa.", - "显卡信息": "información de la GPU", - "未使用": "No utilizado", - "未使用判别器预训练模型": "No se usó el modelo preentrenado del discriminador", - "未使用生成器预训练模型": "No se usó el modelo preentrenado del generador", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "No se detectó una GPU compatible; entrenar con la CPU puede tardar mucho más", - "未运行": "No iniciado", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "Este software es de código abierto bajo la licencia MIT, el autor no tiene ningún control sobre el software, y aquellos que usan el software y difunden los sonidos exportados por el software son los únicos responsables.
Si no está de acuerdo con esta cláusula , no puede utilizar ni citar ningún código ni archivo del paquete de software Consulte el directorio raíz Agreement-LICENSE.txt para obtener más información.", - "查看": "Ver", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "Ver información del modelo (solo aplicable a archivos de modelos pequeños extraídos de la carpeta 'pesos')", - "检索特征占比": "Proporción de función de búsqueda", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "Información del modelo: %s\nFrecuencia de muestreo: %s\nGuía de tono: %s\nVersión: %s", - "模型推理": "inferencia del modelo", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "Extracción de modelo (ingrese la ruta de un archivo de modelo grande en la carpeta 'logs'), aplicable cuando desea extraer un archivo de modelo pequeño después de entrenar a mitad de camino y no se guardó automáticamente, o cuando desea probar un modelo intermedio", - "模型是否带音高指导": "Si el modelo tiene guía de tono.", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "Si el modelo tiene guía de tono (necesaria para cantar, pero no para hablar)", - "模型是否带音高指导,1是0否": "Si el modelo tiene guía de tono, 1 para sí, 0 para no", - "模型版本型号": "Versión y modelo del modelo", - "模型融合, 可用于测试音色融合": "Fusión de modelos, se puede utilizar para fusionar diferentes voces", - "模型融合失败:两个模型的结构不一致": "Error al fusionar modelos: las arquitecturas no coinciden", - "模型训练": "Entrenamiento del modelo", - "模型路径": "Ruta del modelo", - "正在保存最终检查点:%s": "Guardando el punto de control final: %s", - "正在保存检查点 %s_e%s:%s": "Guardando el punto de control %s_e%s: %s", - "正在加载RMVPE模型": "Cargando el modelo RMVPE", - "正在加载模型": "Cargando el modelo", - "正在启动": "Iniciando", - "正在收尾": "Finalizando", - "正在预热CUDA Graph": "Preparando CUDA Graph", - "每张显卡的batch_size": "Tamaño del lote (batch_size) por tarjeta gráfica", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "No hay audio válido para entrenar. Complete primero el preprocesamiento y la extracción de características.", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "Duración del fundido de entrada/salida", - "清理模型缓存": "Limpiando la caché del modelo", - "版本": "Versión", - "特征": "Características", - "特征提取": "Extracción de características", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "Ruta del índice de características (se detecta al elegir el modelo; editable)", - "状态": "Estado", - "独占 WASAPI 设备": "Dispositivo WASAPI exclusivo", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "Tasa de muestreo objetivo", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "En espera", - "等待输入": "Esperando entrada", - "算法延迟(ms):": "Latencia del algoritmo (ms):", - "索引": "Índice", - "索引文件不存在,将不使用索引继续推理:%s": "El archivo de índice no existe; la inferencia continuará sin índice: %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "Índice no válido: use added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "Falló la búsqueda por índice", - "索引检索失败或未启用": "La búsqueda por índice falló o está desactivada", - "索引训练": "Entrenamiento del índice", - "耗时": "Tiempo transcurrido", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "Tiempo transcurrido: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "Fusión", - "要改的模型信息": "Información del modelo a modificar", - "要置入的模型信息": "Información del modelo a colocar.", - "训练": "Entrenamiento", - "训练已完成,正在保存最终模型": "Entrenamiento completado; guardando el modelo final", - "训练文件列表写入完成": "Lista de archivos de entrenamiento guardada", - "训练模型": "Entrenar Modelo", - "训练特征索引": "Índice de características", - "训练设备规则选择的精度:%s": "Precisión de entrenamiento elegida según las reglas del dispositivo: %s", - "训练轮次:{} [{:.0f}%]": "Época de entrenamiento: {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "Tipo de dispositivo", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "Suba un archivo de audio", - "请填写输出文件夹路径": "Introduzca la ruta de la carpeta de salida", - "请指定说话人id": "ID del modelo", - "请选择index文件": "Seleccione el archivo .index", - "请选择pth文件": "Seleccione el archivo .pth", - "请选择说话人id": "Seleccione una identificación de altavoz", - "转换": "Conversión", - "输入实验名": "Ingrese el nombre del modelo", - "输入实验名,例如:test": "Nombre del experimento, por ejemplo: test", - "输入待处理音频文件夹路径": "Ingrese la ruta a la carpeta de audio que se procesará", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "Ingrese la ruta a la carpeta de audio que se procesará (simplemente cópiela desde la barra de direcciones del administrador de archivos)", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "Proporción de fusión para reemplazar el sobre de volumen de entrada con el sobre de volumen de salida, cuanto más cerca de 1, más se utiliza el sobre de salida", - "输入监听": "Monitorizar entrada", - "输入训练文件夹路径": "Introduzca la ruta de la carpeta de entrenamiento", - "输入设备": "Dispositivo de entrada", - "输入设备:%s:%s": "Dispositivo de entrada: %s:%s", - "输入降噪": "Reducción de ruido de entrada", - "输出信息": "Información de salida", - "输出变声": "Conversión de salida", - "输出设备": "Dispositivo de salida", - "输出设备:%s:%s": "Dispositivo de salida: %s:%s", - "输出降噪": "Reducción de ruido de salida", - "输出音频(右下角三个点,点了可以下载)": "Salida de audio (haga clic en los tres puntos en la esquina inferior derecha para descargar)", - "运行中": "En ejecución", - "进度": "Progreso", - "选择.index文件": "Seleccione el archivo .index", - "选择.pth文件": "Seleccione el archivo .pth", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "Seleccionar modelo", - "选择索引": "Seleccionar índice", - "选择音高提取算法": "Seleccione el algoritmo de extracción de tono", - "采样率:": "Frecuencia de muestreo:", - "采样长度": "Longitud de muestreo", - "重复次数": "Repeat count", - "重载设备列表": "Actualizar lista de dispositivos", - "音调设置": "Ajuste de tono", - "音频设备": "Dispositivo de audio", - "音高全部为0,该音频无意义,跳过:%s": "Todos los valores de tono son cero; este audio no es útil y se omitirá: %s", - "音高算法": "Algoritmo de tono", - "额外推理时长": "Tiempo de inferencia adicional" -} diff --git a/i18n/locale/fr_FR.json b/i18n/locale/fr_FR.json deleted file mode 100644 index 99f0d77489d858a0a0c172fa58e5c043995f4f78..0000000000000000000000000000000000000000 --- a/i18n/locale/fr_FR.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s est en cours ; arrêtez cette tâche avant d'en démarrer une autre", - "====> 轮次:{} {}": "====> Époque : {} {}", - "A模型权重": "Poids (w) pour le modèle A :", - "A模型路径": "Chemin d'accès au modèle A :", - "B模型路径": "Chemin d'accès au modèle B :", - "CUDA Graph预热完成": "Préchauffage de CUDA Graph terminé", - "CUDA可用:%s": "CUDA disponible : %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "Chemin du dossier d'entraînement, par exemple : E:\\Mon jeu d'entraînement", - "F0与HuBERT特征提取": "Extraction F0 et caractéristiques HuBERT", - "F0提取": "Extraction F0", - "F0提取没有生成有效结果,已停止训练": "L'extraction F0 n'a produit aucun résultat valide. L'entraînement a été arrêté.", - "HuBERT特征": "Caractéristiques HuBERT", - "HuBERT特征提取没有生成有效结果,已停止训练": "L'extraction des caractéristiques HuBERT n'a produit aucun résultat valide. L'entraînement a été arrêté.", - "Index Rate": "Taux d'indexation", - "SOLA偏移:%d": "Décalage SOLA : %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Extraction F0] Terminé | Réussite: %s | Ignorés: %s | Échec: %s", - "[F0提取] 待处理:%s": "[Extraction F0] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[Extraction F0] Aucun audio en attente ; tous les fichiers ont été ignorés", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[Extraction F0] Progression: %s/%s | Réussite: %s | Ignorés: %s | %s", - "[F0提取][失败] %s": "[Extraction F0][Échec] %s", - "[F0提取][失败] %s\n%s": "[Extraction F0][Échec] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Caractéristiques HuBERT] Terminé | Réussite: %s | Ignorés: %s | Échec: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[Caractéristiques HuBERT] Aucun audio en attente ; ignorés: %s", - "[HuBERT特征] 正在加载模型:%s": "[Caractéristiques HuBERT] Chargement du modèle: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[Caractéristiques HuBERT] Périphérique: %s | Pending: %s | Ignorés: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[Caractéristiques HuBERT] Progression: %s/%s | Réussite: %s | Échec: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[Caractéristiques HuBERT][Échec] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[Caractéristiques HuBERT][Échec] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[Caractéristiques HuBERT][Échec] Modèle not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[Découpage des données] Sous-tâche terminée | Réussite: %s | Échec: %s", - "[数据切分] 完成": "[Découpage des données] Terminé", - "[数据切分] 开始": "[Découpage des données] Démarré", - "[数据切分] 待处理:%s | 进程数:%s": "[Découpage des données] Pending: %s | Processus: %s", - "[数据切分] 进度:%s/%s | %s": "[Découpage des données] Progression: %s/%s | %s", - "[数据切分][失败] %s": "[Découpage des données][Échec] %s", - "[数据切分][失败] %s\n%s": "[Découpage des données][Échec] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[Découpage des données][Ignorés] Segment audio invalide ou anormal: %s_%s | Crête: %s", - "[索引训练] 写入进度:%s/%s": "[Entraînement de l'index] Progressionion de l'écriture: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[Entraînement de l’index] Le lien externe existe déjà : %s", - "[索引训练] 已链接索引到外部目录:%s": "[Entraînement de l'index] Index lié au dossier externe: %s", - "[索引训练] 成功构建索引:%s": "[Entraînement de l'index] Index créé avec succès: %s", - "[索引训练] 正在写入特征向量": "[Entraînement de l'index] Ajout des vecteurs de caractéristiques", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[Entraînement de l'index] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[Entraînement de l'index] Entraînement de l'index", - "[索引训练] 特征形状:%s | IVF数量:%s": "[Entraînement de l'index] Forme des caractéristiques: %s | Nombre d'IVF: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[Entraînement de l'index][Échec] Impossible de lier l'index au dossier externe: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[Entraînement de l'index][Échec] Échec du regroupement ; poursuite avec les caractéristiques d'origine\n%s", - "[索引训练][失败] 请先进行特征提取": "[Entraînement de l'index][Échec] Extrayez d'abord les caractéristiques", - "[索引训练][跳过] added索引已存在:%s": "[Entraînement de l’index][Ignoré] L’index added existe déjà : %s", - "[索引训练][跳过] trained索引已存在:%s": "[Entraînement de l’index][Ignoré] L’index trained existe déjà : %s", - "ckpt处理": "Traitement des fichiers .ckpt", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": "Le chemin du fichier d'index ne doit pas contenir de caractères chinois.", - "pth文件路径不可包含中文": "Le chemin du fichier .pth ne doit pas contenir de caractères chinois.", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "Configuration des numéros de carte RMVPE : séparez les index GPU par des tirets \"-\", par exemple, 0-0-1 pour utiliser 2 processus sur GPU0 et 1 processus sur GPU1.", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "Étape 1 : Remplissez la configuration expérimentale. Les données expérimentales sont stockées dans le dossier 'logs', avec chaque expérience ayant un dossier distinct. Entrez manuellement le chemin du nom de l'expérience, qui contient la configuration expérimentale, les journaux et les fichiers de modèle entraînés.", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "Étape 2b : extraction de la hauteur et des caractéristiques sémantiques HuBERT", - "step3: 填写训练设置, 开始训练模型和索引": "Étape 3 : Remplissez les paramètres d'entraînement et démarrez l'entraînement du modèle ainsi que l'indexation.", - "……仅显示最近10条失败记录": "…Seuls les 10 échecs les plus récents sont affichés", - "……已省略前%s行,仅显示最新状态": "…Les %s premières lignes ont été omises ; seul l'état récent est affiché", - "一键训练": "Entraînement en un clic", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "Dossier de sortie principal", - "也可批量输入音频文件, 二选一, 优先读文件夹": "Il est également possible d'importer plusieurs fichiers audio. Si un chemin de dossier existe, cette entrée est ignorée.", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "Traitement par lots des voix, de l’accompagnement et de la réverbération avec les modèles pymss/MSST.", - "人声伴奏分离&去混响": "Séparation voix/accompagnement et suppression de la réverbération", - "仅支持pm和rmvpe音高提取算法": "Seules les méthodes d'extraction de hauteur pm et rmvpe sont prises en charge", - "从训练检查点提取的模型": "Modèle extrait d'un point de contrôle d'entraînement", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "Entrez le(s) index GPU séparé(s) par '-', par exemple, 0-1-2 pour utiliser les GPU 0, 1 et 2 :", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "Tâche", - "使用显卡:%s": "GPU utilisés : %s", - "使用模型采样率": "Utiliser la fréquence du modèle", - "使用设备采样率": "Utiliser la fréquence du périphérique", - "保存名": "Nom de sauvegarde :", - "保存的文件名, 默认空为和源文件同名": "Nom du fichier de sauvegarde (par défaut : identique au nom du fichier source) :", - "保存的模型名不带后缀": "Nom du modèle enregistré (sans extension) :", - "保存频率save_every_epoch": "Fréquence de sauvegarde (save_every_epoch) :", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Protéger les consonnes sourdes et les bruits de respiration pour éviter les artefacts tels que le déchirement dans la musique électronique. Réglez à 0,5 pour désactiver. Diminuez la valeur pour renforcer la protection, mais cela peut réduire la précision de l'indexation :", - "修改": "Modifier", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Modifier les informations du modèle (uniquement pris en charge pour les petits fichiers de modèle extraits du dossier 'weights')", - "停止一键训练": "Arrêter l’entraînement en un clic", - "停止分离": "Arrêter la séparation", - "停止处理数据": "Arrêter le prétraitement des données", - "停止特征提取": "Arrêter l’extraction des caractéristiques", - "停止训练模型": "Arrêter l’entraînement du modèle", - "停止训练索引": "Arrêter l’entraînement de l’index", - "停止音频转换": "Arrêter la conversion audio", - "分离残余文件夹": "Dossier de sortie résiduel", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "Actualiser la liste des voix", - "加载模型": "Charger le modèle.", - "加载预训练底模D路径": "Charger le chemin du modèle de base pré-entraîné D :", - "加载预训练底模G路径": "Charger le chemin du modèle de base pré-entraîné G :", - "单次推理": "Inférence unique", - "单说话人": "Single speaker", - "卸载音色省显存": "Décharger la voix pour économiser la mémoire GPU.", - "变调(整数, 半音数量, 升八度12降八度-12)": "Transposer (entier, nombre de demi-tons, monter d'une octave : 12, descendre d'une octave : -12) :", - "合成": "Synthèse", - "后处理重采样至最终采样率,0为不进行重采样": "Rééchantillonner l'audio de sortie en post-traitement à la fréquence d'échantillonnage finale. Réglez sur 0 pour ne pas effectuer de rééchantillonnage :", - "否": "Non", - "响应阈值": "Seuil de réponse", - "响度因子": "Facteur de volume sonore", - "处理中": "Traitement en cours", - "处理数据": "Traitement des données", - "处理方式": "Mode de traitement", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "Remarque : l'entraînement multi-locuteurs peut restituer chaque voix moins fidèlement qu'un entraînement séparé par locuteur !", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "Échec", - "失败记录": "Détails des échecs", - "子进程执行失败,返回码:%s": "Le sous-processus a échoué avec le code de sortie: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "Format de fichier d'exportation", - "已停止": "Arrêté", - "已加载判别器预训练模型:%s": "Modèle préentraîné du discriminateur chargé: %s", - "已加载生成器预训练模型:%s": "Modèle préentraîné du générateur chargé: %s", - "已启用索引检索": "Recherche par index activée", - "已完成": "Terminé", - "已完成阶段": "Étapes terminées", - "已恢复判别器检查点": "Point de contrôle du discriminateur restauré", - "已成功": "Réussi", - "常见问题解答": "FAQ (Foire Aux Questions)", - "常规设置": "Paramètres généraux", - "底层模型": "Modèle sous-jacent", - "开始音频转换": "Démarrer la conversion audio.", - "当前": "Actuel", - "当前设备:%s | 推理精度:%s": "Périphérique actuel : %s | Précision d’inférence : %s", - "当前阶段": "Étape actuelle", - "很遗憾您这没有能用的显卡来支持您训练": "Malheureusement, il n'y a pas de GPU compatible disponible pour prendre en charge votre entrainement.", - "性别因子/声线粗细": "Facteur de genre / épaisseur de la voix", - "性能设置": "Paramètres de performance", - "总训练轮数total_epoch": "Nombre total d'époques d'entraînement (total_epoch) :", - "成功": "Réussite", - "执行命令": "Commande", - "批量推理": "Inférence par lot", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Conversion en lot. Entrez le dossier contenant les fichiers audio à convertir ou téléchargez plusieurs fichiers audio. Les fichiers audio convertis seront enregistrés dans le dossier spécifié (par défaut : 'opt').", - "拖拽或点击上传待处理音频": "Glissez-déposez ou cliquez pour téléverser l’audio à traiter", - "指定输出文件夹": "Spécifiez le dossier de sortie :", - "推理时间(ms):": "Temps d'inférence (ms) :", - "推理耗时:%.2f秒": "Temps d'inférence: %.2f seconds", - "推理音色": "Voix pour l'inférence", - "提交训练集清单": "Submit dataset manifest", - "提取": "Extraire", - "提取音高和处理数据使用的CPU进程数": "Nombre de processus CPU utilisés pour l'extraction de la hauteur et le traitement des données :", - "数据切分": "Découpage des données", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "Le prétraitement n'a produit aucun audio 16 kHz. L'extraction et l'entraînement ont été arrêtés.", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "Le prétraitement n'a produit aucun audio d'entraînement valide. Vérifiez le jeu de données et le journal.", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "Les fichiers de sortie du prétraitement ne correspondent pas. L'extraction et l'entraînement ont été arrêtés.", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "Extraction des données démarrée : start_time=%.6f, parallélisme demandé=%s, limite réelle=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "Extraction des données terminée : end_time=%.6f, durée totale=%.3f secondes", - "新增一行": "Add row", - "无法停止": "Impossible à arrêter", - "是": "Oui", - "是否仅保存最新的ckpt文件以节省硬盘空间": "Enregistrer uniquement le dernier fichier '.ckpt' pour économiser de l'espace disque :", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "Enregistrer un petit modèle final dans le dossier 'weights' à chaque point de sauvegarde :", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Mettre en cache tous les ensembles d'entrainement dans la mémoire GPU. Mettre en cache de petits ensembles de données (moins de 10 minutes) peut accélérer l'entrainement, mais mettre en cache de grands ensembles de données consommera beaucoup de mémoire GPU et peut ne pas apporter beaucoup d'amélioration de vitesse :", - "显卡信息": "Informations sur la carte graphique (GPU)", - "未使用": "Non utilisé", - "未使用判别器预训练模型": "Modèle préentraîné du discriminateur non utilisé", - "未使用生成器预训练模型": "Modèle préentraîné du générateur non utilisé", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "Aucun GPU compatible détecté ; l'entraînement sur CPU peut être beaucoup plus long", - "未运行": "Non démarré", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "Ce logiciel est open source sous la licence MIT. L'auteur n'a aucun contrôle sur le logiciel. Les utilisateurs qui utilisent le logiciel et distribuent les sons exportés par le logiciel en sont entièrement responsables.
Si vous n'acceptez pas cette clause, vous ne pouvez pas utiliser ou faire référence à aucun code ni fichier contenu dans le package logiciel. Consultez le fichier Agreement-LICENSE.txt dans le répertoire racine pour plus de détails.", - "查看": "Voir", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "Afficher les informations sur le modèle (uniquement pour les petits fichiers de modèle extraits du dossier \"weights\")", - "检索特征占比": "Rapport de recherche de caractéristiques (contrôle l'intensité de l'accent, un rapport trop élevé provoque des artefacts) :", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "Informations du modèle: %s\nFréquence d'échantillonnage: %s\nGuidage de hauteur: %s\nVersion: %s", - "模型推理": "Inférence du modèle", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "Extraction du modèle (saisissez le chemin d'accès au modèle du grand fichier dans le dossier \"logs\"). Cette fonction est utile si vous souhaitez arrêter l'entrainement à mi-chemin et extraire et enregistrer manuellement un petit fichier de modèle, ou si vous souhaitez tester un modèle intermédiaire :", - "模型是否带音高指导": "Indique si le modèle dispose d'un guidage en hauteur :", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "Indique si le modèle dispose d'un système de guidage de la hauteur (obligatoire pour le chant, facultatif pour la parole) :", - "模型是否带音高指导,1是0否": "Le modèle dispose-t-il d'un guide de hauteur (1 : oui, 0 : non) ?", - "模型版本型号": "Version de l'architecture du modèle :", - "模型融合, 可用于测试音色融合": "Fusion de modèles, peut être utilisée pour tester la fusion de timbres", - "模型融合失败:两个模型的结构不一致": "Échec de la fusion : les architectures des deux modèles diffèrent", - "模型训练": "Entraînement du modèle", - "模型路径": "Le chemin vers le modèle :", - "正在保存最终检查点:%s": "Enregistrement du point de contrôle final: %s", - "正在保存检查点 %s_e%s:%s": "Enregistrement du point de contrôle %s_e%s: %s", - "正在加载RMVPE模型": "Chargement du modèle RMVPE", - "正在加载模型": "Chargement du modèle", - "正在启动": "Démarrage", - "正在收尾": "Finalisation", - "正在预热CUDA Graph": "Préchauffage de CUDA Graph", - "每张显卡的batch_size": "Taille du batch par GPU :", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "Aucun audio valide n'est disponible pour l'entraînement. Terminez d'abord le prétraitement et l'extraction.", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "Longueur de la transition", - "清理模型缓存": "Nettoyage du cache du modèle", - "版本": "Version", - "特征": "Caractéristiques", - "特征提取": "Extraction des caractéristiques", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "Chemin de l’index de caractéristiques (détecté après sélection du modèle ; modifiable)", - "状态": "État", - "独占 WASAPI 设备": "Périphérique WASAPI exclusif", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "Taux d'échantillonnage cible :", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "En attente", - "等待输入": "En attente d'une entrée", - "算法延迟(ms):": "Latence de l'algorithme (ms) :", - "索引": "Index", - "索引文件不存在,将不使用索引继续推理:%s": "Le fichier d'index n'existe pas ; l'inférence continuera sans index : %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "Index invalide : utilisez added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "Échec de la recherche par index", - "索引检索失败或未启用": "La recherche par index a échoué ou est désactivée", - "索引训练": "Entraînement de l'index", - "耗时": "Temps écoulé", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "Temps écoulé: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "Fusion", - "要改的模型信息": "Informations sur le modèle à modifier :", - "要置入的模型信息": "Informations sur le modèle à placer :", - "训练": "Entraîner", - "训练已完成,正在保存最终模型": "Entraînement terminé ; enregistrement du modèle final", - "训练文件列表写入完成": "Liste des fichiers d'entraînement enregistrée", - "训练模型": "Entraîner le modèle", - "训练特征索引": "Entraîner l'index des caractéristiques", - "训练设备规则选择的精度:%s": "Précision d'entraînement choisie selon les règles du périphérique: %s", - "训练轮次:{} [{:.0f}%]": "Époque d'entraînement : {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "Type de périphérique", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "Téléversez un fichier audio", - "请填写输出文件夹路径": "Saisissez le chemin du dossier de sortie", - "请指定说话人id": "Veuillez spécifier l'ID de l'orateur ou du chanteur :", - "请选择index文件": "Veuillez sélectionner le fichier d'index", - "请选择pth文件": "Veuillez sélectionner le fichier pth", - "请选择说话人id": "Sélectionner l'ID de l'orateur ou du chanteur :", - "转换": "Convertir", - "输入实验名": "Saisissez le nom de l'expérience :", - "输入实验名,例如:test": "Nom de l'expérience, par exemple : test", - "输入待处理音频文件夹路径": "Entrez le chemin du dossier audio à traiter :", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "Entrez le chemin du dossier audio à traiter (copiez-le depuis la barre d'adresse du gestionnaire de fichiers) :", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "Ajustez l'échelle de l'enveloppe de volume. Plus il est proche de 0, plus il imite le volume des voix originales. Cela peut aider à masquer les bruits et à rendre le volume plus naturel lorsqu'il est réglé relativement bas. Plus le volume est proche de 1, plus le volume sera fort et constant :", - "输入监听": "Écouter l'entrée", - "输入训练文件夹路径": "Indiquez le chemin d'accès au dossier d'entraînement :", - "输入设备": "Dispositif d'entrée", - "输入设备:%s:%s": "Périphérique d'entrée: %s:%s", - "输入降噪": "Réduction du bruit d'entrée", - "输出信息": "Informations sur la sortie", - "输出变声": "Conversion de sortie", - "输出设备": "Dispositif de sortie", - "输出设备:%s:%s": "Périphérique de sortie: %s:%s", - "输出降噪": "Réduction du bruit de sortie", - "输出音频(右下角三个点,点了可以下载)": "Exporter l'audio (cliquer sur les trois points dans le coin inférieur droit pour télécharger)", - "运行中": "En cours", - "进度": "Progression", - "选择.index文件": "Sélectionner le fichier .index", - "选择.pth文件": "Sélectionner le fichier .pth", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "Sélectionner le modèle", - "选择索引": "Sélectionner l'index", - "选择音高提取算法": "Sélectionnez l’algorithme d’extraction de la hauteur", - "采样率:": "Fréquence d'échantillonnage :", - "采样长度": "Longueur de l'échantillon", - "重复次数": "Repeat count", - "重载设备列表": "Recharger la liste des dispositifs", - "音调设置": "Réglages de la hauteur", - "音频设备": "Périphérique audio", - "音高全部为0,该音频无意义,跳过:%s": "Toutes les valeurs de hauteur sont nulles ; cet audio est inutilisable et sera ignoré: %s", - "音高算法": "Algorithme de hauteur", - "额外推理时长": "Temps d'inférence supplémentaire" -} diff --git a/i18n/locale/it_IT.json b/i18n/locale/it_IT.json deleted file mode 100644 index 5399940e228c0ab52f6e43fafb88d950c31c2b0d..0000000000000000000000000000000000000000 --- a/i18n/locale/it_IT.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s è in esecuzione; interromperlo prima di avviare un'altra attività", - "====> 轮次:{} {}": "====> Epoca: {} {}", - "A模型权重": "Peso (w) per il modello A:", - "A模型路径": "Percorso per il modello A:", - "B模型路径": "Percorso per il modello B:", - "CUDA Graph预热完成": "Riscaldamento di CUDA Graph completato", - "CUDA可用:%s": "CUDA disponibile: %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "Percorso della cartella di addestramento, ad esempio: E:\\Il mio set di addestramento", - "F0与HuBERT特征提取": "Estrazione F0 e caratteristiche HuBERT", - "F0提取": "Estrazione F0", - "F0提取没有生成有效结果,已停止训练": "Estrazione F0 senza risultati validi. Addestramento interrotto.", - "HuBERT特征": "Caratteristiche HuBERT", - "HuBERT特征提取没有生成有效结果,已停止训练": "Estrazione HuBERT senza risultati validi. Addestramento interrotto.", - "Index Rate": "Tasso di indice", - "SOLA偏移:%d": "Offset SOLA: %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Estrazione F0] Completato | Successo: %s | Ignorati: %s | Errore: %s", - "[F0提取] 待处理:%s": "[Estrazione F0] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[Estrazione F0] Nessun audio in attesa; tutti i file sono stati ignorati", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[Estrazione F0] Avanzamento: %s/%s | Successo: %s | Ignorati: %s | %s", - "[F0提取][失败] %s": "[Estrazione F0][Errore] %s", - "[F0提取][失败] %s\n%s": "[Estrazione F0][Errore] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Caratteristiche HuBERT] Completato | Successo: %s | Ignorati: %s | Errore: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[Caratteristiche HuBERT] Nessun audio in attesa; ignorati: %s", - "[HuBERT特征] 正在加载模型:%s": "[Caratteristiche HuBERT] Caricamento del modello: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[Caratteristiche HuBERT] Dispositivo: %s | Pending: %s | Ignorati: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[Caratteristiche HuBERT] Avanzamento: %s/%s | Successo: %s | Errore: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[Caratteristiche HuBERT][Errore] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[Caratteristiche HuBERT][Errore] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[Caratteristiche HuBERT][Errore] Modello not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[Suddivisione dati] Sottoattività completata | Successo: %s | Errore: %s", - "[数据切分] 完成": "[Suddivisione dati] Completato", - "[数据切分] 开始": "[Suddivisione dati] Avviato", - "[数据切分] 待处理:%s | 进程数:%s": "[Suddivisione dati] Pending: %s | Processi: %s", - "[数据切分] 进度:%s/%s | %s": "[Suddivisione dati] Avanzamento: %s/%s | %s", - "[数据切分][失败] %s": "[Suddivisione dati][Errore] %s", - "[数据切分][失败] %s\n%s": "[Suddivisione dati][Errore] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[Suddivisione dati][Ignorati] Segmento audio non valido o anomalo: %s_%s | Picco: %s", - "[索引训练] 写入进度:%s/%s": "[Addestramento indice] Avanzamento scrittura: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[Addestramento indice] Il collegamento esterno esiste già: %s", - "[索引训练] 已链接索引到外部目录:%s": "[Addestramento indice] Indice collegato alla cartella esterna: %s", - "[索引训练] 成功构建索引:%s": "[Addestramento indice] Indice creato correttamente: %s", - "[索引训练] 正在写入特征向量": "[Addestramento indice] Aggiunta dei vettori delle caratteristiche", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[Addestramento indice] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[Addestramento indice] Addestramento dell'indice", - "[索引训练] 特征形状:%s | IVF数量:%s": "[Addestramento indice] Forma caratteristiche: %s | Numero IVF: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[Addestramento indice][Errore] Impossibile collegare l'indice alla cartella esterna: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[Addestramento indice][Errore] Clustering non riuscito; continuazione con le caratteristiche originali\n%s", - "[索引训练][失败] 请先进行特征提取": "[Addestramento indice][Errore] Estrarre prima le caratteristiche", - "[索引训练][跳过] added索引已存在:%s": "[Addestramento indice][Saltato] L’indice added esiste già: %s", - "[索引训练][跳过] trained索引已存在:%s": "[Addestramento indice][Saltato] L’indice trained esiste già: %s", - "ckpt处理": "Elaborazione ckpt", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": "Il percorso del file index non può contenere caratteri cinesi", - "pth文件路径不可包含中文": "pth è un'app per il futuro", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "Configurazione GPU RMVPE separata da trattini; ad esempio 0-0-1 avvia due processi sulla GPU 0 e uno sulla GPU 1", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "Passaggio 1: compilare la configurazione sperimentale. ", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "Passaggio 2b: estrazione del tono e delle caratteristiche semantiche HuBERT", - "step3: 填写训练设置, 开始训练模型和索引": "Passaggio 3: compilare le impostazioni di addestramento e avviare l'addestramento del modello e dell'indice", - "……仅显示最近10条失败记录": "…Vengono mostrati solo gli ultimi 10 errori", - "……已省略前%s行,仅显示最新状态": "…Omesse le prime %s righe; viene mostrato solo lo stato più recente", - "一键训练": "Addestramento con un clic", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "Cartella di output principale", - "也可批量输入音频文件, 二选一, 优先读文件夹": "È anche possibile scegliere più file audio; la cartella ha la priorità", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "Elaborazione batch di voce, accompagnamento e riverbero con i modelli pymss/MSST.", - "人声伴奏分离&去混响": "Separazione voce/accompagnamento e rimozione del riverbero", - "仅支持pm和rmvpe音高提取算法": "Sono supportati solo i metodi di estrazione dell'intonazione pm e rmvpe", - "从训练检查点提取的模型": "Modellolo estratto da un checkpoint di addestramento", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "Inserisci gli indici GPU separati da '-', ad esempio 0-1-2 per utilizzare GPU 0, 1 e 2:", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "Attività", - "使用显卡:%s": "GPU in uso: %s", - "使用模型采样率": "Usa frequenza del modello", - "使用设备采样率": "Usa frequenza del dispositivo", - "保存名": "Salva nome:", - "保存的文件名, 默认空为和源文件同名": "Salva il nome del file (predefinito: uguale al file di origine):", - "保存的模型名不带后缀": "Nome del modello salvato (senza estensione):", - "保存频率save_every_epoch": "Frequenza di salvataggio (save_every_epoch):", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Proteggi le consonanti senza voce e i suoni del respiro per evitare artefatti come il tearing nella musica elettronica. ", - "修改": "Modificare", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Modifica le informazioni sul modello (supportato solo per i file di modello di piccole dimensioni estratti dalla cartella 'weights')", - "停止一键训练": "Interrompi addestramento con un clic", - "停止分离": "Interrompi separazione", - "停止处理数据": "Interrompi pre-elaborazione dei dati", - "停止特征提取": "Interrompi estrazione delle caratteristiche", - "停止训练模型": "Interrompi addestramento del modello", - "停止训练索引": "Interrompi addestramento dell’indice", - "停止音频转换": "Arresta la conversione audio", - "分离残余文件夹": "Cartella di output residuo", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "Aggiorna elenco voci", - "加载模型": "Carica modello", - "加载预训练底模D路径": "Carica il percorso D del modello base pre-addestrato:", - "加载预训练底模G路径": "Carica il percorso G del modello base pre-addestrato:", - "单次推理": "Inferenza singola", - "单说话人": "Single speaker", - "卸载音色省显存": "Scarica la voce per risparmiare memoria della GPU:", - "变调(整数, 半音数量, 升八度12降八度-12)": "Trasposizione (numero intero, numero di semitoni, alza di un'ottava: 12, abbassa di un'ottava: -12):", - "合成": "Sintesi", - "后处理重采样至最终采样率,0为不进行重采样": "Ricampiona l'audio di output in post-elaborazione alla frequenza di campionamento finale. ", - "否": "NO", - "响应阈值": "Soglia di risposta", - "响度因子": "fattore di sonorità", - "处理中": "Elaborazione", - "处理数据": "Processa dati", - "处理方式": "Modalità di elaborazione", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "Nota: l'addestramento multivoce potrebbe riprodurre ogni voce meno fedelmente rispetto all'addestramento separato di ciascun parlante!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "Errore", - "失败记录": "Registro errori", - "子进程执行失败,返回码:%s": "Il sottoprocesso non è riuscito, codice di uscita: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "Formato file di esportazione", - "已停止": "Interrotto", - "已加载判别器预训练模型:%s": "Modellolo preaddestrato del discriminatore caricato: %s", - "已加载生成器预训练模型:%s": "Modellolo preaddestrato del generatore caricato: %s", - "已启用索引检索": "Ricerca nell'indice attivata", - "已完成": "Completato", - "已完成阶段": "Fasi completate", - "已恢复判别器检查点": "Checkpoint del discriminatore ripristinato", - "已成功": "Completato", - "常见问题解答": "FAQ (Domande frequenti)", - "常规设置": "Impostazioni generali", - "底层模型": "Modello sottostante", - "开始音频转换": "Avvia la conversione audio", - "当前": "Attuale", - "当前设备:%s | 推理精度:%s": "Dispositivo corrente: %s | Precisione di inferenza: %s", - "当前阶段": "Fase attuale", - "很遗憾您这没有能用的显卡来支持您训练": "Sfortunatamente, non è disponibile alcuna GPU compatibile per supportare l'addestramento.", - "性别因子/声线粗细": "Fattore di genere / spessore della voce", - "性能设置": "Impostazioni delle prestazioni", - "总训练轮数total_epoch": "Epoch totali di addestramento (total_epoch):", - "成功": "Successo", - "执行命令": "Comando", - "批量推理": "Inferenza batch", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Conversione massiva. Inserisci il percorso della cartella che contiene i file da convertire o carica più file audio. I file convertiti finiranno nella cartella specificata. (default: opt) ", - "拖拽或点击上传待处理音频": "Trascina qui o fai clic per caricare l’audio da elaborare", - "指定输出文件夹": "Specifica la cartella di output:", - "推理时间(ms):": "Tempo di inferenza (ms):", - "推理耗时:%.2f秒": "Tempo di inferenza: %.2f seconds", - "推理音色": "Voce di inferenza:", - "提交训练集清单": "Submit dataset manifest", - "提取": "Estrai", - "提取音高和处理数据使用的CPU进程数": "Numero di processi CPU utilizzati per l'estrazione del tono e l'elaborazione dei dati:", - "数据切分": "Suddivisione dati", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "Il pre-processing non ha generato audio a 16 kHz. Estrazione e addestramento sono stati interrotti.", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "Il pre-processing non ha generato audio di addestramento valido. Controlla il dataset e il registro.", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "I file prodotti dal pre-processing non corrispondono. Estrazione e addestramento sono stati interrotti.", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "Estrazione dati avviata: start_time=%.6f, concorrenza richiesta=%s, limite effettivo=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "Estrazione dati completata: end_time=%.6f, tempo totale=%.3f secondi", - "新增一行": "Add row", - "无法停止": "Impossibile interrompere", - "是": "SÌ", - "是否仅保存最新的ckpt文件以节省硬盘空间": "Salva solo l'ultimo file '.ckpt' per risparmiare spazio su disco:", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "Salva un piccolo modello finale nella cartella \"weights\" in ogni punto di salvataggio:", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Memorizza nella cache tutti i set di addestramento nella memoria della GPU. ", - "显卡信息": "Informazioni GPU", - "未使用": "Non usato", - "未使用判别器预训练模型": "Modello preaddestrato del discriminatore non usato", - "未使用生成器预训练模型": "Modello preaddestrato del generatore non usato", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "Nessuna GPU supportata rilevata; l'addestramento sulla CPU può richiedere molto più tempo", - "未运行": "Non avviato", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "Questo software è open source con licenza MIT.
Se non si accetta questa clausola, non è possibile utilizzare o fare riferimento a codici e file all'interno del pacchetto software. Contratto-LICENZA.txt per dettagli.", - "查看": "Visualizzazione", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "Visualizza le informazioni sul modello (supportato solo per file di modello piccoli estratti dalla cartella 'weights')", - "检索特征占比": "Rapporto funzionalità di ricerca (controlla la forza dell'accento, troppo alto ha artefatti):", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "Informazioni modello: %s\nFrequenza di campionamento: %s\nGuida intonazione: %s\nVersione: %s", - "模型推理": "Inferenza del modello", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "Estrazione del modello (inserire il percorso del modello di file di grandi dimensioni nella cartella \"logs\"). ", - "模型是否带音高指导": "Se il modello ha una guida del tono:", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "Se il modello ha una guida del tono (necessario per il canto, facoltativo per il parlato):", - "模型是否带音高指导,1是0否": "Se il modello ha una guida del tono (1: sì, 0: no):", - "模型版本型号": "Versione dell'architettura del modello:", - "模型融合, 可用于测试音色融合": "Model fusion, può essere utilizzato per testare la fusione timbrica", - "模型融合失败:两个模型的结构不一致": "Unione dei modelli non riuscita: le architetture non corrispondono", - "模型训练": "Addestramento modello", - "模型路径": "Percorso al modello:", - "正在保存最终检查点:%s": "Salvataggio del checkpoint finale: %s", - "正在保存检查点 %s_e%s:%s": "Salvataggio del checkpoint %s_e%s: %s", - "正在加载RMVPE模型": "Caricamento del modello RMVPE", - "正在加载模型": "Caricamento del modello", - "正在启动": "Avvio in corso", - "正在收尾": "Finalizzazione", - "正在预热CUDA Graph": "Riscaldamento di CUDA Graph", - "每张显卡的batch_size": "Dimensione batch per GPU:", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "Nessun audio valido per l’addestramento. Completa prima pre-processing ed estrazione delle caratteristiche.", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "Lunghezza dissolvenza", - "清理模型缓存": "Pulizia della cache del modello", - "版本": "Versione", - "特征": "Caratteristiche", - "特征提取": "Estrazione delle caratteristiche", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "Percorso indice caratteristiche (rilevato dopo la scelta del modello; modificabile)", - "状态": "Stato", - "独占 WASAPI 设备": "Dispositivo WASAPI esclusivo", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "Frequenza di campionamento target:", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "In attesa", - "等待输入": "In attesa dell'input", - "算法延迟(ms):": "Latenza algoritmo (ms):", - "索引": "Indice", - "索引文件不存在,将不使用索引继续推理:%s": "Il file indice non esiste; l'inferenza continuerà senza indice: %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "Indice non valido: usare added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "Ricerca nell'indice non riuscita", - "索引检索失败或未启用": "Ricerca nell'indice non riuscita o disattivata", - "索引训练": "Addestramento indice", - "耗时": "Tempo trascorso", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "Tempo trascorso: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "Fusione", - "要改的模型信息": "Informazioni sul modello da modificare:", - "要置入的模型信息": "Informazioni sul modello da posizionare:", - "训练": "Addestramento", - "训练已完成,正在保存最终模型": "Addestramento completato; salvataggio del modello finale", - "训练文件列表写入完成": "Elenco dei file di addestramento salvato", - "训练模型": "Addestra modello", - "训练特征索引": "Addestra indice delle caratteristiche", - "训练设备规则选择的精度:%s": "Precisione di addestramento scelta dalle regole del dispositivo: %s", - "训练轮次:{} [{:.0f}%]": "Epoca di addestramento: {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "Tipo di dispositivo", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "Caricare un file audio", - "请填写输出文件夹路径": "Inserire il percorso della cartella di output", - "请指定说话人id": "Si prega di specificare l'ID del locutore/cantante:", - "请选择index文件": "Selezionare un file .index", - "请选择pth文件": "Selezionare un file .pth", - "请选择说话人id": "Seleziona ID locutore/cantante:", - "转换": "Convertire", - "输入实验名": "Inserisci il nome dell'esperimento:", - "输入实验名,例如:test": "Nome dell'esperimento, ad esempio: test", - "输入待处理音频文件夹路径": "Immettere il percorso della cartella audio da elaborare:", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "Immettere il percorso della cartella audio da elaborare (copiarlo dalla barra degli indirizzi del file manager):", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "Regola il ridimensionamento dell'inviluppo del volume. ", - "输入监听": "Monitor ingresso", - "输入训练文件夹路径": "Inserisci il percorso della cartella di addestramento:", - "输入设备": "Dispositivo di input", - "输入设备:%s:%s": "Dispositivo di ingresso: %s:%s", - "输入降噪": "Riduzione del rumore in ingresso", - "输出信息": "Informazioni sull'uscita", - "输出变声": "Conversione uscita", - "输出设备": "Dispositivo di uscita", - "输出设备:%s:%s": "Dispositivo di uscita: %s:%s", - "输出降噪": "Riduzione del rumore in uscita", - "输出音频(右下角三个点,点了可以下载)": "Esporta audio (clicca sui tre puntini in basso a destra per scaricarlo)", - "运行中": "In esecuzione", - "进度": "Avanzamento", - "选择.index文件": "Seleziona il file .index", - "选择.pth文件": "Seleziona il file .pth", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "Seleziona modello", - "选择索引": "Seleziona indice", - "选择音高提取算法": "Seleziona l’algoritmo di estrazione dell’intonazione", - "采样率:": "Frequenza di campionamento:", - "采样长度": "Lunghezza del campione", - "重复次数": "Repeat count", - "重载设备列表": "Ricaricare l'elenco dei dispositivi", - "音调设置": "Impostazioni del tono", - "音频设备": "Dispositivo audio", - "音高全部为0,该音频无意义,跳过:%s": "Tutti i valori di intonazione sono zero; questo audio è inutilizzabile e verrà ignorato: %s", - "音高算法": "Algoritmo di intonazione", - "额外推理时长": "Tempo di inferenza extra" -} diff --git a/i18n/locale/ja_JP.json b/i18n/locale/ja_JP.json deleted file mode 100644 index 7e787628cc535aa4c4091886a9fa557b7b1da090..0000000000000000000000000000000000000000 --- a/i18n/locale/ja_JP.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%sを実行中です。先に停止してください", - "====> 轮次:{} {}": "====> エポック: {} {}", - "A模型权重": "Aモデルの重み", - "A模型路径": "Aモデルのパス", - "B模型路径": "Bモデルのパス", - "CUDA Graph预热完成": "CUDA Graphのウォームアップが完了しました", - "CUDA可用:%s": "CUDA利用可能: %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "トレーニングフォルダーのパス(例:E:\\私のトレーニングデータ)", - "F0与HuBERT特征提取": "F0とHuBERT特徴量の抽出", - "F0提取": "F0抽出", - "F0提取没有生成有效结果,已停止训练": "F0抽出で有効な結果が生成されなかったため、学習を停止しました。", - "HuBERT特征": "HuBERT特徴量", - "HuBERT特征提取没有生成有效结果,已停止训练": "HuBERT特徴抽出で有効な結果が生成されなかったため、学習を停止しました。", - "Index Rate": "Index Rate", - "SOLA偏移:%d": "SOLAオフセット: %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[F0抽出] 完了 | 成功: %s | スキップ: %s | 失敗: %s", - "[F0提取] 待处理:%s": "[F0抽出] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[F0抽出] 処理対象の音声はなく、すべてスキップ済みです", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[F0抽出] 進捗: %s/%s | 成功: %s | スキップ: %s | %s", - "[F0提取][失败] %s": "[F0抽出][失敗] %s", - "[F0提取][失败] %s\n%s": "[F0抽出][失敗] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[HuBERT特徴量] 完了 | 成功: %s | スキップ: %s | 失敗: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[HuBERT特徴量] 処理対象の音声なし、スキップ済み: %s", - "[HuBERT特征] 正在加载模型:%s": "[HuBERT特徴量] モデルを読み込み中: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[HuBERT特徴量] デバイス: %s | Pending: %s | スキップ: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[HuBERT特徴量] 進捗: %s/%s | 成功: %s | 失敗: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[HuBERT特徴量][失敗] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[HuBERT特徴量][失敗] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[HuBERT特徴量][失敗] モデル not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[データ分割] サブタスク完了 | 成功: %s | 失敗: %s", - "[数据切分] 完成": "[データ分割] 完了", - "[数据切分] 开始": "[データ分割] 開始", - "[数据切分] 待处理:%s | 进程数:%s": "[データ分割] Pending: %s | プロセス数: %s", - "[数据切分] 进度:%s/%s | %s": "[データ分割] 進捗: %s/%s | %s", - "[数据切分][失败] %s": "[データ分割][失敗] %s", - "[数据切分][失败] %s\n%s": "[データ分割][失敗] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[データ分割][スキップ] 無効または異常な音声区間: %s_%s | ピーク: %s", - "[索引训练] 写入进度:%s/%s": "[インデックス学習] 書き込み進捗: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[インデックス学習] 外部インデックスリンクは既に存在します:%s", - "[索引训练] 已链接索引到外部目录:%s": "[インデックス学習] インデックスを外部フォルダーへリンクしました: %s", - "[索引训练] 成功构建索引:%s": "[インデックス学習] インデックスを作成しました: %s", - "[索引训练] 正在写入特征向量": "[インデックス学習] 特徴ベクトルを追加中", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[インデックス学習] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[インデックス学習] インデックスを学習中", - "[索引训练] 特征形状:%s | IVF数量:%s": "[インデックス学習] 特徴量形状: %s | IVF数: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[インデックス学習][失敗] インデックスを外部フォルダーへリンクできませんでした: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[インデックス学習][失敗] クラスタリングに失敗したため、元の特徴量で続行します\n%s", - "[索引训练][失败] 请先进行特征提取": "[インデックス学習][失敗] 先に特徴抽出を実行してください", - "[索引训练][跳过] added索引已存在:%s": "[インデックス学習][スキップ] addedインデックスは既に存在します:%s", - "[索引训练][跳过] trained索引已存在:%s": "[インデックス学習][スキップ] trainedインデックスは既に存在します:%s", - "ckpt处理": "ckptファイルの処理", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": "indexファイルのパスに漢字を含んではいけません", - "pth文件路径不可包含中文": "pthファイルのパスに漢字を含んではいけません", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "rmvpeカード番号設定:異なるプロセスに使用するカード番号を入力する。例えば、0-0-1でカード0に2つのプロセス、カード1に1つのプロセスを実行する。", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "ステップ1:実験設定を入力します。実験データはlogsに保存され、各実験にはフォルダーがあります。実験名のパスを手動で入力する必要があり、実験設定、ログ、トレーニングされたモデルファイルが含まれます。", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "ステップ2b: ピッチとHuBERTセマンティック特徴量の抽出", - "step3: 填写训练设置, 开始训练模型和索引": "ステップ3: トレーニング設定を入力して、モデルとインデックスのトレーニングを開始します", - "……仅显示最近10条失败记录": "…直近10件の失敗のみ表示しています", - "……已省略前%s行,仅显示最新状态": "…先頭%s行を省略し、最新状態のみ表示しています", - "一键训练": "ワンクリックトレーニング", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "主要出力フォルダー", - "也可批量输入音频文件, 二选一, 优先读文件夹": "複数のオーディオファイルをインポートすることもできます。フォルダパスが存在する場合、この入力は無視されます。", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "pymss/MSSTモデルを使用して、ボーカル、伴奏、残響を一括処理します。", - "人声伴奏分离&去混响": "ボーカル・伴奏分離と残響除去", - "仅支持pm和rmvpe音高提取算法": "ピッチ抽出方式はpmとrmvpeのみ対応しています", - "从训练检查点提取的模型": "学習チェックポイントから抽出したモデル", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "ハイフンで区切って使用するGPUの番号を入力します。例えば0-1-2はGPU0、GPU1、GPU2を使用します", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "タスク", - "使用显卡:%s": "使用GPU: %s", - "使用模型采样率": "モデルのサンプルレートを使用", - "使用设备采样率": "デバイスのサンプルレートを使用", - "保存名": "保存ファイル名", - "保存的文件名, 默认空为和源文件同名": "保存するファイル名、デフォルトでは空欄で元のファイル名と同じ名前になります", - "保存的模型名不带后缀": "拡張子のない保存するモデル名", - "保存频率save_every_epoch": "エポックごとの保存頻度", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "明確な子音と呼吸音を保護し、電子音の途切れやその他のアーティファクトを防止します。0.5でオフになります。下げると保護が強化されますが、indexの効果が低下する可能性があります。", - "修改": "変更", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "モデル情報の修正(weightsフォルダから抽出された小さなモデルファイルのみ対応)", - "停止一键训练": "ワンクリック学習を停止", - "停止分离": "分離を停止", - "停止处理数据": "データ前処理を停止", - "停止特征提取": "特徴抽出を停止", - "停止训练模型": "モデル学習を停止", - "停止训练索引": "インデックス学習を停止", - "停止音频转换": "音声変換を停止", - "分离残余文件夹": "残余出力フォルダー", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "音色リストを更新", - "加载模型": "モデルをロード", - "加载预训练底模D路径": "事前学習済みのDモデルのパス", - "加载预训练底模G路径": "事前学習済みのGモデルのパス", - "单次推理": "単発推論", - "单说话人": "Single speaker", - "卸载音色省显存": "音源を削除してメモリを節約", - "变调(整数, 半音数量, 升八度12降八度-12)": "ピッチ変更(整数、半音数、上下オクターブ12-12)", - "合成": "合成", - "后处理重采样至最终采样率,0为不进行重采样": "最終的なサンプリングレートへのポストプロセッシングのリサンプリング リサンプリングしない場合は0", - "否": "いいえ", - "响应阈值": "反応閾値", - "响度因子": "ラウドネス係数", - "处理中": "処理中", - "处理数据": "データ処理", - "处理方式": "処理方法", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "注意:マルチスピーカー学習は、話者ごとに個別学習する場合よりも音色の再現度が低くなることがあります!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "失敗", - "失败记录": "失敗記録", - "子进程执行失败,返回码:%s": "子プロセスが終了コード付きで失敗しました: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "エクスポート形式", - "已停止": "停止済み", - "已加载判别器预训练模型:%s": "識別器の事前学習モデルを読み込みました: %s", - "已加载生成器预训练模型:%s": "生成器の事前学習モデルを読み込みました: %s", - "已启用索引检索": "インデックス検索を有効化しました", - "已完成": "完了", - "已完成阶段": "完了した段階", - "已恢复判别器检查点": "識別器チェックポイントを復元しました", - "已成功": "成功", - "常见问题解答": "よくある質問", - "常规设置": "一般設定", - "底层模型": "基盤モデル", - "开始音频转换": "音声変換を開始", - "当前": "現在", - "当前设备:%s | 推理精度:%s": "現在のデバイス:%s | 推論精度:%s", - "当前阶段": "現在の段階", - "很遗憾您这没有能用的显卡来支持您训练": "トレーニングに対応したGPUが動作しないのは残念です。", - "性别因子/声线粗细": "性別係数/声質の太さ", - "性能设置": "パフォーマンス設定", - "总训练轮数total_epoch": "総エポック数", - "成功": "成功", - "执行命令": "実行コマンド", - "批量推理": "一括推論", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "一括変換、変換する音声フォルダを入力、または複数の音声ファイルをアップロードし、指定したフォルダ(デフォルトのopt)に変換した音声を出力します。", - "拖拽或点击上传待处理音频": "処理する音声をドラッグ&ドロップするか、クリックしてアップロード", - "指定输出文件夹": "出力フォルダを指定してください", - "推理时间(ms):": "推論時間(ms):", - "推理耗时:%.2f秒": "推論時間: %.2f seconds", - "推理音色": "音源推論", - "提交训练集清单": "Submit dataset manifest", - "提取": "抽出", - "提取音高和处理数据使用的CPU进程数": "ピッチの抽出やデータ処理に使用するCPUスレッド数", - "数据切分": "データ分割", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "データ前処理で16 kHz音声が生成されなかったため、特徴抽出と学習を停止しました。", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "データ前処理で有効な学習音声が生成されませんでした。データセットと前処理ログを確認してください。", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "データ前処理の出力ファイルが一致しないため、特徴抽出と学習を停止しました。", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "データ抽出開始:start_time=%.6f、要求並列数=%s、実並列上限=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "データ抽出完了:end_time=%.6f、合計所要時間=%.3f秒", - "新增一行": "Add row", - "无法停止": "停止できません", - "是": "はい", - "是否仅保存最新的ckpt文件以节省硬盘空间": "ハードディスク容量を節約するため、最新のckptファイルのみを保存しますか?", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "各保存時点の小モデルを全部weightsフォルダに保存するかどうか", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "すべてのトレーニングデータをメモリにキャッシュするかどうか。10分以下の小さなデータはキャッシュしてトレーニングを高速化できますが、大きなデータをキャッシュするとメモリが破裂し、あまり速度が上がりません。", - "显卡信息": "GPU情報", - "未使用": "未使用", - "未使用判别器预训练模型": "識別器の事前学習モデルは未使用です", - "未使用生成器预训练模型": "生成器の事前学習モデルは未使用です", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "対応GPUが検出されませんでした。CPUでの学習には時間がかかる場合があります", - "未运行": "未実行", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "本ソフトウェアはMITライセンスに基づくオープンソースであり、製作者は本ソフトウェアに対していかなる責任を持ちません。本ソフトウェアの利用者および本ソフトウェアから派生した音源(成果物)を配布する者は、本ソフトウェアに対して自身で責任を負うものとします。
この条項に同意しない場合、パッケージ内のコードやファイルを使用や参照を禁じます。詳しくはLICENSEをご覧ください。", - "查看": "表示", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "モデル情報を表示する(小さいモデルファイルはweightsフォルダーからのみサポートされています)", - "检索特征占比": "検索特徴率", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "モデル情報: %s\nサンプルレート: %s\nピッチガイド: %s\nバージョン: %s", - "模型推理": "モデル推論", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "モデル抽出(ログフォルダー内の大きなファイルのモデルパスを入力)、モデルを半分までトレーニングし、自動的に小さいファイルモデルを保存しなかったり、中間モデルをテストしたい場合に適用されます。", - "模型是否带音高指导": "モデルに音高ガイドを付けるかどうか", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "モデルに音高ガイドがあるかどうか(歌唱には必要ですが、音声には必要ありません)", - "模型是否带音高指导,1是0否": "モデルに音高ガイドを付けるかどうか、1は付ける、0は付けない", - "模型版本型号": "モデルのバージョン", - "模型融合, 可用于测试音色融合": "モデルのマージ、音源のマージテストに使用できます", - "模型融合失败:两个模型的结构不一致": "モデルの構造が一致しないため、結合に失敗しました", - "模型训练": "モデル学習", - "模型路径": "モデルパス", - "正在保存最终检查点:%s": "最終チェックポイントを保存中: %s", - "正在保存检查点 %s_e%s:%s": "チェックポイントを保存中 %s_e%s: %s", - "正在加载RMVPE模型": "RMVPEモデルを読み込み中", - "正在加载模型": "モデルを読み込み中", - "正在启动": "起動中", - "正在收尾": "終了処理中", - "正在预热CUDA Graph": "CUDA Graphをウォームアップしています", - "每张显卡的batch_size": "GPUごとのバッチサイズ", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "学習に使用できる有効な音声がありません。先にデータ前処理と特徴抽出を完了してください。", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "フェードイン/フェードアウト長", - "清理模型缓存": "モデルキャッシュを消去中", - "版本": "バージョン", - "特征": "特徴量", - "特征提取": "特徴抽出", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "特徴インデックスのパス(モデル選択後に自動照合、手動編集可)", - "状态": "状態", - "独占 WASAPI 设备": "WASAPI排他デバイス", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "目標サンプリングレート", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "待機中", - "等待输入": "入力待ち", - "算法延迟(ms):": "アルゴリズム遅延(ms):", - "索引": "インデックス", - "索引文件不存在,将不使用索引继续推理:%s": "インデックスファイルが存在しないため、インデックスなしで推論を続行します: %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "無効なインデックスです。使用してください: added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "インデックス検索に失敗しました", - "索引检索失败或未启用": "インデックス検索に失敗したか無効です", - "索引训练": "インデックス学習", - "耗时": "所要時間", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "所要時間: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "マージ", - "要改的模型信息": "変更するモデル情報", - "要置入的模型信息": "挿入するモデル情報", - "训练": "トレーニング", - "训练已完成,正在保存最终模型": "学習が完了しました。最終モデルを保存しています", - "训练文件列表写入完成": "学習ファイル一覧を書き込みました", - "训练模型": "モデルのトレーニング", - "训练特征索引": "特徴インデックスのトレーニング", - "训练设备规则选择的精度:%s": "デバイス規則で選択された学習精度: %s", - "训练轮次:{} [{:.0f}%]": "学習エポック: {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "デバイス種別", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "音声ファイルをアップロードしてください", - "请填写输出文件夹路径": "出力フォルダーのパスを入力してください", - "请指定说话人id": "話者IDを指定してください", - "请选择index文件": "indexファイルを選択してください", - "请选择pth文件": "pthファイルを選択してください", - "请选择说话人id": "話者IDを選択してください", - "转换": "変換", - "输入实验名": "モデル名", - "输入实验名,例如:test": "実験名(例:test)", - "输入待处理音频文件夹路径": "処理するオーディオファイルのフォルダパスを入力してください", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "処理対象音声フォルダーのパスを入力してください(エクスプローラーのアドレスバーからコピーしてください)", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "入力ソースの音量エンベロープと出力音量エンベロープの融合率 1に近づくほど、出力音量エンベロープの割合が高くなる", - "输入监听": "入力モニター", - "输入训练文件夹路径": "トレーニング用フォルダのパスを入力してください", - "输入设备": "入力デバイス", - "输入设备:%s:%s": "入力デバイス: %s:%s", - "输入降噪": "入力ノイズの低減", - "输出信息": "出力情報", - "输出变声": "出力変声", - "输出设备": "出力デバイス", - "输出设备:%s:%s": "出力デバイス: %s:%s", - "输出降噪": "出力ノイズの低減", - "输出音频(右下角三个点,点了可以下载)": "出力音声(右下の三点をクリックしてダウンロードできます)", - "运行中": "実行中", - "进度": "進捗", - "选择.index文件": ".indexファイルを選択", - "选择.pth文件": ".pthファイルを選択", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "モデルを選択", - "选择索引": "インデックスを選択", - "选择音高提取算法": "ピッチ抽出アルゴリズムを選択", - "采样率:": "サンプルレート:", - "采样长度": "サンプル長", - "重复次数": "Repeat count", - "重载设备列表": "デバイスリストをリロードする", - "音调设置": "音程設定", - "音频设备": "オーディオデバイス", - "音高全部为0,该音频无意义,跳过:%s": "ピッチがすべて0のため、この音声は無効としてスキップします: %s", - "音高算法": "ピッチ方式", - "额外推理时长": "追加推論時間" -} diff --git a/i18n/locale/ko_KR.json b/i18n/locale/ko_KR.json deleted file mode 100644 index 98fd51e1d1838c2c00b99302cfb339c02bd5207a..0000000000000000000000000000000000000000 --- a/i18n/locale/ko_KR.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s이(가) 실행 중입니다. 먼저 중지하세요", - "====> 轮次:{} {}": "====> 에포크: {} {}", - "A模型权重": "A 모델 가중치", - "A模型路径": "A 모델 경로", - "B模型路径": "B 모델 경로", - "CUDA Graph预热完成": "CUDA Graph 워밍업 완료", - "CUDA可用:%s": "CUDA 사용 가능: %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "훈련 폴더 경로(예: E:\\내 훈련 데이터)", - "F0与HuBERT特征提取": "F0 및 HuBERT 특징 추출", - "F0提取": "F0 추출", - "F0提取没有生成有效结果,已停止训练": "F0 추출에서 유효한 결과가 생성되지 않아 학습을 중지했습니다.", - "HuBERT特征": "HuBERT 특징", - "HuBERT特征提取没有生成有效结果,已停止训练": "HuBERT 특징 추출에서 유효한 결과가 생성되지 않아 학습을 중지했습니다.", - "Index Rate": "인덱스 비율", - "SOLA偏移:%d": "SOLA 오프셋: %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[F0 추출] 완료 | 성공: %s | 건너뜀: %s | 실패: %s", - "[F0提取] 待处理:%s": "[F0 추출] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[F0 추출] 처리할 오디오가 없으며 모든 파일을 건너뛰었습니다", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[F0 추출] 진행률: %s/%s | 성공: %s | 건너뜀: %s | %s", - "[F0提取][失败] %s": "[F0 추출][실패] %s", - "[F0提取][失败] %s\n%s": "[F0 추출][실패] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[HuBERT 특징] 완료 | 성공: %s | 건너뜀: %s | 실패: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[HuBERT 특징] 처리할 오디오 없음, 건너뜀: %s", - "[HuBERT特征] 正在加载模型:%s": "[HuBERT 특징] 모델 불러오는 중: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[HuBERT 특징] 장치: %s | Pending: %s | 건너뜀: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[HuBERT 특징] 진행률: %s/%s | 성공: %s | 실패: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[HuBERT 특징][실패] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[HuBERT 특징][실패] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[HuBERT 특징][실패] 모델 not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[데이터 분할] 하위 작업 완료 | 성공: %s | 실패: %s", - "[数据切分] 完成": "[데이터 분할] 완료", - "[数据切分] 开始": "[데이터 분할] 시작", - "[数据切分] 待处理:%s | 进程数:%s": "[데이터 분할] Pending: %s | 프로세스 수: %s", - "[数据切分] 进度:%s/%s | %s": "[데이터 분할] 진행률: %s/%s | %s", - "[数据切分][失败] %s": "[데이터 분할][실패] %s", - "[数据切分][失败] %s\n%s": "[데이터 분할][실패] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[데이터 분할][건너뜀] 잘못되었거나 비정상적인 오디오 구간: %s_%s | 피크: %s", - "[索引训练] 写入进度:%s/%s": "[인덱스 학습] 쓰기 진행률: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[인덱스 학습] 외부 인덱스 링크가 이미 있습니다: %s", - "[索引训练] 已链接索引到外部目录:%s": "[인덱스 학습] 인덱스를 외부 폴더에 연결했습니다: %s", - "[索引训练] 成功构建索引:%s": "[인덱스 학습] 인덱스를 성공적으로 생성했습니다: %s", - "[索引训练] 正在写入特征向量": "[인덱스 학습] 특징 벡터 추가 중", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[인덱스 학습] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[인덱스 학습] 인덱스 학습 중", - "[索引训练] 特征形状:%s | IVF数量:%s": "[인덱스 학습] 특징 형태: %s | IVF 수: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[인덱스 학습][실패] 인덱스를 외부 폴더에 연결하지 못했습니다: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[인덱스 학습][실패] 클러스터링에 실패하여 원본 특징으로 계속합니다\n%s", - "[索引训练][失败] 请先进行特征提取": "[인덱스 학습][실패] 먼저 특징을 추출하세요", - "[索引训练][跳过] added索引已存在:%s": "[인덱스 학습][건너뜀] added 인덱스가 이미 있습니다: %s", - "[索引训练][跳过] trained索引已存在:%s": "[인덱스 학습][건너뜀] trained 인덱스가 이미 있습니다: %s", - "ckpt处理": "ckpt 처리", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": "index 파일 경로는 중국어를 포함할 수 없음", - "pth文件路径不可包含中文": "pth 파일 경로는 중국어를 포함할 수 없음", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "rmvpe 카드 번호 설정: -로 구분된 입력 사용 카드 번호, 예: 0-0-1은 카드 0에서 2개 프로세스, 카드 1에서 1개 프로세스 실행", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "step1: 실험 구성 작성. 실험 데이터는 logs에 저장, 각 실험은 하나의 폴더, 수동으로 실험 이름 경로 입력 필요, 실험 구성, 로그, 훈련된 모델 파일 포함.", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "2단계 2b: 피치 및 HuBERT 의미 특징 추출", - "step3: 填写训练设置, 开始训练模型和索引": "step3: 훈련 설정 작성, 모델 및 인덱스 훈련 시작", - "……仅显示最近10条失败记录": "…최근 실패 10개만 표시합니다", - "……已省略前%s行,仅显示最新状态": "…앞의 %s줄을 생략하고 최신 상태만 표시합니다", - "一键训练": "원클릭 훈련", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "주 결과 폴더", - "也可批量输入音频文件, 二选一, 优先读文件夹": "여러 오디오 파일을 일괄 입력할 수도 있음, 둘 중 하나 선택, 폴더 우선 읽기", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "pymss/MSST 모델로 보컬, 반주 및 잔향을 일괄 처리합니다.", - "人声伴奏分离&去混响": "보컬/반주 분리 및 잔향 제거", - "仅支持pm和rmvpe音高提取算法": "피치 추출 방식은 pm과 rmvpe만 지원합니다", - "从训练检查点提取的模型": "학습 체크포인트에서 추출한 모델", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "-로 구분하여 입력하는 카드 번호, 예: 0-1-2는 카드 0, 카드 1, 카드 2 사용", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "작업", - "使用显卡:%s": "사용 GPU: %s", - "使用模型采样率": "모델 샘플링 레이트 사용", - "使用设备采样率": "장치 샘플링 레이트 사용", - "保存名": "저장 이름", - "保存的文件名, 默认空为和源文件同名": "저장될 파일명, 기본적으로 빈 공간은 원본 파일과 동일한 이름으로", - "保存的模型名不带后缀": "저장된 모델명은 접미사 없음", - "保存频率save_every_epoch": "저장 빈도 save_every_epoch", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "청자음과 호흡 소리를 보호, 전자음 찢김 등의 아티팩트 방지, 0.5까지 올려서 비활성화, 낮추면 보호 강도 증가하지만 인덱스 효과 감소 가능성 있음", - "修改": "수정", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "모델 정보 수정(오직 weights 폴더 아래에서 추출된 작은 모델 파일만 지원)", - "停止一键训练": "원클릭 학습 중지", - "停止分离": "분리 중지", - "停止处理数据": "데이터 전처리 중지", - "停止特征提取": "특징 추출 중지", - "停止训练模型": "모델 학습 중지", - "停止训练索引": "인덱스 학습 중지", - "停止音频转换": "오디오 변환 중지", - "分离残余文件夹": "잔여 결과 폴더", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "음색 목록 새로고침", - "加载模型": "모델 로드", - "加载预训练底模D路径": "미리 훈련된 베이스 모델 D 경로 로드", - "加载预训练底模G路径": "미리 훈련된 베이스 모델 G 경로 로드", - "单次推理": "단일 추론", - "单说话人": "Single speaker", - "卸载音色省显存": "음색 언로드로 디스플레이 메모리 절약", - "变调(整数, 半音数量, 升八度12降八度-12)": "키 변경(정수, 반음 수, 옥타브 상승 12, 옥타브 하강 -12)", - "合成": "합성", - "后处理重采样至最终采样率,0为不进行重采样": "후처리 재샘플링을 최종 샘플링 레이트로, 0은 재샘플링하지 않음", - "否": "아니오", - "响应阈值": "응답 임계값", - "响度因子": "음량 인자", - "处理中": "처리 중", - "处理数据": "데이터 처리", - "处理方式": "처리 방식", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "주의: 다중 화자 학습은 화자별로 따로 학습할 때보다 음색 재현도가 낮을 수 있습니다!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "실패", - "失败记录": "실패 기록", - "子进程执行失败,返回码:%s": "하위 프로세스가 종료 코드와 함께 실패했습니다: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "내보낼 파일 형식", - "已停止": "중지됨", - "已加载判别器预训练模型:%s": "판별기 사전 학습 모델을 불러왔습니다: %s", - "已加载生成器预训练模型:%s": "생성기 사전 학습 모델을 불러왔습니다: %s", - "已启用索引检索": "인덱스 검색 활성화됨", - "已完成": "완료", - "已完成阶段": "완료된 단계", - "已恢复判别器检查点": "판별기 체크포인트를 복원했습니다", - "已成功": "성공", - "常见问题解答": "자주 묻는 질문", - "常规设置": "일반 설정", - "底层模型": "기반 모델", - "开始音频转换": "오디오 변환 시작", - "当前": "현재", - "当前设备:%s | 推理精度:%s": "현재 장치: %s | 추론 정밀도: %s", - "当前阶段": "현재 단계", - "很遗憾您这没有能用的显卡来支持您训练": "사용 가능한 그래픽 카드가 없어 훈련을 지원할 수 없습니다", - "性别因子/声线粗细": "성별 계수 / 음색 굵기", - "性能设置": "성능 설정", - "总训练轮数total_epoch": "총 훈련 라운드 수 total_epoch", - "成功": "성공", - "执行命令": "실행 명령", - "批量推理": "일괄 추론", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "일괄 변환, 변환할 오디오 파일 폴더 입력 또는 여러 오디오 파일 업로드, 지정된 폴더(기본값 opt)에 변환된 오디오 출력.", - "拖拽或点击上传待处理音频": "처리할 오디오를 끌어다 놓거나 클릭하여 업로드", - "指定输出文件夹": "출력 파일 폴더 지정", - "推理时间(ms):": "추론 시간(ms):", - "推理耗时:%.2f秒": "추론 시간: %.2f seconds", - "推理音色": "추론 음색", - "提交训练集清单": "Submit dataset manifest", - "提取": "추출", - "提取音高和处理数据使用的CPU进程数": "음높이 추출 및 데이터 처리에 사용되는 CPU 프로세스 수", - "数据切分": "데이터 분할", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "데이터 전처리에서 16 kHz 오디오가 생성되지 않아 특징 추출과 학습을 중지했습니다.", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "데이터 전처리에서 유효한 학습 오디오가 생성되지 않았습니다. 데이터셋과 전처리 로그를 확인하세요.", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "데이터 전처리 출력 파일이 일치하지 않아 특징 추출과 학습을 중지했습니다.", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "데이터 추출 시작: start_time=%.6f, 요청 병렬 수=%s, 실제 병렬 상한=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "데이터 추출 완료: end_time=%.6f, 총 소요 시간=%.3f초", - "新增一行": "Add row", - "无法停止": "중지할 수 없음", - "是": "예", - "是否仅保存最新的ckpt文件以节省硬盘空间": "디스크 공간을 절약하기 위해 최신 ckpt 파일만 저장할지 여부", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "저장 시마다 최종 소형 모델을 weights 폴더에 저장할지 여부", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "모든 훈련 세트를 VRAM에 캐시할지 여부. 10분 미만의 소량 데이터는 캐시하여 훈련 속도를 높일 수 있지만, 대량 데이터 캐시는 VRAM을 과부하시키고 속도를 크게 향상시키지 못함", - "显卡信息": "그래픽 카드 정보", - "未使用": "사용 안 함", - "未使用判别器预训练模型": "판별기 사전 학습 모델을 사용하지 않음", - "未使用生成器预训练模型": "생성기 사전 학습 모델을 사용하지 않음", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "지원되는 GPU가 감지되지 않았습니다. CPU 학습은 훨씬 오래 걸릴 수 있습니다", - "未运行": "실행 안 됨", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "이 소프트웨어는 MIT 라이선스로 공개되며, 저자는 소프트웨어에 대해 어떠한 통제권도 가지지 않습니다. 모든 귀책사유는 소프트웨어 사용자 및 소프트웨어에서 생성된 결과물을 사용하는 당사자에게 있습니다.
해당 조항을 인정하지 않는 경우, 소프트웨어 패키지의 어떠한 코드나 파일도 사용하거나 인용할 수 없습니다. 자세한 내용은 루트 디렉토리의 LICENSE를 참조하세요.", - "查看": "보기", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "모델 정보 보기(오직 weights 폴더에서 추출된 소형 모델 파일만 지원)", - "检索特征占比": "검색 특징 비율", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "모델 정보: %s\n샘플링 레이트: %s\n피치 가이드: %s\n버전: %s", - "模型推理": "모델 추론", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "모델 추출(logs 폴더 아래의 큰 파일 모델 경로 입력), 훈련 중간에 중단한 모델의 자동 추출 및 소형 파일 모델 저장이 안 되거나 중간 모델을 테스트하고 싶은 경우에 적합", - "模型是否带音高指导": "모델이 음높이 지도를 포함하는지 여부", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "모델이 음높이 지도를 포함하는지 여부(노래에는 반드시 필요, 음성에는 필요 없음)", - "模型是否带音高指导,1是0否": "모델이 음높이 지도를 포함하는지 여부, 1은 예, 0은 아니오", - "模型版本型号": "모델 버전 및 모델", - "模型融合, 可用于测试音色融合": "모델 융합, 음색 융합 테스트에 사용 가능", - "模型融合失败:两个模型的结构不一致": "두 모델의 구조가 일치하지 않아 모델 병합에 실패했습니다", - "模型训练": "모델 학습", - "模型路径": "모델 경로", - "正在保存最终检查点:%s": "최종 체크포인트 저장 중: %s", - "正在保存检查点 %s_e%s:%s": "체크포인트 저장 중 %s_e%s: %s", - "正在加载RMVPE模型": "RMVPE 모델 불러오는 중", - "正在加载模型": "모델 불러오는 중", - "正在启动": "시작 중", - "正在收尾": "마무리 중", - "正在预热CUDA Graph": "CUDA Graph 워밍업 중", - "每张显卡的batch_size": "각 그래픽 카드의 batch_size", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "학습에 사용할 유효한 오디오가 없습니다. 먼저 데이터 전처리와 특징 추출을 완료하세요.", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "페이드 인/아웃 길이", - "清理模型缓存": "모델 캐시 정리 중", - "版本": "버전", - "特征": "특징", - "特征提取": "특징 추출", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "특징 인덱스 경로(모델 선택 후 자동 매칭, 수동 수정 가능)", - "状态": "상태", - "独占 WASAPI 设备": "WASAPI 독점 장치", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "목표 샘플링률", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "대기 중", - "等待输入": "입력 대기 중", - "算法延迟(ms):": "알고리즘 지연(ms):", - "索引": "인덱스", - "索引文件不存在,将不使用索引继续推理:%s": "인덱스 파일이 없습니다. 인덱스 없이 추론을 계속합니다: %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "잘못된 인덱스입니다. 다음을 사용하세요: added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "인덱스 검색 실패", - "索引检索失败或未启用": "인덱스 검색 실패 또는 비활성화됨", - "索引训练": "인덱스 학습", - "耗时": "소요 시간", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "소요 시간: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "융합", - "要改的模型信息": "변경할 모델 정보", - "要置入的模型信息": "삽입할 모델 정보", - "训练": "훈련", - "训练已完成,正在保存最终模型": "학습 완료, 최종 모델을 저장합니다", - "训练文件列表写入完成": "학습 파일 목록 저장 완료", - "训练模型": "모델 훈련", - "训练特征索引": "특징 인덱스 훈련", - "训练设备规则选择的精度:%s": "장치 규칙에 따라 선택한 학습 정밀도: %s", - "训练轮次:{} [{:.0f}%]": "학습 에포크: {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "장치 유형", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "오디오 파일을 업로드하세요", - "请填写输出文件夹路径": "출력 폴더 경로를 입력하세요", - "请指定说话人id": "화자 ID 지정 필요", - "请选择index文件": "index 파일 선택", - "请选择pth文件": "pth 파일 선택", - "请选择说话人id": "화자 ID 선택", - "转换": "변환", - "输入实验名": "실험명 입력", - "输入实验名,例如:test": "실험명(예: test)", - "输入待处理音频文件夹路径": "처리할 오디오 파일 폴더 경로 입력", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "처리할 오디오 파일 폴더 경로 입력(파일 탐색기 주소 표시줄에서 복사)", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "입력 소스 볼륨 엔벨로프와 출력 볼륨 엔벨로프의 결합 비율 입력, 1에 가까울수록 출력 엔벨로프 사용", - "输入监听": "입력 모니터링", - "输入训练文件夹路径": "훈련 파일 폴더 경로 입력", - "输入设备": "입력 장치", - "输入设备:%s:%s": "입력 장치: %s:%s", - "输入降噪": "입력 노이즈 감소", - "输出信息": "출력 정보", - "输出变声": "출력 음성 변환", - "输出设备": "출력 장치", - "输出设备:%s:%s": "출력 장치: %s:%s", - "输出降噪": "출력 노이즈 감소", - "输出音频(右下角三个点,点了可以下载)": "출력 오디오(오른쪽 하단 세 개의 점, 클릭하면 다운로드 가능)", - "运行中": "실행 중", - "进度": "진행률", - "选择.index文件": ".index 파일 선택", - "选择.pth文件": ".pth 파일 선택", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "모델 선택", - "选择索引": "인덱스 선택", - "选择音高提取算法": "피치 추출 알고리즘 선택", - "采样率:": "샘플링 레이트:", - "采样长度": "샘플링 길이", - "重复次数": "Repeat count", - "重载设备列表": "장치 목록 재로드", - "音调设置": "음조 설정", - "音频设备": "오디오 장치", - "音高全部为0,该音频无意义,跳过:%s": "모든 피치 값이 0이므로 이 오디오는 무의미하여 건너뜁니다: %s", - "音高算法": "피치 알고리즘", - "额外推理时长": "추가 추론 시간" -} diff --git a/i18n/locale/pt_BR.json b/i18n/locale/pt_BR.json deleted file mode 100644 index 2a74017e9856b1614a3bc05cb8b9491f425f2471..0000000000000000000000000000000000000000 --- a/i18n/locale/pt_BR.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s está em execução; interrompa antes de iniciar outra tarefa", - "====> 轮次:{} {}": "====> Época: {} {}", - "A模型权重": "Peso (w) para o modelo A:", - "A模型路径": "Caminho para o Modelo A:", - "B模型路径": "Caminho para o Modelo B:", - "CUDA Graph预热完成": "Aquecimento do CUDA Graph concluído", - "CUDA可用:%s": "CUDA disponível: %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "Caminho da pasta de treinamento, por exemplo: E:\\Meu conjunto de treinamento", - "F0与HuBERT特征提取": "Extração de F0 e recursos HuBERT", - "F0提取": "Extração F0", - "F0提取没有生成有效结果,已停止训练": "A extração de F0 não gerou resultados válidos. O treinamento foi interrompido.", - "HuBERT特征": "Recursos HuBERT", - "HuBERT特征提取没有生成有效结果,已停止训练": "A extração de recursos HuBERT não gerou resultados válidos. O treinamento foi interrompido.", - "Index Rate": "Taxa do Index", - "SOLA偏移:%d": "Deslocamento SOLA: %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Extração F0] Concluído | Sucesso: %s | Ignorados: %s | Falha: %s", - "[F0提取] 待处理:%s": "[Extração F0] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[Extração F0] Nenhum áudio pendente; todos os arquivos foram ignorados", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[Extração F0] Progresso: %s/%s | Sucesso: %s | Ignorados: %s | %s", - "[F0提取][失败] %s": "[Extração F0][Falha] %s", - "[F0提取][失败] %s\n%s": "[Extração F0][Falha] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Recursos HuBERT] Concluído | Sucesso: %s | Ignorados: %s | Falha: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[Recursos HuBERT] Nenhum áudio pendente; ignorados: %s", - "[HuBERT特征] 正在加载模型:%s": "[Recursos HuBERT] Carregando o modelo: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[Recursos HuBERT] Dispositivo: %s | Pending: %s | Ignorados: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[Recursos HuBERT] Progresso: %s/%s | Sucesso: %s | Falha: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[Recursos HuBERT][Falha] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[Recursos HuBERT][Falha] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[Recursos HuBERT][Falha] Modelo not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[Divisão de dados] Subtarefa concluída | Sucesso: %s | Falha: %s", - "[数据切分] 完成": "[Divisão de dados] Concluído", - "[数据切分] 开始": "[Divisão de dados] Iniciado", - "[数据切分] 待处理:%s | 进程数:%s": "[Divisão de dados] Pending: %s | Processos: %s", - "[数据切分] 进度:%s/%s | %s": "[Divisão de dados] Progresso: %s/%s | %s", - "[数据切分][失败] %s": "[Divisão de dados][Falha] %s", - "[数据切分][失败] %s\n%s": "[Divisão de dados][Falha] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[Divisão de dados][Ignorados] Segmento de áudio inválido ou anormal: %s_%s | Pico: %s", - "[索引训练] 写入进度:%s/%s": "[Treinamento do índice] Progressoo da gravação: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[Treinamento de índice] O link externo já existe: %s", - "[索引训练] 已链接索引到外部目录:%s": "[Treinamento do índice] Índice vinculado à pasta externa: %s", - "[索引训练] 成功构建索引:%s": "[Treinamento do índice] Índice criado com sucesso: %s", - "[索引训练] 正在写入特征向量": "[Treinamento do índice] Adicionando vetores de recursos", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[Treinamento do índice] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[Treinamento do índice] Treinando o índice", - "[索引训练] 特征形状:%s | IVF数量:%s": "[Treinamento do índice] Forma dos recursos: %s | Quantidade de IVF: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[Treinamento do índice][Falha] Não foi possível vincular o índice à pasta externa: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[Treinamento do índice][Falha] O agrupamento falhou; continuando com os recursos originais\n%s", - "[索引训练][失败] 请先进行特征提取": "[Treinamento do índice][Falha] Extraia os recursos primeiro", - "[索引训练][跳过] added索引已存在:%s": "[Treinamento de índice][Ignorado] O índice added já existe: %s", - "[索引训练][跳过] trained索引已存在:%s": "[Treinamento de índice][Ignorado] O índice trained já existe: %s", - "ckpt处理": "processamento ckpt", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": "O caminho do arquivo de Index não pode conter caracteres chineses", - "pth文件路径不可包含中文": "o caminho do arquivo pth não pode conter caracteres chineses", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "Configuração do número do cartão rmvpe: Use - para separar os números dos cartões de entrada de diferentes processos. Por exemplo, 0-0-1 é usado para executar 2 processos no cartão 0 e 1 processo no cartão 1.", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "Etapa 1: Preencha a configuração experimental. Os dados experimentais são armazenados na pasta 'logs', com cada experimento tendo uma pasta separada. Digite manualmente o caminho do nome do experimento, que contém a configuração experimental, os logs e os arquivos de modelo treinados.", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "Etapa 2b: extração de tom e características semânticas do HuBERT", - "step3: 填写训练设置, 开始训练模型和索引": "Etapa 3: Preencha as configurações de treinamento e comece a treinar o modelo e o Index", - "……仅显示最近10条失败记录": "…Mostrando apenas as 10 falhas mais recentes", - "……已省略前%s行,仅显示最新状态": "…As primeiras %s linhas foram omitidas; mostrando apenas o estado mais recente", - "一键训练": "Treinamento com um clique", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "Pasta de saída principal", - "也可批量输入音频文件, 二选一, 优先读文件夹": "Você também pode inserir arquivos de áudio em lotes. Escolha uma das duas opções. É dada prioridade à leitura da pasta.", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "Processamento em lote de voz, acompanhamento e reverberação com modelos pymss/MSST.", - "人声伴奏分离&去混响": "Separação de voz/acompanhamento e remoção de reverberação", - "仅支持pm和rmvpe音高提取算法": "Somente os métodos de extração de tom pm e rmvpe são compatíveis", - "从训练检查点提取的模型": "Modeloo extraído de um checkpoint de treinamento", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "Digite o (s) índice(s) da GPU separados por '-', por exemplo, 0-1-2 para usar a GPU 0, 1 e 2:", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "Tarefa", - "使用显卡:%s": "GPUs em uso: %s", - "使用模型采样率": "Usar taxa do modelo", - "使用设备采样率": "Usar taxa do dispositivo", - "保存名": "Salvar nome", - "保存的文件名, 默认空为和源文件同名": "Salvar nome do arquivo (padrão: igual ao arquivo de origem):", - "保存的模型名不带后缀": "Nome do modelo salvo (sem extensão):", - "保存频率save_every_epoch": "Faça backup a cada # de Epoch:", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Proteja consoantes sem voz e sons respiratórios, evite artefatos como quebra de som eletrônico e desligue-o quando estiver cheio de 0,5. Diminua-o para aumentar a proteção, mas pode reduzir o efeito de indexação:", - "修改": "Editar", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Modificar informações do modelo (suportado apenas para arquivos de modelo pequenos extraídos da pasta 'weights')", - "停止一键训练": "Parar treinamento com um clique", - "停止分离": "Parar separação", - "停止处理数据": "Parar pré-processamento de dados", - "停止特征提取": "Parar extração de características", - "停止训练模型": "Parar treinamento do modelo", - "停止训练索引": "Parar treinamento do índice", - "停止音频转换": "Conversão de áudio", - "分离残余文件夹": "Pasta de saída residual", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "Atualizar lista de vozes", - "加载模型": "Modelo", - "加载预训练底模D路径": "Carregue o caminho D do modelo base pré-treinado:", - "加载预训练底模G路径": "Carregue o caminho G do modelo base pré-treinado:", - "单次推理": "Inferência única", - "单说话人": "Single speaker", - "卸载音色省显存": "Descarregue a voz para liberar a memória da GPU:", - "变调(整数, 半音数量, 升八度12降八度-12)": "Mude o tom aqui. Se a voz for do mesmo sexo, não é necessario alterar (12 caso seja Masculino para feminino, -12 caso seja ao contrário).", - "合成": "Síntese", - "后处理重采样至最终采样率,0为不进行重采样": "Reamostragem pós-processamento para a taxa de amostragem final, 0 significa sem reamostragem:", - "否": "Não", - "响应阈值": "Limiar de resposta", - "响度因子": "Fator de volume", - "处理中": "Processando", - "处理数据": "Processar o Conjunto de Dados", - "处理方式": "Modo de processamento", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "Atenção: o treinamento com vários falantes pode reproduzir cada voz com menos fidelidade do que treinar cada falante separadamente!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "Falha", - "失败记录": "Registro de falhas", - "子进程执行失败,返回码:%s": "O subprocesso falhou com o código de saída: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "Qual formato de arquivo você prefere?", - "已停止": "Interrompido", - "已加载判别器预训练模型:%s": "Modeloo pré-treinado do discriminador carregado: %s", - "已加载生成器预训练模型:%s": "Modeloo pré-treinado do gerador carregado: %s", - "已启用索引检索": "Pesquisa por índice ativada", - "已完成": "Concluído", - "已完成阶段": "Etapas concluídas", - "已恢复判别器检查点": "Checkpoint do discriminador restaurado", - "已成功": "Concluído", - "常见问题解答": "FAQ (Perguntas frequentes)", - "常规设置": "Configurações gerais", - "底层模型": "Modelo subjacente", - "开始音频转换": "Iniciar conversão de áudio", - "当前": "Atual", - "当前设备:%s | 推理精度:%s": "Dispositivo atual: %s | Precisão de inferência: %s", - "当前阶段": "Etapa atual", - "很遗憾您这没有能用的显卡来支持您训练": "Infelizmente, não há GPU compatível disponível para apoiar o seu treinamento.", - "性别因子/声线粗细": "Fator de gênero / espessura da voz", - "性能设置": "Configurações de desempenho.", - "总训练轮数total_epoch": "Número total de ciclos(epoch) de treino (se escolher um valor alto demais, o seu modelo parecerá terrivelmente sobretreinado):", - "成功": "Sucesso", - "执行命令": "Comando", - "批量推理": "Inferência em lote", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Conversão em Massa.", - "拖拽或点击上传待处理音频": "Arraste e solte ou clique para enviar o áudio a ser processado", - "指定输出文件夹": "Especifique a pasta de saída:", - "推理时间(ms):": "Tempo de inferência (ms):", - "推理耗时:%.2f秒": "Tempo de inferência: %.2f seconds", - "推理音色": "Escolha o seu Modelo:", - "提交训练集清单": "Submit dataset manifest", - "提取": "Extrato", - "提取音高和处理数据使用的CPU进程数": "Número de processos de CPU usados para extração de tom e processamento de dados:", - "数据切分": "Divisão de dados", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "O pré-processamento não gerou áudio de 16 kHz. A extração e o treinamento foram interrompidos.", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "O pré-processamento não gerou áudio de treinamento válido. Verifique o conjunto de dados e o log.", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "Os arquivos de saída do pré-processamento não correspondem. A extração e o treinamento foram interrompidos.", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "Extração de dados iniciada: start_time=%.6f, concorrência solicitada=%s, limite real=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "Extração de dados concluída: end_time=%.6f, tempo total=%.3f segundos", - "新增一行": "Add row", - "无法停止": "Não é possível interromper", - "是": "Sim", - "是否仅保存最新的ckpt文件以节省硬盘空间": "Só deve salvar apenas o arquivo ckpt mais recente para economizar espaço em disco:", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "Salve um pequeno modelo final na pasta 'weights' em cada ponto de salvamento:", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Se deve armazenar em cache todos os conjuntos de treinamento na memória de vídeo. Pequenos dados com menos de 10 minutos podem ser armazenados em cache para acelerar o treinamento, e um cache de dados grande irá explodir a memória de vídeo e não aumentar muito a velocidade:", - "显卡信息": "Informações da GPU", - "未使用": "Não usado", - "未使用判别器预训练模型": "Modelo pré-treinado do discriminador não usado", - "未使用生成器预训练模型": "Modelo pré-treinado do gerador não usado", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "Nenhuma GPU compatível foi detectada; treinar na CPU pode demorar muito mais", - "未运行": "Não iniciado", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "
The Mangio-RVC 💻 | Tradução por Krisp e Rafael Godoy Ebert | AI HUB BRASIL
Este software é de código aberto sob a licença MIT. O autor não tem qualquer controle sobre o software. Aqueles que usam o software e divulgam os sons exportados pelo software são totalmente responsáveis.
Se você não concorda com este termo, você não pode usar ou citar nenhum código e arquivo no pacote de software. Para obter detalhes, consulte o diretório raiz O acordo a ser seguido para uso LICENSE
", - "查看": "Visualizar", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "Exibir informações do modelo (suportado apenas para arquivos de modelo pequenos extraídos da pasta 'weights')", - "检索特征占比": "Taxa de recurso de recuperação:", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "Informações do modelo: %s\nTaxa de amostragem: %s\nOrientação de tom: %s\nVersão: %s", - "模型推理": "Inference", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "Extração do modelo (insira o caminho do modelo de arquivo grande na pasta 'logs'). Isso é útil se você quiser interromper o treinamento no meio do caminho e extrair e salvar manualmente um arquivo de modelo pequeno, ou se quiser testar um modelo intermediário:", - "模型是否带音高指导": "Se o modelo tem orientação de tom:", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "Se o modelo tem orientação de tom (necessário para cantar, opcional para fala):", - "模型是否带音高指导,1是0否": "Se o modelo tem orientação de passo (1: sim, 0: não):", - "模型版本型号": "Versão:", - "模型融合, 可用于测试音色融合": "A fusão modelo, pode ser usada para testar a fusão do timbre", - "模型融合失败:两个模型的结构不一致": "Falha ao mesclar modelos: as arquiteturas não correspondem", - "模型训练": "Treinamento do modelo", - "模型路径": "Caminho para o Modelo:", - "正在保存最终检查点:%s": "Salvando o checkpoint final: %s", - "正在保存检查点 %s_e%s:%s": "Salvando o checkpoint %s_e%s: %s", - "正在加载RMVPE模型": "Carregando o modelo RMVPE", - "正在加载模型": "Carregando o modelo", - "正在启动": "Iniciando", - "正在收尾": "Finalizando", - "正在预热CUDA Graph": "Aquecendo o CUDA Graph", - "每张显卡的batch_size": "Batch Size (DEIXE COMO ESTÁ a menos que saiba o que está fazendo, no Colab pode deixar até 20!):", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "Não há áudio válido para treinamento. Conclua primeiro o pré-processamento e a extração de recursos.", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "Comprimento de desvanecimento", - "清理模型缓存": "Limpando o cache do modelo", - "版本": "Versão", - "特征": "Recursos", - "特征提取": "Extrair Tom", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "Caminho do índice de características (detectado após selecionar o modelo; editável)", - "状态": "Estado", - "独占 WASAPI 设备": "Dispositivo WASAPI exclusivo", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "Taxa de amostragem:", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "Aguardando", - "等待输入": "Aguardando entrada", - "算法延迟(ms):": "Latência do algoritmo (ms):", - "索引": "Índice", - "索引文件不存在,将不使用索引继续推理:%s": "O arquivo de índice não existe; a inferência continuará sem índice: %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "Índice inválido: use added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "Falha na pesquisa por índice", - "索引检索失败或未启用": "A pesquisa por índice falhou ou está desativada", - "索引训练": "Treinamento do índice", - "耗时": "Tempo decorrido", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "Tempo decorrido: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "Fusão", - "要改的模型信息": "Informações do modelo a ser modificado:", - "要置入的模型信息": "Informações do modelo a ser colocado:", - "训练": "Treinar", - "训练已完成,正在保存最终模型": "Treinamento concluído; salvando o modelo final", - "训练文件列表写入完成": "Lista de arquivos de treinamento salva", - "训练模型": "Treinar Modelo", - "训练特征索引": "Treinar Index", - "训练设备规则选择的精度:%s": "Precisão de treinamento escolhida pelas regras do dispositivo: %s", - "训练轮次:{} [{:.0f}%]": "Época de treinamento: {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "Tipo de dispositivo", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "Envie um arquivo de áudio", - "请填写输出文件夹路径": "Informe o caminho da pasta de saída", - "请指定说话人id": "Especifique o ID do locutor/cantor:", - "请选择index文件": "Selecione o arquivo de Index", - "请选择pth文件": "Selecione o arquivo pth", - "请选择说话人id": "Selecione Palestrantes/Cantores ID:", - "转换": "Converter", - "输入实验名": "Nome da voz:", - "输入实验名,例如:test": "Nome do experimento, por exemplo: test", - "输入待处理音频文件夹路径": "Caminho da pasta de áudio a ser processada:", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "Caminho da pasta de áudio a ser processada (copie-o da barra de endereços do gerenciador de arquivos):", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "O envelope de volume da fonte de entrada substitui a taxa de fusão do envelope de volume de saída, quanto mais próximo de 1, mais o envelope de saída é usado:", - "输入监听": "Monitorar entrada", - "输入训练文件夹路径": "Caminho da pasta de treinamento:", - "输入设备": "Dispositivo de entrada", - "输入设备:%s:%s": "Dispositivo de entrada: %s:%s", - "输入降噪": "Redução de ruído de entrada", - "输出信息": "Informação de saída", - "输出变声": "Conversão de saída", - "输出设备": "Dispositivo de saída", - "输出设备:%s:%s": "Dispositivo de saída: %s:%s", - "输出降噪": "Redução de ruído de saída", - "输出音频(右下角三个点,点了可以下载)": "Exportar áudio (clique nos três pontos no canto inferior direito para baixar)", - "运行中": "Em execução", - "进度": "Progresso", - "选择.index文件": "Selecione o Index", - "选择.pth文件": "Selecione o Arquivo", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "Selecionar modelo", - "选择索引": "Selecionar índice", - "选择音高提取算法": "Selecione o algoritmo de extração de tom", - "采样率:": "Taxa de amostragem:", - "采样长度": "Comprimento da Amostra", - "重复次数": "Repeat count", - "重载设备列表": "Recarregar lista de dispositivos", - "音调设置": "Configurações de tom", - "音频设备": "Dispositivo de áudio", - "音高全部为0,该音频无意义,跳过:%s": "Todos os valores de tom são zero; este áudio não tem utilidade e será ignorado: %s", - "音高算法": "Algoritmo de tom", - "额外推理时长": "Tempo extra de inferência" -} diff --git a/i18n/locale/ru_RU.json b/i18n/locale/ru_RU.json deleted file mode 100644 index 86c9ea8e44fb516224319edb4dc89ff9b235533a..0000000000000000000000000000000000000000 --- a/i18n/locale/ru_RU.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s уже выполняется; сначала остановите эту задачу", - "====> 轮次:{} {}": "====> Эпоха: {} {}", - "A模型权重": "Весы (w) модели А:", - "A模型路径": "Путь к модели А:", - "B模型路径": "Путь к модели Б:", - "CUDA Graph预热完成": "Прогрев CUDA Graph завершён", - "CUDA可用:%s": "CUDA доступна: %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "Путь к папке обучающего набора, например: E:\\Мой обучающий набор", - "F0与HuBERT特征提取": "Извлечение F0 и признаков HuBERT", - "F0提取": "Извлечение F0", - "F0提取没有生成有效结果,已停止训练": "Извлечение F0 не дало допустимых результатов. Обучение остановлено.", - "HuBERT特征": "Признаки HuBERT", - "HuBERT特征提取没有生成有效结果,已停止训练": "Извлечение признаков HuBERT не дало допустимых результатов. Обучение остановлено.", - "Index Rate": "Темп индекса", - "SOLA偏移:%d": "Смещение SOLA: %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Извлечение F0] Завершено | Успешно: %s | Пропущено: %s | Ошибка: %s", - "[F0提取] 待处理:%s": "[Извлечение F0] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[Извлечение F0] Нет ожидающих аудиофайлов; все файлы пропущены", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[Извлечение F0] Прогресс: %s/%s | Успешно: %s | Пропущено: %s | %s", - "[F0提取][失败] %s": "[Извлечение F0][Ошибка] %s", - "[F0提取][失败] %s\n%s": "[Извлечение F0][Ошибка] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[Признаки HuBERT] Завершено | Успешно: %s | Пропущено: %s | Ошибка: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[Признаки HuBERT] Нет ожидающих аудиофайлов; пропущено: %s", - "[HuBERT特征] 正在加载模型:%s": "[Признаки HuBERT] Загрузка модели: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[Признаки HuBERT] Устройство: %s | Pending: %s | Пропущено: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[Признаки HuBERT] Прогресс: %s/%s | Успешно: %s | Ошибка: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[Признаки HuBERT][Ошибка] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[Признаки HuBERT][Ошибка] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[Признаки HuBERT][Ошибка] Модель not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[Нарезка данных] Подзадача завершена | Успешно: %s | Ошибка: %s", - "[数据切分] 完成": "[Нарезка данных] Завершено", - "[数据切分] 开始": "[Нарезка данных] Запущено", - "[数据切分] 待处理:%s | 进程数:%s": "[Нарезка данных] Pending: %s | Процессы: %s", - "[数据切分] 进度:%s/%s | %s": "[Нарезка данных] Прогресс: %s/%s | %s", - "[数据切分][失败] %s": "[Нарезка данных][Ошибка] %s", - "[数据切分][失败] %s\n%s": "[Нарезка данных][Ошибка] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[Нарезка данных][Пропущено] Недопустимый или аномальный аудиофрагмент: %s_%s | Пик: %s", - "[索引训练] 写入进度:%s/%s": "[Обучение индекса] Ход записи: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[Обучение индекса] Внешняя ссылка уже существует: %s", - "[索引训练] 已链接索引到外部目录:%s": "[Обучение индекса] Индекс связан с внешней папкой: %s", - "[索引训练] 成功构建索引:%s": "[Обучение индекса] Индекс успешно создан: %s", - "[索引训练] 正在写入特征向量": "[Обучение индекса] Добавление векторов признаков", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[Обучение индекса] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[Обучение индекса] Обучение индекса", - "[索引训练] 特征形状:%s | IVF数量:%s": "[Обучение индекса] Форма признаков: %s | Количество IVF: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[Обучение индекса][Ошибка] Не удалось связать индекс с внешней папкой: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[Обучение индекса][Ошибка] Сбой кластеризации; продолжение с исходными признаками\n%s", - "[索引训练][失败] 请先进行特征提取": "[Обучение индекса][Ошибка] Сначала извлеките признаки", - "[索引训练][跳过] added索引已存在:%s": "[Обучение индекса][Пропущено] Индекс added уже существует: %s", - "[索引训练][跳过] trained索引已存在:%s": "[Обучение индекса][Пропущено] Индекс trained уже существует: %s", - "ckpt处理": "Обработка ckpt", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": "Путь к файлу индекса", - "pth文件路径不可包含中文": "Путь к файлу pth", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "Введите номера графических процессоров, разделенные символом «-», например, 0-0-1, чтобы запустить два процесса на GPU 0 и один процесс на GPU 1:", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "Шаг 1. Конфигурирование модели. Данные обучения модели сохраняются в папку 'logs', и для каждой модели создаётся отдельная папка. Введите вручную путь к настройкам для модели, в которой находятся логи и тренировочные файлы.", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "Шаг 2Б: извлечение высоты тона и семантических признаков HuBERT", - "step3: 填写训练设置, 开始训练模型和索引": "Шаг 3. Заполнение дополнительных настроек обучения и запуск обучения модели и индекса", - "……仅显示最近10条失败记录": "…Показаны только 10 последних ошибок", - "……已省略前%s行,仅显示最新状态": "…Первые %s строк пропущены; показано только последнее состояние", - "一键训练": "Обучение в одно нажатие", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "Основная папка вывода", - "也可批量输入音频文件, 二选一, 优先读文件夹": "Можно также импортировать несколько аудиофайлов. Если путь к папке существует, то этот ввод игнорируется.", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "Пакетная обработка вокала, аккомпанемента и реверберации с помощью моделей pymss/MSST.", - "人声伴奏分离&去混响": "Разделение вокала/аккомпанемента и удаление реверберации", - "仅支持pm和rmvpe音高提取算法": "Поддерживаются только методы извлечения высоты тона pm и rmvpe", - "从训练检查点提取的模型": "Модель извлечена из контрольной точки обучения", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "Введите, какие(-ую) GPU(-у) хотите использовать через '-', например 0-1-2, чтобы использовать GPU с номерами 0, 1 и 2:", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "Задача", - "使用显卡:%s": "Используемые GPU: %s", - "使用模型采样率": "Использовать частоту модели", - "使用设备采样率": "Использовать частоту устройства", - "保存名": "Имя файла для сохранения:", - "保存的文件名, 默认空为和源文件同名": "Название сохранённого файла (по умолчанию: такое же, как и у входного):", - "保存的模型名不带后缀": "Имя файла модели для сохранения (без расширения):", - "保存频率save_every_epoch": "Частота сохранения (save_every_epoch):", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Защитить глухие согласные и звуки дыхания для предотвращения артефактов, например, разрывания в электронной музыке. Поставьте на 0.5, чтобы выключить. Уменьшите значение для повышения защиты, но учтите, что при этом может ухудшиться точность индексирования:", - "修改": "Изменить", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Изменить информацию о модели (работает только с маленькими моделями, взятыми из папки 'weights')", - "停止一键训练": "Остановить обучение в один клик", - "停止分离": "Остановить разделение", - "停止处理数据": "Остановить предобработку данных", - "停止特征提取": "Остановить извлечение признаков", - "停止训练模型": "Остановить обучение модели", - "停止训练索引": "Остановить обучение индекса", - "停止音频转换": "Закончить конвертацию аудио", - "分离残余文件夹": "Папка остаточного вывода", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "Обновить список голосов", - "加载模型": "Загрузить модель", - "加载预训练底模D路径": "Путь к предварительно обученной базовой модели D:", - "加载预训练底模G路径": "Путь к предварительно обученной базовой модели G:", - "单次推理": "Одиночный инференс", - "单说话人": "Single speaker", - "卸载音色省显存": "Выгрузить модель из памяти GPU для освобождения ресурсов", - "变调(整数, 半音数量, 升八度12降八度-12)": "Изменить высоту голоса (укажите количество полутонов; чтобы поднять голос на октаву, выберите 12, понизить на октаву — -12):", - "合成": "Синтез", - "后处理重采样至最终采样率,0为不进行重采样": "Изменить частоту дискретизации в выходном файле на финальную. Поставьте 0, чтобы ничего не изменялось:", - "否": "Нет", - "响应阈值": "Порог ответа", - "响度因子": "коэффициент громкости", - "处理中": "Обработка", - "处理数据": "Обработать данные", - "处理方式": "Режим обработки", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "Внимание: обучение нескольких голосов может передавать каждый тембр менее точно, чем отдельное обучение для каждого диктора!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "Ошибка", - "失败记录": "Список ошибок", - "子进程执行失败,返回码:%s": "Дочерний процесс завершился с кодом: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "Формат выходных файлов", - "已停止": "Остановлено", - "已加载判别器预训练模型:%s": "Предобученная модель дискриминатора загружена: %s", - "已加载生成器预训练模型:%s": "Предобученная модель генератора загружена: %s", - "已启用索引检索": "Поиск по индексу включён", - "已完成": "Завершено", - "已完成阶段": "Завершённые этапы", - "已恢复判别器检查点": "Контрольная точка дискриминатора восстановлена", - "已成功": "Успешно", - "常见问题解答": "ЧаВо (часто задаваемые вопросы)", - "常规设置": "Основные настройки", - "底层模型": "Базовая модель", - "开始音频转换": "Начать конвертацию аудио", - "当前": "Текущий", - "当前设备:%s | 推理精度:%s": "Текущее устройство: %s | Точность вывода: %s", - "当前阶段": "Текущий этап", - "很遗憾您这没有能用的显卡来支持您训练": "К сожалению, у вас нету графического процессора, который поддерживает обучение моделей.", - "性别因子/声线粗细": "Гендерный коэффициент / толщина голоса", - "性能设置": "Настройки быстроты", - "总训练轮数total_epoch": "Полное количество эпох (total_epoch):", - "成功": "Успешно", - "执行命令": "Команда", - "批量推理": "Пакетный инференс", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Массовое преобразование. Введите путь к папке, в которой находятся файлы для преобразования голоса или выгрузите несколько аудиофайлов. Сконвертированные файлы будут сохранены в указанной папке (по умолчанию: 'opt').", - "拖拽或点击上传待处理音频": "Перетащите или нажмите, чтобы загрузить аудио для обработки", - "指定输出文件夹": "Папка для результатов:", - "推理时间(ms):": "Время переработки (мс):", - "推理耗时:%.2f秒": "Время инференса: %.2f seconds", - "推理音色": "Желаемый голос:", - "提交训练集清单": "Submit dataset manifest", - "提取": "Создать модель", - "提取音高和处理数据使用的CPU进程数": "Число процессов ЦП, используемое для оценки высоты голоса и обработки данных:", - "数据切分": "Нарезка данных", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "Предобработка не создала аудио 16 кГц. Извлечение признаков и обучение остановлены.", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "Предобработка не создала допустимые аудиофайлы для обучения. Проверьте набор данных и журнал.", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "Выходные файлы предобработки не совпадают. Извлечение признаков и обучение остановлены.", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "Извлечение данных начато: start_time=%.6f, запрошенный параллелизм=%s, фактический предел=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "Извлечение данных завершено: end_time=%.6f, общее время=%.3f с", - "新增一行": "Add row", - "无法停止": "Невозможно остановить", - "是": "Да", - "是否仅保存最新的ckpt文件以节省硬盘空间": "Сохранять только последний файл '.ckpt', чтобы сохранить место на диске:", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "Сохранять маленькую финальную модель в папку 'weights' на каждой точке сохранения:", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Кэшировать все тренировочные сеты в видеопамять. Кэширование маленький датасетов (меньше 10 минут) может ускорить тренировку, но кэширование больших, наоборот, займёт много видеопамяти и не сильно ускорит тренировку:", - "显卡信息": "Информация о графических процессорах (GPUs):", - "未使用": "Не используется", - "未使用判别器预训练模型": "Предобученная модель дискриминатора не используется", - "未使用生成器预训练模型": "Предобученная модель генератора не используется", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "Поддерживаемый GPU не обнаружен; обучение на CPU может занять значительно больше времени", - "未运行": "Не запущено", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "Это программное обеспечение с открытым исходным кодом распространяется по лицензии MIT. Автор никак не контролирует это программное обеспечение. Пользователи, которые используют эту программу и распространяют аудиозаписи, полученные с помощью этой программы, несут полную ответственность за это. Если вы не согласны с этим, вы не можете использовать какие-либо коды и файлы в рамках этой программы или ссылаться на них. Подробнее в файле Agreement-LICENSE.txt в корневом каталоге программы.", - "查看": "Просмотреть информацию", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "Просмотреть информацию о модели (работает только с маленькими моделями, взятыми из папки 'weights')", - "检索特征占比": "Соотношение поиска черт:", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "Информация о модели: %s\nЧастота дискретизации: %s\nУправление высотой тона: %s\nВерсия: %s", - "模型推理": "Изменение голоса", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "Создание модели из данных, полученных в процессе обучения (введите путь к большому файлу модели в папке 'logs'). Может пригодиться, если вам нужно завершить обучение и получить маленький файл готовой модели, или если вам нужно проверить недообученную модель:", - "模型是否带音高指导": "Поддерживает ли модель изменение высоты голоса (1: да, 0: нет):", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "Поддержка изменения высоты звука (обязательно для пения, необязательно для речи):", - "模型是否带音高指导,1是0否": "Поддерживает ли модель изменение высоты голоса (1: да, 0: нет):", - "模型版本型号": "Версия архитектуры модели:", - "模型融合, 可用于测试音色融合": "Слияние моделей, может быть использовано для проверки слияния тембра", - "模型融合失败:两个模型的结构不一致": "Не удалось объединить модели: их архитектуры не совпадают", - "模型训练": "Обучение модели", - "模型路径": "Путь к папке:", - "正在保存最终检查点:%s": "Сохранение итоговой контрольной точки: %s", - "正在保存检查点 %s_e%s:%s": "Сохранение контрольной точки %s_e%s: %s", - "正在加载RMVPE模型": "Загрузка модели RMVPE", - "正在加载模型": "Загрузка модели", - "正在启动": "Запуск", - "正在收尾": "Завершение", - "正在预热CUDA Graph": "Прогрев CUDA Graph", - "每张显卡的batch_size": "Размер пачки для GPU:", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "Нет допустимых аудиофайлов для обучения. Сначала выполните предобработку и извлечение признаков.", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "Длина затухания", - "清理模型缓存": "Очистка кэша модели", - "版本": "Версия архитектуры модели:", - "特征": "Признаки", - "特征提取": "Извлечь черты", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "Путь к индексу признаков (подбирается после выбора модели; можно изменить)", - "状态": "Состояние", - "独占 WASAPI 设备": "Эксклюзивное устройство WASAPI", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "Частота дискретизации аудио:", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "Ожидание", - "等待输入": "Ожидание ввода", - "算法延迟(ms):": "Задержка алгоритма (мс):", - "索引": "Индекс", - "索引文件不存在,将不使用索引继续推理:%s": "Файл индекса не существует; вывод продолжится без индекса: %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "Недопустимый индекс: используйте added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "Сбой поиска по индексу", - "索引检索失败或未启用": "Поиск по индексу не выполнен или отключён", - "索引训练": "Обучение индекса", - "耗时": "Затраченное время", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "Затраченное время: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "Запустить слияние", - "要改的模型信息": "Информация, которая будет изменена:", - "要置入的模型信息": "Информация о модели:", - "训练": "Обучение модели", - "训练已完成,正在保存最终模型": "Обучение завершено; сохраняется итоговая модель", - "训练文件列表写入完成": "Список файлов обучения записан", - "训练模型": "Обучить модель", - "训练特征索引": "Обучить индекс черт", - "训练设备规则选择的精度:%s": "Точность обучения выбрана по правилам устройства: %s", - "训练轮次:{} [{:.0f}%]": "Эпоха обучения: {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "Тип устройства", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "Загрузите аудиофайл", - "请填写输出文件夹路径": "Укажите путь к выходной папке", - "请指定说话人id": "Номер говорящего/поющего:", - "请选择index文件": "Пожалуйста, выберите файл индекса", - "请选择pth文件": "Пожалуйста, выберите файл pth", - "请选择说话人id": "Номер говорящего:", - "转换": "Преобразовать", - "输入实验名": "Название модели:", - "输入实验名,例如:test": "Название эксперимента, например: test", - "输入待处理音频文件夹路径": "Путь к папке с аудиофайлами для обработки:", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "Путь к папке с аудиофайлами для переработки (можно скопировать путь из адресной строки файлового менеджера):", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "Использовать громкость входного файла для замены или перемешивания с громкостью выходного файла. Чем ближе соотношение к 1, тем больше используется звука из выходного файла:", - "输入监听": "Мониторинг входа", - "输入训练文件夹路径": "Путь к папке с аудиозаписями, на которых будет обучаться модель:", - "输入设备": "Входное устройство", - "输入设备:%s:%s": "Устройство ввода: %s:%s", - "输入降噪": "Уменьшение входного шума", - "输出信息": "Статистика", - "输出变声": "Преобразование выхода", - "输出设备": "Выходное устройство", - "输出设备:%s:%s": "Устройство вывода: %s:%s", - "输出降噪": "Уменьшение выходного шума", - "输出音频(右下角三个点,点了可以下载)": "Аудиофайл (чтобы скачать, нажмите на три точки справа в плеере)", - "运行中": "Выполняется", - "进度": "Прогресс", - "选择.index文件": "Выбрать файл .index", - "选择.pth文件": "Выбрать файл .pth", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "Выберите модель", - "选择索引": "Выберите индекс", - "选择音高提取算法": "Выберите алгоритм извлечения высоты тона", - "采样率:": "Частота дискретизации:", - "采样长度": "Длина сэмпла", - "重复次数": "Repeat count", - "重载设备列表": "Обновить список устройств", - "音调设置": "Настройка высоты звука", - "音频设备": "Аудиоустройство", - "音高全部为0,该音频无意义,跳过:%s": "Все значения высоты тона равны нулю; это аудио бесполезно и будет пропущено: %s", - "音高算法": "Алгоритм высоты тона", - "额外推理时长": "Доп. время переработки" -} diff --git a/i18n/locale/tr_TR.json b/i18n/locale/tr_TR.json deleted file mode 100644 index 0c5b6addb557d3400d56c51ebf14d131b24ee01c..0000000000000000000000000000000000000000 --- a/i18n/locale/tr_TR.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s çalışıyor; başka bir görev başlatmadan önce durdurun", - "====> 轮次:{} {}": "====> Dönem: {} {}", - "A模型权重": "A Modeli Ağırlığı:", - "A模型路径": "A Modeli Yolu:", - "B模型路径": "B Modeli Yolu:", - "CUDA Graph预热完成": "CUDA Graph ısınması tamamlandı", - "CUDA可用:%s": "CUDA kullanılabilir: %s", - "输入训练文件夹路径,例如:E:\\我的训练集": "Eğitim klasörü yolu, örneğin: E:\\Eğitim veri kümem", - "F0与HuBERT特征提取": "F0 ve HuBERT özellik çıkarımı", - "F0提取": "F0 çıkarma", - "F0提取没有生成有效结果,已停止训练": "F0 çıkarma geçerli sonuç üretmedi. Eğitim durduruldu.", - "HuBERT特征": "HuBERT özellikleri", - "HuBERT特征提取没有生成有效结果,已停止训练": "HuBERT özellik çıkarma geçerli sonuç üretmedi. Eğitim durduruldu.", - "Index Rate": "Index Oranı", - "SOLA偏移:%d": "SOLA ofseti: %d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[F0 çıkarma] Tamamlandı | Başarılı: %s | Atlandı: %s | Başarısız: %s", - "[F0提取] 待处理:%s": "[F0 çıkarma] Pending: %s", - "[F0提取] 无待处理音频,已全部跳过": "[F0 çıkarma] Bekleyen ses yok; tüm dosyalar atlandı", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[F0 çıkarma] İlerleme: %s/%s | Başarılı: %s | Atlandı: %s | %s", - "[F0提取][失败] %s": "[F0 çıkarma][Başarısız] %s", - "[F0提取][失败] %s\n%s": "[F0 çıkarma][Başarısız] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[HuBERT özellikleri] Tamamlandı | Başarılı: %s | Atlandı: %s | Başarısız: %s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[HuBERT özellikleri] Bekleyen ses yok; atlanan: %s", - "[HuBERT特征] 正在加载模型:%s": "[HuBERT özellikleri] Model yükleniyor: %s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[HuBERT özellikleri] Cihaz: %s | Pending: %s | Atlandı: %s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[HuBERT özellikleri] İlerleme: %s/%s | Başarılı: %s | Başarısız: %s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[HuBERT özellikleri][Başarısız] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[HuBERT özellikleri][Başarısız] %s contains NaN values", - "[HuBERT特征][失败] 模型不存在:%s": "[HuBERT özellikleri][Başarısız] Model not found: %s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[Dataset preprocessing] Multi-speaker files: %s | Workers: %s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[Veri dilimleme] Alt görev tamamlandı | Başarılı: %s | Başarısız: %s", - "[数据切分] 完成": "[Veri dilimleme] Tamamlandı", - "[数据切分] 开始": "[Veri dilimleme] Başlatıldı", - "[数据切分] 待处理:%s | 进程数:%s": "[Veri dilimleme] Pending: %s | İşlemler: %s", - "[数据切分] 进度:%s/%s | %s": "[Veri dilimleme] İlerleme: %s/%s | %s", - "[数据切分][失败] %s": "[Veri dilimleme][Başarısız] %s", - "[数据切分][失败] %s\n%s": "[Veri dilimleme][Başarısız] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[Veri dilimleme][Atlandı] Geçersiz veya anormal ses bölümü: %s_%s | Tepe: %s", - "[索引训练] 写入进度:%s/%s": "[İndeks eğitimi] Yazma ilerlemesi: %s/%s", - "[索引训练] 外部索引链接已存在:%s": "[Dizin eğitimi] Harici dizin bağlantısı zaten var: %s", - "[索引训练] 已链接索引到外部目录:%s": "[İndeks eğitimi] İndeks harici klasöre bağlandı: %s", - "[索引训练] 成功构建索引:%s": "[İndeks eğitimi] İndeks başarıyla oluşturuldu: %s", - "[索引训练] 正在写入特征向量": "[İndeks eğitimi] Özellik vektörleri ekleniyor", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[İndeks eğitimi] Clustering %s feature vectors into 10,000 centers", - "[索引训练] 正在训练索引": "[İndeks eğitimi] İndeks eğitiliyor", - "[索引训练] 特征形状:%s | IVF数量:%s": "[İndeks eğitimi] Özellik şekli: %s | IVF sayısı: %s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[İndeks eğitimi][Başarısız] İndeks harici klasöre bağlanamadı: %s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[İndeks eğitimi][Başarısız] Kümeleme başarısız; özgün özelliklerle devam ediliyor\n%s", - "[索引训练][失败] 请先进行特征提取": "[İndeks eğitimi][Başarısız] Önce özellikleri çıkarın", - "[索引训练][跳过] added索引已存在:%s": "[Dizin eğitimi][Atlandı] added dizini zaten var: %s", - "[索引训练][跳过] trained索引已存在:%s": "[Dizin eğitimi][Atlandı] trained dizini zaten var: %s", - "ckpt处理": "ckpt İşleme", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "HuBERT: Enter GPU IDs separated by hyphens; for example, 0-1-2 uses GPUs 0, 1, and 2", - "index文件路径不可包含中文": ".index dosya yolu Çince karakter içeremez", - "pth文件路径不可包含中文": ".pth dosya yolu Çince karakter içeremez", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "RMVPE GPU yapılandırmasını tirelerle ayırın; örneğin 0-0-1, GPU 0'da iki ve GPU 1'de bir işlem çalıştırır", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "Adım 1: Deneysel yapılandırmayı doldurun. Deneysel veriler 'logs' klasöründe saklanır ve her bir deney için ayrı bir klasör vardır. Deneysel adı yolu manuel olarak girin; bu yol, deneysel yapılandırmayı, günlükleri ve eğitilmiş model dosyalarını içerir.", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "Step 2a: Scan, slice, and normalize training audio, then create training WAV files in the experiment directory.", - "step2b: 音高与hubert语义特征提取": "Adım 2b: perde ve HuBERT anlamsal özelliklerini çıkarma", - "step3: 填写训练设置, 开始训练模型和索引": "Adım 3: Eğitim ayarlarını doldurun ve modeli ve dizini eğitmeye başlayın", - "……仅显示最近10条失败记录": "…Yalnızca son 10 hata gösteriliyor", - "……已省略前%s行,仅显示最新状态": "…İlk %s satır atlandı; yalnızca en son durum gösteriliyor", - "一键训练": "Tek Tuşla Eğit", - "上一页": "Previous", - "下一页": "Next", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "Create a multi-speaker dataset manifest. Empty rows are ignored; incomplete path, speaker name, speaker ID, or repeat count fields are reported on submission.", - "主结果文件夹": "Ana çıktı klasörü", - "也可批量输入音频文件, 二选一, 优先读文件夹": "Ses dosyaları ayrıca toplu olarak, iki seçimle, öncelikli okuma klasörüyle içe aktarılabilir", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "pymss/MSST modelleriyle vokal, altyapı ve yankıyı toplu olarak işler.", - "人声伴奏分离&去混响": "Vokal/altyapı ayırma ve yankı giderme", - "仅支持pm和rmvpe音高提取算法": "Yalnızca pm ve rmvpe perde çıkarma yöntemleri desteklenir", - "从训练检查点提取的模型": "Eğitim kontrol noktasından çıkarılan model", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "GPU indekslerini '-' ile ayırarak girin, örneğin 0-1-2, GPU 0, 1 ve 2'yi kullanmak için:", - "以下行填写不完整或无效,已忽略:%s": "The following incomplete or invalid rows were ignored: %s", - "任务": "Görev", - "使用显卡:%s": "Kullanılan GPU: %s", - "使用模型采样率": "Model örnekleme hızını kullan", - "使用设备采样率": "Cihaz örnekleme hızını kullan", - "保存名": "Kaydetme Adı:", - "保存的文件名, 默认空为和源文件同名": "Kaydedilecek dosya adı (varsayılan: kaynak dosya ile aynı):", - "保存的模型名不带后缀": "Kaydedilecek model adı (uzantı olmadan):", - "保存频率save_every_epoch": "Kaydetme sıklığı (save_every_epoch):", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "Sessiz ünsüzleri ve nefes seslerini koruyarak elektronik müzikte yırtılma gibi sanal hataların oluşmasını engeller. 0.5 olarak ayarlandığında devre dışı kalır. Değerin azaltılması korumayı artırabilir, ancak indeksleme doğruluğunu azaltabilir:", - "修改": "Düzenle", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "Model bilgilerini düzenle (sadece 'weights' klasöründen çıkarılan küçük model dosyaları desteklenir)", - "停止一键训练": "Tek tıkla eğitimi durdur", - "停止分离": "Ayırmayı durdur", - "停止处理数据": "Veri ön işlemeyi durdur", - "停止特征提取": "Özellik çıkarmayı durdur", - "停止训练模型": "Model eğitimini durdur", - "停止训练索引": "İndeks eğitimini durdur", - "停止音频转换": "Ses dönüştürmeyi durdur", - "分离残余文件夹": "Artık çıktı klasörü", - "删除末行": "Remove last row", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "Discriminator pretrained model not found; it will not be used: assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "Ses listesini yenile", - "加载模型": "Model yükle", - "加载预训练底模D路径": "Önceden eğitilmiş temel D modelini yükleme yolu:", - "加载预训练底模G路径": "Önceden eğitilmiş temel G modelini yükleme yolu:", - "单次推理": "Tekli çıkarım", - "单说话人": "Single speaker", - "卸载音色省显存": "GPU bellek kullanımını azaltmak için sesi kaldır", - "变调(整数, 半音数量, 升八度12降八度-12)": "Transpoze et (tamsayı, yarıton sayısıyla; bir oktav yükseltmek için: 12, bir oktav düşürmek için: -12):", - "合成": "Sentez", - "后处理重采样至最终采样率,0为不进行重采样": "Son işleme aşamasında çıktı sesini son örnekleme hızına yeniden örnekle. 0 değeri için yeniden örnekleme yapılmaz:", - "否": "Hayır", - "响应阈值": "Tepki eşiği", - "响度因子": "ses yüksekliği faktörü", - "处理中": "İşleniyor", - "处理数据": "Verileri işle", - "处理方式": "İşleme modu", - "多说话人": "Multiple speakers", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "Not: Çok konuşmacılı eğitim, her sesi konuşmacıları ayrı ayrı eğitmek kadar doğru yansıtmayabilir!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "Invalid multi-speaker subfolders (expected Name_ID_Repeat, ID 0-109, a positive repeat count, one consistent name per ID, and at least one audio file): %s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "Only direct subfolders of the multi-speaker root are scanned; root files are ignored.\nName each subfolder x_y_z: x is the speaker name, y is the speaker ID (0-109, 110 choices), and z is the repeat count.\nYou can also submit a manifest from the Multi-speaker Dataset Helper tab.", - "多说话人训练集总文件夹不存在:%s": "Multi-speaker dataset root does not exist: %s", - "多说话人训练集总文件夹中没有有效音频": "The multi-speaker dataset root contains no valid audio", - "多说话人训练集总文件夹中没有直接子文件夹": "The multi-speaker dataset root has no direct subfolders", - "多说话人训练集总文件夹路径": "Multi-speaker dataset root", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "The multi-speaker manifest does not exist. Submit it from the helper tab or enter a dataset root first", - "多说话人训练集清单包含无效条目:%s": "The multi-speaker manifest contains an invalid entry: %s", - "多说话人训练集清单存在重复输出标识:%s": "The multi-speaker manifest contains a duplicate output key: %s", - "多说话人训练集清单已保存:%s;有效音频%s个": "Multi-speaker dataset manifest saved: %s; valid audio files: %s", - "多说话人训练集清单格式错误": "The multi-speaker manifest format is invalid", - "多说话人训练集清单没有有效音频": "The multi-speaker manifest contains no valid audio", - "多说话人训练集辅助": "Multi-speaker Dataset Helper", - "失败": "Başarısız", - "失败记录": "Hata kayıtları", - "子进程执行失败,返回码:%s": "Alt işlem şu çıkış koduyla başarısız oldu: %s", - "实验名不能为空": "Experiment name is required", - "导出文件格式": "Dışa aktarma dosya formatı", - "已停止": "Durduruldu", - "已加载判别器预训练模型:%s": "Önceden eğitilmiş ayırıcı modeli yüklendi: %s", - "已加载生成器预训练模型:%s": "Önceden eğitilmiş üretici modeli yüklendi: %s", - "已启用索引检索": "İndeks araması etkin", - "已完成": "Tamamlandı", - "已完成阶段": "Tamamlanan aşamalar", - "已恢复判别器检查点": "Ayırıcı kontrol noktası geri yüklendi", - "已成功": "Başarılı", - "常见问题解答": "Sıkça Sorulan Sorular (SSS)", - "常规设置": "Genel ayarlar", - "底层模型": "Temel model", - "开始音频转换": "Ses dönüştürmeyi başlat", - "当前": "Geçerli", - "当前设备:%s | 推理精度:%s": "Geçerli cihaz: %s | Çıkarım hassasiyeti: %s", - "当前阶段": "Geçerli aşama", - "很遗憾您这没有能用的显卡来支持您训练": "Maalesef, eğitiminizi desteklemek için uyumlu bir GPU bulunmamaktadır.", - "性别因子/声线粗细": "Cinsiyet faktörü / ses kalınlığı", - "性能设置": "Performans ayarları", - "总训练轮数total_epoch": "Toplam eğitim turu (total_epoch):", - "成功": "Başarılı", - "执行命令": "Komut", - "批量推理": "Toplu çıkarım", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "Toplu dönüştür. Dönüştürülecek ses dosyalarının bulunduğu klasörü girin veya birden çok ses dosyasını yükleyin. Dönüştürülen ses dosyaları belirtilen klasöre ('opt' varsayılan olarak) dönüştürülecektir", - "拖拽或点击上传待处理音频": "İşlenecek sesi sürükleyip bırakın veya yüklemek için tıklayın", - "指定输出文件夹": "Çıkış klasörünü belirt:", - "推理时间(ms):": "Çıkarsama süresi (ms):", - "推理耗时:%.2f秒": "Çıkarım süresi: %.2f seconds", - "推理音色": "Ses çıkartma (Inference):", - "提交训练集清单": "Submit dataset manifest", - "提取": "Çıkart", - "提取音高和处理数据使用的CPU进程数": "Ses yüksekliği çıkartmak (Pitch) ve verileri işlemek için kullanılacak CPU işlemci sayısı:", - "数据切分": "Veri dilimleme", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "Veri ön işleme 16 kHz ses üretmedi. Özellik çıkarma ve eğitim durduruldu.", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "Veri ön işleme geçerli eğitim sesi üretmedi. Veri kümesini ve günlüğü kontrol edin.", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "Veri ön işleme çıktı dosyaları eşleşmiyor. Özellik çıkarma ve eğitim durduruldu.", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "Veri çıkarma başladı: start_time=%.6f, istenen eşzamanlılık=%s, gerçek üst sınır=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "Veri çıkarma tamamlandı: end_time=%.6f, toplam süre=%.3f saniye", - "新增一行": "Add row", - "无法停止": "Durdurulamıyor", - "是": "Evet", - "是否仅保存最新的ckpt文件以节省硬盘空间": "Sadece en son '.ckpt' dosyasını kaydet:", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "Her kaydetme noktasında son küçük bir modeli 'weights' klasörüne kaydetmek için:", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "Tüm eğitim verilerini GPU belleğine önbelleğe alıp almayacağınızı belirtin. Küçük veri setlerini (10 dakikadan az) önbelleğe almak eğitimi hızlandırabilir, ancak büyük veri setlerini önbelleğe almak çok fazla GPU belleği tüketir ve çok fazla hız artışı sağlamaz:", - "显卡信息": "GPU Bilgisi", - "未使用": "Kullanılmadı", - "未使用判别器预训练模型": "Önceden eğitilmiş ayırıcı modeli kullanılmadı", - "未使用生成器预训练模型": "Önceden eğitilmiş üretici modeli kullanılmadı", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "Desteklenen GPU algılanmadı; CPU ile eğitim çok daha uzun sürebilir", - "未运行": "Başlatılmadı", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "Bu yazılım, MIT lisansı altında açık kaynaklıdır. Yazarın yazılım üzerinde herhangi bir kontrolü yoktur. Yazılımı kullanan ve yazılım tarafından dışa aktarılan sesleri dağıtan kullanıcılar sorumludur.
Eğer bu maddeyle aynı fikirde değilseniz, yazılım paketi içindeki herhangi bir kod veya dosyayı kullanamaz veya referans göremezsiniz. Detaylar için kök dizindeki Agreement-LICENSE.txt dosyasına bakınız.", - "查看": "Görüntüle", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "Model bilgilerini görüntüle (sadece 'weights' klasöründen çıkarılan küçük model dosyaları desteklenir)", - "检索特征占比": "Arama özelliği oranı (vurgu gücünü kontrol eder, çok yüksek olması sanal etkilere neden olur)", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "Model bilgisi: %s\nÖrnekleme hızı: %s\nPerde yönlendirmesi: %s\nSürüm: %s", - "模型推理": "Model çıkartma (Inference)", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "Model çıkartma (büyük dosya modeli yolunu 'logs' klasöründe girin). Bu, eğitimi yarıda bırakmak istediğinizde ve manuel olarak küçük bir model dosyası çıkartmak ve kaydetmek istediğinizde veya bir ara modeli test etmek istediğinizde kullanışlıdır:", - "模型是否带音高指导": "Modelin ses yüksekliği rehberi içerip içermediği:", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "Modelin ses yüksekliği (Pitch) rehberliği içerip içermediği (şarkı söyleme için şarttır, konuşma için isteğe bağlıdır):", - "模型是否带音高指导,1是0否": "Modelin ses yüksekliği rehberi içerip içermediği (1: evet, 0: hayır):", - "模型版本型号": "Model mimari versiyonu:", - "模型融合, 可用于测试音色融合": "Model birleştirme, ses rengi birleştirmesi için kullanılabilir", - "模型融合失败:两个模型的结构不一致": "Model birleştirme başarısız: iki modelin mimarisi eşleşmiyor", - "模型训练": "Model eğitimi", - "模型路径": "Model Yolu:", - "正在保存最终检查点:%s": "Son kontrol noktası kaydediliyor: %s", - "正在保存检查点 %s_e%s:%s": "Kontrol noktası kaydediliyor %s_e%s: %s", - "正在加载RMVPE模型": "RMVPE modeli yükleniyor", - "正在加载模型": "Model yükleniyor", - "正在启动": "Başlatılıyor", - "正在收尾": "Tamamlanıyor", - "正在预热CUDA Graph": "CUDA Graph ısınıyor", - "每张显卡的batch_size": "Her GPU için yığın boyutu (batch_size):", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "Eğitim için geçerli ses yok. Önce veri ön işleme ve özellik çıkarmayı tamamlayın.", - "没有有效的多说话人训练集行": "There are no valid multi-speaker dataset rows", - "淡入淡出长度": "Geçiş (Fade) uzunluğu", - "清理模型缓存": "Model önbelleği temizleniyor", - "版本": "Sürüm", - "特征": "Özellikler", - "特征提取": "Özellik çıkartma", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "Özellik dizini yolu (model seçilince otomatik eşleşir; düzenlenebilir)", - "状态": "Durum", - "独占 WASAPI 设备": "Özel WASAPI cihazı", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "Generator pretrained model not found; it will not be used: assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "Leave empty to use the manifest submitted from the helper tab", - "目标采样率": "Hedef örnekleme oranı:", - "第%s/%s页,共%s行": "Page %s/%s, %s rows", - "等待中": "Bekliyor", - "等待输入": "Girdi bekleniyor", - "算法延迟(ms):": "Algoritma gecikmesi (ms):", - "索引": "İndeks", - "索引文件不存在,将不使用索引继续推理:%s": "İndeks dosyası mevcut değil; çıkarım indeks kullanılmadan devam edecek: %s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "Geçersiz indeks: şunu kullanın added_xxxx.index, not trained_xxxx.index", - "索引检索失败": "İndeks araması başarısız", - "索引检索失败或未启用": "İndeks araması başarısız veya devre dışı", - "索引训练": "İndeks eğitimi", - "耗时": "Geçen süre", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "Geçen süre: features=%.3fs, index=%.3fs, pitch=%.3fs, model=%.3fs", - "融合": "Birleştir", - "要改的模型信息": "Düzenlenecek model bilgileri:", - "要置入的模型信息": "Eklemek için model bilgileri:", - "训练": "Eğitim", - "训练已完成,正在保存最终模型": "Eğitim tamamlandı; son model kaydediliyor", - "训练文件列表写入完成": "Eğitim dosyası listesi yazıldı", - "训练模型": "Modeli Eğit", - "训练特征索引": "Özellik Dizinini Eğit", - "训练设备规则选择的精度:%s": "Eğitim hassasiyeti cihaz kurallarına göre seçildi: %s", - "训练轮次:{} [{:.0f}%]": "Eğitim dönemi: {} [{:.0f}%]", - "训练集子音频文件夹目录路径": "Dataset audio subfolder path", - "训练集类型": "Dataset type", - "设备类型": "Cihaz türü", - "说话人ID(0~109)": "Speaker ID (0-109)", - "说话人名称": "Speaker name", - "说话人:%s(ID:%s)": "Speaker: %s (ID: %s)", - "请上传音频文件": "Bir ses dosyası yükleyin", - "请填写输出文件夹路径": "Çıktı klasörü yolunu girin", - "请指定说话人id": "Lütfen konuşmacı/sanatçı no belirtin:", - "请选择index文件": "Lütfen .index dosyası seçin", - "请选择pth文件": "Lütfen .pth dosyası seçin", - "请选择说话人id": "Konuşmacı/Şarkıcı No seçin:", - "转换": "Dönüştür", - "输入实验名": "Deneysel adı girin:", - "输入实验名,例如:test": "Deney adı, örneğin: test", - "输入待处理音频文件夹路径": "İşlenecek ses klasörünün yolunu girin:", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "İşlenecek ses klasörünün yolunu girin (dosya yöneticisinin adres çubuğundan kopyalayın):", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "Sesin hacim zarfını ayarlayın. 0'a yakın değerler, sesin orijinal vokallerin hacmine benzer olmasını sağlar. Düşük bir değerle ses gürültüsünü maskeleyebilir ve hacmi daha doğal bir şekilde duyulabilir hale getirebilirsiniz. 1'e yaklaştıkça sürekli bir yüksek ses seviyesi elde edilir:", - "输入监听": "Girişi izle", - "输入训练文件夹路径": "Eğitim klasörünün yolunu girin:", - "输入设备": "Giriş cihazı", - "输入设备:%s:%s": "Giriş cihazı: %s:%s", - "输入降噪": "Giriş gürültü azaltma", - "输出信息": "Çıkış bilgisi", - "输出变声": "Çıkış ses dönüşümü", - "输出设备": "Çıkış cihazı", - "输出设备:%s:%s": "Çıkış cihazı: %s:%s", - "输出降噪": "Çıkış gürültü azaltma", - "输出音频(右下角三个点,点了可以下载)": "Ses dosyasını dışa aktar (indirmek için sağ alt köşedeki üç noktaya tıklayın)", - "运行中": "Çalışıyor", - "进度": "İlerleme", - "选择.index文件": ".index dosyası seç", - "选择.pth文件": ".pth dosyası seç", - "选择多说话人音色": "Select multi-speaker voice", - "选择模型": "Model seçin", - "选择索引": "İndeks seçin", - "选择音高提取算法": "Perde çıkarma algoritmasını seçin", - "采样率:": "Örnekleme hızı:", - "采样长度": "Örnekleme uzunluğu", - "重复次数": "Repeat count", - "重载设备列表": "Cihaz listesini yeniden yükle", - "音调设置": "Pitch ayarları", - "音频设备": "Ses cihazı", - "音高全部为0,该音频无意义,跳过:%s": "Tüm perde değerleri sıfır; bu ses kullanılamaz ve atlanacak: %s", - "音高算法": "Perde algoritması", - "额外推理时长": "Ekstra çıkartma süresi" -} diff --git a/i18n/locale/zh_CN.json b/i18n/locale/zh_CN.json deleted file mode 100644 index 6cc75150b09004bdc82697505f79fea49d92c651..0000000000000000000000000000000000000000 --- a/i18n/locale/zh_CN.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s运行中,请先停止该任务", - "====> 轮次:{} {}": "====> 轮次:{} {}", - "A模型权重": "A模型权重", - "A模型路径": "A模型路径", - "B模型路径": "B模型路径", - "CUDA Graph预热完成": "CUDA Graph预热完成", - "CUDA可用:%s": "CUDA可用:%s", - "输入训练文件夹路径,例如:E:\\我的训练集": "输入训练文件夹路径,例如:E:\\我的训练集", - "F0与HuBERT特征提取": "F0与HuBERT特征提取", - "F0提取": "F0提取", - "F0提取没有生成有效结果,已停止训练": "F0提取没有生成有效结果,已停止训练", - "HuBERT特征": "HuBERT特征", - "HuBERT特征提取没有生成有效结果,已停止训练": "HuBERT特征提取没有生成有效结果,已停止训练", - "Index Rate": "检索特征占比", - "SOLA偏移:%d": "SOLA偏移:%d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s", - "[F0提取] 待处理:%s": "[F0提取] 待处理:%s", - "[F0提取] 无待处理音频,已全部跳过": "[F0提取] 无待处理音频,已全部跳过", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s", - "[F0提取][失败] %s": "[F0提取][失败] %s", - "[F0提取][失败] %s\n%s": "[F0提取][失败] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[HuBERT特征] 无待处理音频,已全部跳过:%s", - "[HuBERT特征] 正在加载模型:%s": "[HuBERT特征] 正在加载模型:%s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[HuBERT特征][失败] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[HuBERT特征][失败] %s 包含NaN", - "[HuBERT特征][失败] 模型不存在:%s": "[HuBERT特征][失败] 模型不存在:%s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[数据切分] 多说话人待处理:%s | 进程数:%s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[数据切分] 子任务完成 | 成功:%s | 失败:%s", - "[数据切分] 完成": "[数据切分] 完成", - "[数据切分] 开始": "[数据切分] 开始", - "[数据切分] 待处理:%s | 进程数:%s": "[数据切分] 待处理:%s | 进程数:%s", - "[数据切分] 进度:%s/%s | %s": "[数据切分] 进度:%s/%s | %s", - "[数据切分][失败] %s": "[数据切分][失败] %s", - "[数据切分][失败] %s\n%s": "[数据切分][失败] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s", - "[索引训练] 写入进度:%s/%s": "[索引训练] 写入进度:%s/%s", - "[索引训练] 外部索引链接已存在:%s": "[索引训练] 外部索引链接已存在:%s", - "[索引训练] 已链接索引到外部目录:%s": "[索引训练] 已链接索引到外部目录:%s", - "[索引训练] 成功构建索引:%s": "[索引训练] 成功构建索引:%s", - "[索引训练] 正在写入特征向量": "[索引训练] 正在写入特征向量", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[索引训练] 正在将%s条特征聚类为10000个中心", - "[索引训练] 正在训练索引": "[索引训练] 正在训练索引", - "[索引训练] 特征形状:%s | IVF数量:%s": "[索引训练] 特征形状:%s | IVF数量:%s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[索引训练][失败] 无法链接索引到外部目录:%s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s", - "[索引训练][失败] 请先进行特征提取": "[索引训练][失败] 请先进行特征提取", - "[索引训练][跳过] added索引已存在:%s": "[索引训练][跳过] added索引已存在:%s", - "[索引训练][跳过] trained索引已存在:%s": "[索引训练][跳过] trained索引已存在:%s", - "ckpt处理": "ckpt处理", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2", - "index文件路径不可包含中文": "index文件路径不可包含中文", - "pth文件路径不可包含中文": "pth文件路径不可包含中文", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。", - "step2b: 音高与hubert语义特征提取": "step2b: 音高与hubert语义特征提取", - "step3: 填写训练设置, 开始训练模型和索引": "step3: 填写训练设置, 开始训练模型和索引", - "……仅显示最近10条失败记录": "……仅显示最近10条失败记录", - "……已省略前%s行,仅显示最新状态": "……已省略前%s行,仅显示最新状态", - "一键训练": "一键训练", - "上一页": "上一页", - "下一页": "下一页", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。", - "主结果文件夹": "主结果文件夹", - "也可批量输入音频文件, 二选一, 优先读文件夹": "也可批量输入音频文件, 二选一, 优先读文件夹", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "人声、伴奏与混响批量处理,使用pymss/MSST模型。", - "人声伴奏分离&去混响": "人声伴奏分离&去混响", - "仅支持pm和rmvpe音高提取算法": "仅支持pm和rmvpe音高提取算法", - "从训练检查点提取的模型": "从训练检查点提取的模型", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2", - "以下行填写不完整或无效,已忽略:%s": "以下行填写不完整或无效,已忽略:%s", - "任务": "任务", - "使用显卡:%s": "使用显卡:%s", - "使用模型采样率": "使用模型采样率", - "使用设备采样率": "使用设备采样率", - "保存名": "保存名", - "保存的文件名, 默认空为和源文件同名": "保存的文件名, 默认空为和源文件同名", - "保存的模型名不带后缀": "保存的模型名不带后缀", - "保存频率save_every_epoch": "保存频率save_every_epoch", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果", - "修改": "修改", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "修改模型信息(仅支持weights文件夹下提取的小模型文件)", - "停止一键训练": "停止一键训练", - "停止分离": "停止分离", - "停止处理数据": "停止处理数据", - "停止特征提取": "停止特征提取", - "停止训练模型": "停止训练模型", - "停止训练索引": "停止训练索引", - "停止音频转换": "停止音频转换", - "分离残余文件夹": "分离残余文件夹", - "删除末行": "删除末行", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "刷新音色列表", - "加载模型": "加载模型", - "加载预训练底模D路径": "加载预训练底模D路径", - "加载预训练底模G路径": "加载预训练底模G路径", - "单次推理": "单次推理", - "单说话人": "单说话人", - "卸载音色省显存": "卸载音色省显存", - "变调(整数, 半音数量, 升八度12降八度-12)": "变调(整数, 半音数量, 升八度12降八度-12)", - "合成": "合成", - "后处理重采样至最终采样率,0为不进行重采样": "后处理重采样至最终采样率,0为不进行重采样", - "否": "否", - "响应阈值": "响应阈值", - "响度因子": "响度因子", - "处理中": "处理中", - "处理数据": "处理数据", - "处理方式": "处理方式", - "多说话人": "多说话人", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "注意:多说话人训练音色还原度不一定有单说话人分开训练好!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。", - "多说话人训练集总文件夹不存在:%s": "多说话人训练集总文件夹不存在:%s", - "多说话人训练集总文件夹中没有有效音频": "多说话人训练集总文件夹中没有有效音频", - "多说话人训练集总文件夹中没有直接子文件夹": "多说话人训练集总文件夹中没有直接子文件夹", - "多说话人训练集总文件夹路径": "多说话人训练集总文件夹路径", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹", - "多说话人训练集清单包含无效条目:%s": "多说话人训练集清单包含无效条目:%s", - "多说话人训练集清单存在重复输出标识:%s": "多说话人训练集清单存在重复输出标识:%s", - "多说话人训练集清单已保存:%s;有效音频%s个": "多说话人训练集清单已保存:%s;有效音频%s个", - "多说话人训练集清单格式错误": "多说话人训练集清单格式错误", - "多说话人训练集清单没有有效音频": "多说话人训练集清单没有有效音频", - "多说话人训练集辅助": "多说话人训练集辅助", - "失败": "失败", - "失败记录": "失败记录", - "子进程执行失败,返回码:%s": "子进程执行失败,返回码:%s", - "实验名不能为空": "实验名不能为空", - "导出文件格式": "导出文件格式", - "已停止": "已停止", - "已加载判别器预训练模型:%s": "已加载判别器预训练模型:%s", - "已加载生成器预训练模型:%s": "已加载生成器预训练模型:%s", - "已启用索引检索": "已启用索引检索", - "已完成": "已完成", - "已完成阶段": "已完成阶段", - "已恢复判别器检查点": "已恢复判别器检查点", - "已成功": "已成功", - "常见问题解答": "常见问题解答", - "常规设置": "常规设置", - "底层模型": "底层模型", - "开始音频转换": "开始音频转换", - "当前": "当前", - "当前设备:%s | 推理精度:%s": "当前设备:%s | 推理精度:%s", - "当前阶段": "当前阶段", - "很遗憾您这没有能用的显卡来支持您训练": "很遗憾您这没有能用的显卡来支持您训练", - "性别因子/声线粗细": "性别因子/声线粗细", - "性能设置": "性能设置", - "总训练轮数total_epoch": "总训练轮数total_epoch", - "成功": "成功", - "执行命令": "执行命令", - "批量推理": "批量推理", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ", - "拖拽或点击上传待处理音频": "拖拽或点击上传待处理音频", - "指定输出文件夹": "指定输出文件夹", - "推理时间(ms):": "推理时间(ms):", - "推理耗时:%.2f秒": "推理耗时:%.2f秒", - "推理音色": "推理音色", - "提交训练集清单": "提交训练集清单", - "提取": "提取", - "提取音高和处理数据使用的CPU进程数": "提取音高和处理数据使用的CPU进程数", - "数据切分": "数据切分", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "数据切分没有生成16k音频,已停止后续特征提取和训练", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "数据切分没有生成有效训练音频,请检查训练集和数据切分日志", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "数据切分输出文件不匹配,已停止后续特征提取和训练", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "数据提取结束:end_time=%.6f,总耗时=%.3f秒", - "新增一行": "新增一行", - "无法停止": "无法停止", - "是": "是", - "是否仅保存最新的ckpt文件以节省硬盘空间": "是否仅保存最新的ckpt文件以节省硬盘空间", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "是否在每次保存时间点将最终小模型保存至weights文件夹", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速", - "显卡信息": "显卡信息", - "未使用": "未使用", - "未使用判别器预训练模型": "未使用判别器预训练模型", - "未使用生成器预训练模型": "未使用生成器预训练模型", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "未检测到可用显卡,将使用CPU训练,耗时可能较长", - "未运行": "未运行", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.", - "查看": "查看", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "查看模型信息(仅支持weights文件夹下提取的小模型文件)", - "检索特征占比": "检索特征占比", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s", - "模型推理": "模型推理", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况", - "模型是否带音高指导": "模型是否带音高指导", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "模型是否带音高指导(唱歌一定要, 语音可以不要)", - "模型是否带音高指导,1是0否": "模型是否带音高指导,1是0否", - "模型版本型号": "模型版本型号", - "模型融合, 可用于测试音色融合": "模型融合, 可用于测试音色融合", - "模型融合失败:两个模型的结构不一致": "模型融合失败:两个模型的结构不一致", - "模型训练": "模型训练", - "模型路径": "模型路径", - "正在保存最终检查点:%s": "正在保存最终检查点:%s", - "正在保存检查点 %s_e%s:%s": "正在保存检查点 %s_e%s:%s", - "正在加载RMVPE模型": "正在加载RMVPE模型", - "正在加载模型": "正在加载模型", - "正在启动": "正在启动", - "正在收尾": "正在收尾", - "正在预热CUDA Graph": "正在预热CUDA Graph", - "每张显卡的batch_size": "每张显卡的batch_size", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "没有可用于训练的有效音频,请先完成数据切分和特征提取", - "没有有效的多说话人训练集行": "没有有效的多说话人训练集行", - "淡入淡出长度": "淡入淡出长度", - "清理模型缓存": "清理模型缓存", - "版本": "版本", - "特征": "特征", - "特征提取": "特征提取", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "特征检索库文件路径(选择模型后自动匹配,可手动修改)", - "状态": "状态", - "独占 WASAPI 设备": "独占 WASAPI 设备", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "留空则使用辅助页已提交的清单", - "目标采样率": "目标采样率", - "第%s/%s页,共%s行": "第%s/%s页,共%s行", - "等待中": "等待中", - "等待输入": "等待输入", - "算法延迟(ms):": "算法延迟(ms):", - "索引": "索引", - "索引文件不存在,将不使用索引继续推理:%s": "索引文件不存在,将不使用索引继续推理:%s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index", - "索引检索失败": "索引检索失败", - "索引检索失败或未启用": "索引检索失败或未启用", - "索引训练": "索引训练", - "耗时": "耗时", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒", - "融合": "融合", - "要改的模型信息": "要改的模型信息", - "要置入的模型信息": "要置入的模型信息", - "训练": "训练", - "训练已完成,正在保存最终模型": "训练已完成,正在保存最终模型", - "训练文件列表写入完成": "训练文件列表写入完成", - "训练模型": "训练模型", - "训练特征索引": "训练特征索引", - "训练设备规则选择的精度:%s": "训练设备规则选择的精度:%s", - "训练轮次:{} [{:.0f}%]": "训练轮次:{} [{:.0f}%]", - "训练集子音频文件夹目录路径": "训练集子音频文件夹目录路径", - "训练集类型": "训练集类型", - "设备类型": "设备类型", - "说话人ID(0~109)": "说话人ID(0~109)", - "说话人名称": "说话人名称", - "说话人:%s(ID:%s)": "说话人:%s(ID:%s)", - "请上传音频文件": "请上传音频文件", - "请填写输出文件夹路径": "请填写输出文件夹路径", - "请指定说话人id": "请指定说话人id", - "请选择index文件": "请选择index文件", - "请选择pth文件": "请选择pth文件", - "请选择说话人id": "请选择说话人id", - "转换": "转换", - "输入实验名": "输入实验名", - "输入实验名,例如:test": "输入实验名,例如:test", - "输入待处理音频文件夹路径": "输入待处理音频文件夹路径", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络", - "输入监听": "输入监听", - "输入训练文件夹路径": "输入训练文件夹路径", - "输入设备": "输入设备", - "输入设备:%s:%s": "输入设备:%s:%s", - "输入降噪": "输入降噪", - "输出信息": "输出信息", - "输出变声": "输出变声", - "输出设备": "输出设备", - "输出设备:%s:%s": "输出设备:%s:%s", - "输出降噪": "输出降噪", - "输出音频(右下角三个点,点了可以下载)": "输出音频(右下角三个点,点了可以下载)", - "运行中": "运行中", - "进度": "进度", - "选择.index文件": "选择.index文件", - "选择.pth文件": "选择.pth文件", - "选择多说话人音色": "选择多说话人音色", - "选择模型": "选择模型", - "选择索引": "选择索引", - "选择音高提取算法": "选择音高提取算法", - "采样率:": "采样率:", - "采样长度": "采样长度", - "重复次数": "重复次数", - "重载设备列表": "重载设备列表", - "音调设置": "音调设置", - "音频设备": "音频设备", - "音高全部为0,该音频无意义,跳过:%s": "音高全部为0,该音频无意义,跳过:%s", - "音高算法": "音高算法", - "额外推理时长": "额外推理时长" -} diff --git a/i18n/locale/zh_HK.json b/i18n/locale/zh_HK.json deleted file mode 100644 index d94d461fd4a6bbeed81a86d305d992d0309a9486..0000000000000000000000000000000000000000 --- a/i18n/locale/zh_HK.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s运行中,请先停止该任务", - "====> 轮次:{} {}": "====> 輪次:{} {}", - "A模型权重": "A模型權重", - "A模型路径": "A模型路徑", - "B模型路径": "B模型路徑", - "CUDA Graph预热完成": "CUDA Graph 預熱完成", - "CUDA可用:%s": "CUDA可用:%s", - "输入训练文件夹路径,例如:E:\\我的训练集": "輸入訓練資料夾路徑,例如:E:\\我的訓練集", - "F0与HuBERT特征提取": "F0與HuBERT特徵提取", - "F0提取": "F0提取", - "F0提取没有生成有效结果,已停止训练": "F0提取沒有產生有效結果,已停止訓練", - "HuBERT特征": "HuBERT特徵", - "HuBERT特征提取没有生成有效结果,已停止训练": "HuBERT特徵提取沒有產生有效結果,已停止訓練", - "Index Rate": "Index Rate", - "SOLA偏移:%d": "SOLA偏移:%d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[F0提取] 完成 | 成功:%s | 跳過:%s | 失敗:%s", - "[F0提取] 待处理:%s": "[F0提取] 待处理:%s", - "[F0提取] 无待处理音频,已全部跳过": "[F0提取] 無待处理音頻,已全部跳過", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[F0提取] 進度:%s/%s | 成功:%s | 跳過:%s | %s", - "[F0提取][失败] %s": "[F0提取][失敗] %s", - "[F0提取][失败] %s\n%s": "[F0提取][失敗] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[HuBERT特徵] 完成 | 成功:%s | 跳過:%s | 失敗:%s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[HuBERT特徵] 無待处理音頻,已全部跳過:%s", - "[HuBERT特征] 正在加载模型:%s": "[HuBERT特徵] 正在載入模型:%s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[HuBERT特徵] 设备:%s | 待处理:%s | 已跳過:%s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[HuBERT特徵] 進度:%s/%s | 成功:%s | 失敗:%s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[HuBERT特徵][失敗] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[HuBERT特徵][失敗] %s 包含NaN", - "[HuBERT特征][失败] 模型不存在:%s": "[HuBERT特徵][失敗] 模型不存在:%s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[数据切分] 多说话人待处理:%s | 进程数:%s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[數據切分] 子任务完成 | 成功:%s | 失敗:%s", - "[数据切分] 完成": "[數據切分] 完成", - "[数据切分] 开始": "[數據切分] 开始", - "[数据切分] 待处理:%s | 进程数:%s": "[數據切分] 待处理:%s | 進程数:%s", - "[数据切分] 进度:%s/%s | %s": "[數據切分] 進度:%s/%s | %s", - "[数据切分][失败] %s": "[數據切分][失敗] %s", - "[数据切分][失败] %s\n%s": "[數據切分][失敗] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[數據切分][跳過] 無效或異常音頻片段:%s_%s | 峰值:%s", - "[索引训练] 写入进度:%s/%s": "[索引訓練] 写入進度:%s/%s", - "[索引训练] 外部索引链接已存在:%s": "[索引訓練] 外部索引連結已存在:%s", - "[索引训练] 已链接索引到外部目录:%s": "[索引訓練] 已連結索引到外部目录:%s", - "[索引训练] 成功构建索引:%s": "[索引訓練] 成功构建索引:%s", - "[索引训练] 正在写入特征向量": "[索引訓練] 正在写入特徵向量", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[索引訓練] 正在将%s條特徵聚类為10000个中心", - "[索引训练] 正在训练索引": "[索引訓練] 正在訓練索引", - "[索引训练] 特征形状:%s | IVF数量:%s": "[索引訓練] 特徵形状:%s | IVF數量:%s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[索引訓練][失敗] 無法連結索引到外部目录:%s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[索引訓練][失敗] 聚类失敗,将使用原始特徵繼續\n%s", - "[索引训练][失败] 请先进行特征提取": "[索引訓練][失敗] 请先進行特徵提取", - "[索引训练][跳过] added索引已存在:%s": "[索引訓練][跳過] added索引已存在:%s", - "[索引训练][跳过] trained索引已存在:%s": "[索引訓練][跳過] trained索引已存在:%s", - "ckpt处理": "ckpt處理", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2", - "index文件路径不可包含中文": "index文件路径不可包含中文", - "pth文件路径不可包含中文": "pth文件路径不可包含中文", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "rmvpe卡號配置:以-分隔輸入使用的不同進程卡號,例如0-0-1使用在卡0上跑2個進程並在卡1上跑1個進程", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "step1:填寫實驗配置。實驗數據放在logs下,每個實驗一個資料夾,需手動輸入實驗名路徑,內含實驗配置、日誌、訓練得到的模型檔案。", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。", - "step2b: 音高与hubert语义特征提取": "步驟2b: 音高與hubert語義特徵提取", - "step3: 填写训练设置, 开始训练模型和索引": "步驟3: 填寫訓練設定, 開始訓練模型和索引", - "……仅显示最近10条失败记录": "……僅顯示最近10條失敗記錄", - "……已省略前%s行,仅显示最新状态": "……已省略前%s行,僅顯示最新状态", - "一键训练": "一鍵訓練", - "上一页": "上一页", - "下一页": "下一页", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。", - "主结果文件夹": "主要結果資料夾", - "也可批量输入音频文件, 二选一, 优先读文件夹": "也可批量输入音频文件, 二选一, 优先读文件夹", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "使用 pymss/MSST 模型批次處理人聲、伴奏與混響。", - "人声伴奏分离&去混响": "人聲伴奏分離&去混響", - "仅支持pm和rmvpe音高提取算法": "僅支援pm和rmvpe音高提取算法", - "从训练检查点提取的模型": "从訓練检查点提取的模型", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "以-分隔輸入使用的卡號, 例如 0-1-2 使用卡0和卡1和卡2", - "以下行填写不完整或无效,已忽略:%s": "以下行填写不完整或无效,已忽略:%s", - "任务": "任务", - "使用显卡:%s": "使用顯示卡:%s", - "使用模型采样率": "使用模型采样率", - "使用设备采样率": "使用设备采样率", - "保存名": "儲存名", - "保存的文件名, 默认空为和源文件同名": "儲存的檔案名,預設空為與來源檔案同名", - "保存的模型名不带后缀": "儲存的模型名不帶副檔名", - "保存频率save_every_epoch": "保存頻率save_every_epoch", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "保護清輔音和呼吸聲,防止電音撕裂等artifact,拉滿0.5不開啟,調低加大保護力度但可能降低索引效果", - "修改": "修改", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "修改模型資訊(僅支援weights資料夾下提取的小模型檔案)", - "停止一键训练": "停止一鍵訓練", - "停止分离": "停止分離", - "停止处理数据": "停止處理資料", - "停止特征提取": "停止特徵擷取", - "停止训练模型": "停止訓練模型", - "停止训练索引": "停止訓練索引", - "停止音频转换": "停止音訊轉換", - "分离残余文件夹": "分離殘餘資料夾", - "删除末行": "删除末行", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "判别器预訓練模型不存在,将不使用:assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "重新整理音色列表", - "加载模型": "載入模型", - "加载预训练底模D路径": "加載預訓練底模D路徑", - "加载预训练底模G路径": "加載預訓練底模G路徑", - "单次推理": "单次推理", - "单说话人": "单说话人", - "卸载音色省显存": "卸載音色節省 VRAM", - "变调(整数, 半音数量, 升八度12降八度-12)": "變調(整數、半音數量、升八度12降八度-12)", - "合成": "合成", - "后处理重采样至最终采样率,0为不进行重采样": "後處理重採樣至最終採樣率,0為不進行重採樣", - "否": "否", - "响应阈值": "響應閾值", - "响度因子": "響度因子", - "处理中": "處理中", - "处理数据": "處理資料", - "处理方式": "處理方式", - "多说话人": "多说话人", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "注意:多說話人訓練的音色還原度未必及逐個說話人分開訓練!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。", - "多说话人训练集总文件夹不存在:%s": "多说话人训练集总文件夹不存在:%s", - "多说话人训练集总文件夹中没有有效音频": "多说话人训练集总文件夹中没有有效音频", - "多说话人训练集总文件夹中没有直接子文件夹": "多说话人训练集总文件夹中没有直接子文件夹", - "多说话人训练集总文件夹路径": "多说话人训练集总文件夹路径", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹", - "多说话人训练集清单包含无效条目:%s": "多说话人训练集清单包含无效条目:%s", - "多说话人训练集清单存在重复输出标识:%s": "多说话人训练集清单存在重复输出标识:%s", - "多说话人训练集清单已保存:%s;有效音频%s个": "多说话人训练集清单已保存:%s;有效音频%s个", - "多说话人训练集清单格式错误": "多说话人训练集清单格式错误", - "多说话人训练集清单没有有效音频": "多说话人训练集清单没有有效音频", - "多说话人训练集辅助": "多说话人训练集辅助", - "失败": "失敗", - "失败记录": "失敗記錄", - "子进程执行失败,返回码:%s": "子進程执行失敗,返回码:%s", - "实验名不能为空": "实验名不能为空", - "导出文件格式": "導出檔格式", - "已停止": "已停止", - "已加载判别器预训练模型:%s": "已載入判别器预訓練模型:%s", - "已加载生成器预训练模型:%s": "已載入生成器预訓練模型:%s", - "已启用索引检索": "已启用索引检索", - "已完成": "已完成", - "已完成阶段": "已完成階段", - "已恢复判别器检查点": "已恢复判别器检查点", - "已成功": "已成功", - "常见问题解答": "常見問題解答", - "常规设置": "一般設定", - "底层模型": "底層模型", - "开始音频转换": "開始音訊轉換", - "当前": "目前", - "当前设备:%s | 推理精度:%s": "目前裝置:%s | 推理精度:%s", - "当前阶段": "目前阶段", - "很遗憾您这没有能用的显卡来支持您训练": "很遗憾您这没有能用的显卡来支持您训练", - "性别因子/声线粗细": "性別因子/聲線粗細", - "性能设置": "效能設定", - "总训练轮数total_epoch": "總訓練輪數total_epoch", - "成功": "成功", - "执行命令": "执行命令", - "批量推理": "批量推理", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "批量轉換,輸入待轉換音頻資料夾,或上傳多個音頻檔案,在指定資料夾(默認opt)下輸出轉換的音頻。", - "拖拽或点击上传待处理音频": "拖放或按一下上載待處理音訊", - "指定输出文件夹": "指定輸出資料夾", - "推理时间(ms):": "推理時間(ms):", - "推理耗时:%.2f秒": "推理耗时:%.2f秒", - "推理音色": "推理音色", - "提交训练集清单": "提交训练集清单", - "提取": "提取", - "提取音高和处理数据使用的CPU进程数": "提取音高和處理數據使用的CPU進程數", - "数据切分": "數據切分", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "資料切分沒有產生16k音訊,已停止後續特徵提取和訓練", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "資料切分沒有產生有效訓練音訊,請檢查訓練集和資料切分日誌", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "資料切分輸出檔案不匹配,已停止後續特徵提取和訓練", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "資料擷取開始:start_time=%.6f,請求並行數=%s,實際並行數上限=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "資料擷取結束:end_time=%.6f,總耗時=%.3f秒", - "新增一行": "新增一行", - "无法停止": "無法停止", - "是": "是", - "是否仅保存最新的ckpt文件以节省硬盘空间": "是否僅保存最新的ckpt檔案以節省硬碟空間", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "是否在每次保存時間點將最終小模型保存至weights檔夾", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "是否緩存所有訓練集至 VRAM。小於10分鐘的小數據可緩存以加速訓練,大數據緩存會爆 VRAM 也加不了多少速度", - "显卡信息": "顯示卡資訊", - "未使用": "未使用", - "未使用判别器预训练模型": "未使用判别器预訓練模型", - "未使用生成器预训练模型": "未使用生成器预訓練模型", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "未偵測到可用顯示卡,将使用CPU訓練,耗时可能较长", - "未运行": "未运行", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "本軟體以MIT協議開源,作者不對軟體具備任何控制力,使用軟體者、傳播軟體導出的聲音者自負全責。
如不認可該條款,則不能使用或引用軟體包內任何程式碼和檔案。詳見根目錄使用需遵守的協議-LICENSE.txt。", - "查看": "查看", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "查看模型資訊(僅支援weights資料夾下提取的小模型檔案)", - "检索特征占比": "檢索特徵佔比", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "模型資訊:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s", - "模型推理": "模型推理", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "模型提取(輸入logs資料夾下大檔案模型路徑),適用於訓一半不想訓了模型沒有自動提取儲存小檔案模型,或者想測試中間模型的情況", - "模型是否带音高指导": "模型是否帶音高指導", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "模型是否帶音高指導(唱歌一定要,語音可以不要)", - "模型是否带音高指导,1是0否": "模型是否帶音高指導,1是0否", - "模型版本型号": "模型版本型號", - "模型融合, 可用于测试音色融合": "模型融合,可用於測試音色融合", - "模型融合失败:两个模型的结构不一致": "模型融合失敗:两个模型的结构不一致", - "模型训练": "模型訓練", - "模型路径": "模型路徑", - "正在保存最终检查点:%s": "正在儲存最终检查点:%s", - "正在保存检查点 %s_e%s:%s": "正在儲存检查点 %s_e%s:%s", - "正在加载RMVPE模型": "正在載入RMVPE模型", - "正在加载模型": "正在載入模型", - "正在启动": "正在启动", - "正在收尾": "正在收尾", - "正在预热CUDA Graph": "正在預熱 CUDA Graph", - "每张显卡的batch_size": "每张显卡的batch_size", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "沒有可用於訓練的有效音訊,請先完成資料切分和特徵提取", - "没有有效的多说话人训练集行": "没有有效的多说话人训练集行", - "淡入淡出长度": "淡入淡出長度", - "清理模型缓存": "清理模型缓存", - "版本": "版本", - "特征": "特徵", - "特征提取": "特徵提取", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "特徵索引庫檔案路徑(選擇模型後自動配對,可手動修改)", - "状态": "状态", - "独占 WASAPI 设备": "独占 WASAPI 设备", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "生成器预訓練模型不存在,将不使用:assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "留空则使用辅助页已提交的清单", - "目标采样率": "目標取樣率", - "第%s/%s页,共%s行": "第%s/%s页,共%s行", - "等待中": "等待中", - "等待输入": "等待輸入", - "算法延迟(ms):": "算法延迟(ms):", - "索引": "索引", - "索引文件不存在,将不使用索引继续推理:%s": "索引檔案不存在,將不使用索引繼續推理:%s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "索引無效:必须使用added_xxxx.index,不能使用trained_xxxx.index", - "索引检索失败": "索引检索失敗", - "索引检索失败或未启用": "索引检索失敗或未启用", - "索引训练": "索引訓練", - "耗时": "耗时", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "耗时:特徵=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒", - "融合": "融合", - "要改的模型信息": "要改的模型資訊", - "要置入的模型信息": "要置入的模型資訊", - "训练": "訓練", - "训练已完成,正在保存最终模型": "訓練已完成,正在儲存最终模型", - "训练文件列表写入完成": "訓練檔案列表写入完成", - "训练模型": "訓練模型", - "训练特征索引": "訓練特徵索引", - "训练设备规则选择的精度:%s": "訓練设备规则选择的精度:%s", - "训练轮次:{} [{:.0f}%]": "訓練輪次:{} [{:.0f}%]", - "训练集子音频文件夹目录路径": "训练集子音频文件夹目录路径", - "训练集类型": "训练集类型", - "设备类型": "设备类型", - "说话人ID(0~109)": "说话人ID(0~109)", - "说话人名称": "说话人名称", - "说话人:%s(ID:%s)": "说话人:%s(ID:%s)", - "请上传音频文件": "请上传音頻檔案", - "请填写输出文件夹路径": "请填写輸出資料夾路径", - "请指定说话人id": "請指定說話人id", - "请选择index文件": "请选择index文件", - "请选择pth文件": "请选择pth文件", - "请选择说话人id": "請選擇說話人ID", - "转换": "轉換", - "输入实验名": "輸入實驗名稱", - "输入实验名,例如:test": "輸入實驗名稱,例如:test", - "输入待处理音频文件夹路径": "輸入待處理音頻資料夾路徑", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "輸入待處理音頻資料夾路徑(去檔案管理器地址欄拷貝即可)", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "輸入源音量包絡替換輸出音量包絡融合比例,越靠近1越使用輸出包絡", - "输入监听": "输入监听", - "输入训练文件夹路径": "輸入訓練檔案夾路徑", - "输入设备": "輸入設備", - "输入设备:%s:%s": "輸入设备:%s:%s", - "输入降噪": "輸入降噪", - "输出信息": "輸出訊息", - "输出变声": "输出变声", - "输出设备": "輸出設備", - "输出设备:%s:%s": "輸出设备:%s:%s", - "输出降噪": "輸出降噪", - "输出音频(右下角三个点,点了可以下载)": "輸出音頻(右下角三個點,點了可以下載)", - "运行中": "运行中", - "进度": "進度", - "选择.index文件": "選擇 .index 檔案", - "选择.pth文件": "選擇 .pth 檔案", - "选择多说话人音色": "选择多说话人音色", - "选择模型": "选择模型", - "选择索引": "选择索引", - "选择音高提取算法": "選擇音高擷取演算法", - "采样率:": "采样率:", - "采样长度": "取樣長度", - "重复次数": "重复次数", - "重载设备列表": "重載設備列表", - "音调设置": "音調設定", - "音频设备": "音訊設備", - "音高全部为0,该音频无意义,跳过:%s": "音高全部為0,该音頻無意义,跳過:%s", - "音高算法": "音高演算法", - "额外推理时长": "額外推理時長" -} diff --git a/i18n/locale/zh_SG.json b/i18n/locale/zh_SG.json deleted file mode 100644 index 6760c6fa35d204ef12416bf83f9bb3585ab39ba8..0000000000000000000000000000000000000000 --- a/i18n/locale/zh_SG.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s运行中,请先停止该任务", - "====> 轮次:{} {}": "====> 轮次:{} {}", - "A模型权重": "A模型權重", - "A模型路径": "A模型路徑", - "B模型路径": "B模型路徑", - "CUDA Graph预热完成": "CUDA Graph预热完成", - "CUDA可用:%s": "CUDA可用:%s", - "输入训练文件夹路径,例如:E:\\我的训练集": "输入训练文件夹路径,例如:E:\\我的训练集", - "F0与HuBERT特征提取": "F0与HuBERT特征提取", - "F0提取": "F0提取", - "F0提取没有生成有效结果,已停止训练": "F0提取没有生成有效结果,已停止训练", - "HuBERT特征": "HuBERT特征", - "HuBERT特征提取没有生成有效结果,已停止训练": "HuBERT特征提取没有生成有效结果,已停止训练", - "Index Rate": "Index Rate", - "SOLA偏移:%d": "SOLA偏移:%d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s", - "[F0提取] 待处理:%s": "[F0提取] 待处理:%s", - "[F0提取] 无待处理音频,已全部跳过": "[F0提取] 无待处理音频,已全部跳过", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s", - "[F0提取][失败] %s": "[F0提取][失败] %s", - "[F0提取][失败] %s\n%s": "[F0提取][失败] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[HuBERT特征] 无待处理音频,已全部跳过:%s", - "[HuBERT特征] 正在加载模型:%s": "[HuBERT特征] 正在加载模型:%s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[HuBERT特征][失败] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[HuBERT特征][失败] %s 包含NaN", - "[HuBERT特征][失败] 模型不存在:%s": "[HuBERT特征][失败] 模型不存在:%s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[数据切分] 多说话人待处理:%s | 进程数:%s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[数据切分] 子任务完成 | 成功:%s | 失败:%s", - "[数据切分] 完成": "[数据切分] 完成", - "[数据切分] 开始": "[数据切分] 开始", - "[数据切分] 待处理:%s | 进程数:%s": "[数据切分] 待处理:%s | 进程数:%s", - "[数据切分] 进度:%s/%s | %s": "[数据切分] 进度:%s/%s | %s", - "[数据切分][失败] %s": "[数据切分][失败] %s", - "[数据切分][失败] %s\n%s": "[数据切分][失败] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s", - "[索引训练] 写入进度:%s/%s": "[索引训练] 写入进度:%s/%s", - "[索引训练] 外部索引链接已存在:%s": "[索引训练] 外部索引链接已存在:%s", - "[索引训练] 已链接索引到外部目录:%s": "[索引训练] 已链接索引到外部目录:%s", - "[索引训练] 成功构建索引:%s": "[索引训练] 成功构建索引:%s", - "[索引训练] 正在写入特征向量": "[索引训练] 正在写入特征向量", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[索引训练] 正在将%s条特征聚类为10000个中心", - "[索引训练] 正在训练索引": "[索引训练] 正在训练索引", - "[索引训练] 特征形状:%s | IVF数量:%s": "[索引训练] 特征形状:%s | IVF数量:%s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[索引训练][失败] 无法链接索引到外部目录:%s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s", - "[索引训练][失败] 请先进行特征提取": "[索引训练][失败] 请先进行特征提取", - "[索引训练][跳过] added索引已存在:%s": "[索引训练][跳过] added索引已存在:%s", - "[索引训练][跳过] trained索引已存在:%s": "[索引训练][跳过] trained索引已存在:%s", - "ckpt处理": "ckpt處理", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2", - "index文件路径不可包含中文": "index文件路径不可包含中文", - "pth文件路径不可包含中文": "pth文件路径不可包含中文", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "rmvpe卡號配置:以-分隔輸入使用的不同進程卡號,例如0-0-1使用在卡0上跑2個進程並在卡1上跑1個進程", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "step1:填寫實驗配置。實驗數據放在logs下,每個實驗一個資料夾,需手動輸入實驗名路徑,內含實驗配置、日誌、訓練得到的模型檔案。", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。", - "step2b: 音高与hubert语义特征提取": "step2b: 音高与hubert语义特征提取", - "step3: 填写训练设置, 开始训练模型和索引": "步驟3: 填寫訓練設定, 開始訓練模型和索引", - "……仅显示最近10条失败记录": "……仅显示最近10条失败记录", - "……已省略前%s行,仅显示最新状态": "……已省略前%s行,仅显示最新状态", - "一键训练": "一鍵訓練", - "上一页": "上一页", - "下一页": "下一页", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。", - "主结果文件夹": "主结果文件夹", - "也可批量输入音频文件, 二选一, 优先读文件夹": "也可批量输入音频文件, 二选一, 优先读文件夹", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "人声、伴奏与混响批量处理,使用pymss/MSST模型。", - "人声伴奏分离&去混响": "人声伴奏分离&去混响", - "仅支持pm和rmvpe音高提取算法": "仅支持pm和rmvpe音高提取算法", - "从训练检查点提取的模型": "从训练检查点提取的模型", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "以-分隔輸入使用的卡號, 例如 0-1-2 使用卡0和卡1和卡2", - "以下行填写不完整或无效,已忽略:%s": "以下行填写不完整或无效,已忽略:%s", - "任务": "任务", - "使用显卡:%s": "使用显卡:%s", - "使用模型采样率": "使用模型采样率", - "使用设备采样率": "使用设备采样率", - "保存名": "儲存名", - "保存的文件名, 默认空为和源文件同名": "儲存的檔案名,預設空為與來源檔案同名", - "保存的模型名不带后缀": "儲存的模型名不帶副檔名", - "保存频率save_every_epoch": "保存頻率save_every_epoch", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "保護清輔音和呼吸聲,防止電音撕裂等artifact,拉滿0.5不開啟,調低加大保護力度但可能降低索引效果", - "修改": "修改", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "修改模型資訊(僅支援weights資料夾下提取的小模型檔案)", - "停止一键训练": "停止一键训练", - "停止分离": "停止分离", - "停止处理数据": "停止处理数据", - "停止特征提取": "停止特征提取", - "停止训练模型": "停止训练模型", - "停止训练索引": "停止训练索引", - "停止音频转换": "停止音訊轉換", - "分离残余文件夹": "分离残余文件夹", - "删除末行": "删除末行", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "刷新音色列表", - "加载模型": "載入模型", - "加载预训练底模D路径": "加載預訓練底模D路徑", - "加载预训练底模G路径": "加載預訓練底模G路徑", - "单次推理": "单次推理", - "单说话人": "单说话人", - "卸载音色省显存": "卸載音色節省 VRAM", - "变调(整数, 半音数量, 升八度12降八度-12)": "變調(整數、半音數量、升八度12降八度-12)", - "合成": "合成", - "后处理重采样至最终采样率,0为不进行重采样": "後處理重採樣至最終採樣率,0為不進行重採樣", - "否": "否", - "响应阈值": "響應閾值", - "响度因子": "響度因子", - "处理中": "处理中", - "处理数据": "處理資料", - "处理方式": "处理方式", - "多说话人": "多说话人", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "注意:多说话人训练音色还原度不一定有单说话人分开训练好!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。", - "多说话人训练集总文件夹不存在:%s": "多说话人训练集总文件夹不存在:%s", - "多说话人训练集总文件夹中没有有效音频": "多说话人训练集总文件夹中没有有效音频", - "多说话人训练集总文件夹中没有直接子文件夹": "多说话人训练集总文件夹中没有直接子文件夹", - "多说话人训练集总文件夹路径": "多说话人训练集总文件夹路径", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹", - "多说话人训练集清单包含无效条目:%s": "多说话人训练集清单包含无效条目:%s", - "多说话人训练集清单存在重复输出标识:%s": "多说话人训练集清单存在重复输出标识:%s", - "多说话人训练集清单已保存:%s;有效音频%s个": "多说话人训练集清单已保存:%s;有效音频%s个", - "多说话人训练集清单格式错误": "多说话人训练集清单格式错误", - "多说话人训练集清单没有有效音频": "多说话人训练集清单没有有效音频", - "多说话人训练集辅助": "多说话人训练集辅助", - "失败": "失败", - "失败记录": "失败记录", - "子进程执行失败,返回码:%s": "子进程执行失败,返回码:%s", - "实验名不能为空": "实验名不能为空", - "导出文件格式": "導出檔格式", - "已停止": "已停止", - "已加载判别器预训练模型:%s": "已加载判别器预训练模型:%s", - "已加载生成器预训练模型:%s": "已加载生成器预训练模型:%s", - "已启用索引检索": "已启用索引检索", - "已完成": "已完成", - "已完成阶段": "已完成阶段", - "已恢复判别器检查点": "已恢复判别器检查点", - "已成功": "已成功", - "常见问题解答": "常見問題解答", - "常规设置": "一般設定", - "底层模型": "底层模型", - "开始音频转换": "開始音訊轉換", - "当前": "当前", - "当前设备:%s | 推理精度:%s": "当前设备:%s | 推理精度:%s", - "当前阶段": "当前阶段", - "很遗憾您这没有能用的显卡来支持您训练": "很遗憾您这没有能用的显卡来支持您训练", - "性别因子/声线粗细": "性别因子/声线粗细", - "性能设置": "效能設定", - "总训练轮数total_epoch": "總訓練輪數total_epoch", - "成功": "成功", - "执行命令": "执行命令", - "批量推理": "批量推理", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "批量轉換,輸入待轉換音頻資料夾,或上傳多個音頻檔案,在指定資料夾(默認opt)下輸出轉換的音頻。", - "拖拽或点击上传待处理音频": "拖拽或点击上传待处理音频", - "指定输出文件夹": "指定輸出資料夾", - "推理时间(ms):": "推理時間(ms):", - "推理耗时:%.2f秒": "推理耗时:%.2f秒", - "推理音色": "推理音色", - "提交训练集清单": "提交训练集清单", - "提取": "提取", - "提取音高和处理数据使用的CPU进程数": "提取音高和處理數據使用的CPU進程數", - "数据切分": "数据切分", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "数据切分没有生成16k音频,已停止后续特征提取和训练", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "数据切分没有生成有效训练音频,请检查训练集和数据切分日志", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "数据切分输出文件不匹配,已停止后续特征提取和训练", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "数据提取结束:end_time=%.6f,总耗时=%.3f秒", - "新增一行": "新增一行", - "无法停止": "无法停止", - "是": "是", - "是否仅保存最新的ckpt文件以节省硬盘空间": "是否僅保存最新的ckpt檔案以節省硬碟空間", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "是否在每次保存時間點將最終小模型保存至weights檔夾", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "是否緩存所有訓練集至 VRAM。小於10分鐘的小數據可緩存以加速訓練,大數據緩存會爆 VRAM 也加不了多少速度", - "显卡信息": "顯示卡資訊", - "未使用": "未使用", - "未使用判别器预训练模型": "未使用判别器预训练模型", - "未使用生成器预训练模型": "未使用生成器预训练模型", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "未检测到可用显卡,将使用CPU训练,耗时可能较长", - "未运行": "未运行", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "本軟體以MIT協議開源,作者不對軟體具備任何控制力,使用軟體者、傳播軟體導出的聲音者自負全責。
如不認可該條款,則不能使用或引用軟體包內任何程式碼和檔案。詳見根目錄使用需遵守的協議-LICENSE.txt。", - "查看": "查看", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "查看模型資訊(僅支援weights資料夾下提取的小模型檔案)", - "检索特征占比": "檢索特徵佔比", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s", - "模型推理": "模型推理", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "模型提取(輸入logs資料夾下大檔案模型路徑),適用於訓一半不想訓了模型沒有自動提取儲存小檔案模型,或者想測試中間模型的情況", - "模型是否带音高指导": "模型是否帶音高指導", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "模型是否帶音高指導(唱歌一定要,語音可以不要)", - "模型是否带音高指导,1是0否": "模型是否帶音高指導,1是0否", - "模型版本型号": "模型版本型號", - "模型融合, 可用于测试音色融合": "模型融合,可用於測試音色融合", - "模型融合失败:两个模型的结构不一致": "模型融合失败:两个模型的结构不一致", - "模型训练": "模型训练", - "模型路径": "模型路徑", - "正在保存最终检查点:%s": "正在保存最终检查点:%s", - "正在保存检查点 %s_e%s:%s": "正在保存检查点 %s_e%s:%s", - "正在加载RMVPE模型": "正在加载RMVPE模型", - "正在加载模型": "正在加载模型", - "正在启动": "正在启动", - "正在收尾": "正在收尾", - "正在预热CUDA Graph": "正在预热CUDA Graph", - "每张显卡的batch_size": "每张显卡的batch_size", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "没有可用于训练的有效音频,请先完成数据切分和特征提取", - "没有有效的多说话人训练集行": "没有有效的多说话人训练集行", - "淡入淡出长度": "淡入淡出長度", - "清理模型缓存": "清理模型缓存", - "版本": "版本", - "特征": "特征", - "特征提取": "特徵提取", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "特征检索库文件路径(选择模型后自动匹配,可手动修改)", - "状态": "状态", - "独占 WASAPI 设备": "独占 WASAPI 设备", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "留空则使用辅助页已提交的清单", - "目标采样率": "目標取樣率", - "第%s/%s页,共%s行": "第%s/%s页,共%s行", - "等待中": "等待中", - "等待输入": "等待输入", - "算法延迟(ms):": "算法延迟(ms):", - "索引": "索引", - "索引文件不存在,将不使用索引继续推理:%s": "索引文件不存在,将不使用索引继续推理:%s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index", - "索引检索失败": "索引检索失败", - "索引检索失败或未启用": "索引检索失败或未启用", - "索引训练": "索引训练", - "耗时": "耗时", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒", - "融合": "融合", - "要改的模型信息": "要改的模型資訊", - "要置入的模型信息": "要置入的模型資訊", - "训练": "訓練", - "训练已完成,正在保存最终模型": "训练已完成,正在保存最终模型", - "训练文件列表写入完成": "训练文件列表写入完成", - "训练模型": "訓練模型", - "训练特征索引": "訓練特徵索引", - "训练设备规则选择的精度:%s": "训练设备规则选择的精度:%s", - "训练轮次:{} [{:.0f}%]": "训练轮次:{} [{:.0f}%]", - "训练集子音频文件夹目录路径": "训练集子音频文件夹目录路径", - "训练集类型": "训练集类型", - "设备类型": "设备类型", - "说话人ID(0~109)": "说话人ID(0~109)", - "说话人名称": "说话人名称", - "说话人:%s(ID:%s)": "说话人:%s(ID:%s)", - "请上传音频文件": "请上传音频文件", - "请填写输出文件夹路径": "请填写输出文件夹路径", - "请指定说话人id": "請指定說話人id", - "请选择index文件": "请选择index文件", - "请选择pth文件": "请选择pth文件", - "请选择说话人id": "請選擇說話人ID", - "转换": "轉換", - "输入实验名": "輸入實驗名稱", - "输入实验名,例如:test": "输入实验名,例如:test", - "输入待处理音频文件夹路径": "輸入待處理音頻資料夾路徑", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "輸入待處理音頻資料夾路徑(去檔案管理器地址欄拷貝即可)", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "輸入源音量包絡替換輸出音量包絡融合比例,越靠近1越使用輸出包絡", - "输入监听": "输入监听", - "输入训练文件夹路径": "輸入訓練檔案夾路徑", - "输入设备": "輸入設備", - "输入设备:%s:%s": "输入设备:%s:%s", - "输入降噪": "輸入降噪", - "输出信息": "輸出訊息", - "输出变声": "输出变声", - "输出设备": "輸出設備", - "输出设备:%s:%s": "输出设备:%s:%s", - "输出降噪": "輸出降噪", - "输出音频(右下角三个点,点了可以下载)": "輸出音頻(右下角三個點,點了可以下載)", - "运行中": "运行中", - "进度": "进度", - "选择.index文件": "選擇 .index 檔案", - "选择.pth文件": "選擇 .pth 檔案", - "选择多说话人音色": "选择多说话人音色", - "选择模型": "选择模型", - "选择索引": "选择索引", - "选择音高提取算法": "选择音高提取算法", - "采样率:": "采样率:", - "采样长度": "取樣長度", - "重复次数": "重复次数", - "重载设备列表": "重載設備列表", - "音调设置": "音調設定", - "音频设备": "音訊設備", - "音高全部为0,该音频无意义,跳过:%s": "音高全部为0,该音频无意义,跳过:%s", - "音高算法": "音高演算法", - "额外推理时长": "額外推理時長" -} diff --git a/i18n/locale/zh_TW.json b/i18n/locale/zh_TW.json deleted file mode 100644 index 82cb6e8d00df5497f6741389db4619394dbcb18a..0000000000000000000000000000000000000000 --- a/i18n/locale/zh_TW.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "%s运行中,请先停止该任务": "%s运行中,请先停止该任务", - "====> 轮次:{} {}": "====> 輪次:{} {}", - "A模型权重": "A模型權重", - "A模型路径": "A模型路徑", - "B模型路径": "B模型路徑", - "CUDA Graph预热完成": "CUDA Graph 預熱完成", - "CUDA可用:%s": "CUDA可用:%s", - "输入训练文件夹路径,例如:E:\\我的训练集": "輸入訓練資料夾路徑,例如:E:\\我的訓練集", - "F0与HuBERT特征提取": "F0與HuBERT特徵提取", - "F0提取": "F0提取", - "F0提取没有生成有效结果,已停止训练": "F0提取沒有產生有效結果,已停止訓練", - "HuBERT特征": "HuBERT特徵", - "HuBERT特征提取没有生成有效结果,已停止训练": "HuBERT特徵提取沒有產生有效結果,已停止訓練", - "Index Rate": "Index Rate", - "SOLA偏移:%d": "SOLA偏移:%d", - "[F0提取] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[F0提取] 完成 | 成功:%s | 跳過:%s | 失敗:%s", - "[F0提取] 待处理:%s": "[F0提取] 待处理:%s", - "[F0提取] 无待处理音频,已全部跳过": "[F0提取] 無待处理音頻,已全部跳過", - "[F0提取] 进度:%s/%s | 成功:%s | 跳过:%s | %s": "[F0提取] 進度:%s/%s | 成功:%s | 跳過:%s | %s", - "[F0提取][失败] %s": "[F0提取][失敗] %s", - "[F0提取][失败] %s\n%s": "[F0提取][失敗] %s\n%s", - "[HuBERT特征] 完成 | 成功:%s | 跳过:%s | 失败:%s": "[HuBERT特徵] 完成 | 成功:%s | 跳過:%s | 失敗:%s", - "[HuBERT特征] 无待处理音频,已全部跳过:%s": "[HuBERT特徵] 無待处理音頻,已全部跳過:%s", - "[HuBERT特征] 正在加载模型:%s": "[HuBERT特徵] 正在載入模型:%s", - "[HuBERT特征] 设备:%s | 待处理:%s | 已跳过:%s": "[HuBERT特徵] 设备:%s | 待处理:%s | 已跳過:%s", - "[HuBERT特征] 进度:%s/%s | 成功:%s | 失败:%s | %s | %s": "[HuBERT特徵] 進度:%s/%s | 成功:%s | 失敗:%s | %s | %s", - "[HuBERT特征][失败] %s\n%s": "[HuBERT特徵][失敗] %s\n%s", - "[HuBERT特征][失败] %s 包含NaN": "[HuBERT特徵][失敗] %s 包含NaN", - "[HuBERT特征][失败] 模型不存在:%s": "[HuBERT特徵][失敗] 模型不存在:%s", - "[数据切分] 多说话人待处理:%s | 进程数:%s": "[数据切分] 多说话人待处理:%s | 进程数:%s", - "[数据切分] 子任务完成 | 成功:%s | 失败:%s": "[數據切分] 子任务完成 | 成功:%s | 失敗:%s", - "[数据切分] 完成": "[數據切分] 完成", - "[数据切分] 开始": "[數據切分] 开始", - "[数据切分] 待处理:%s | 进程数:%s": "[數據切分] 待处理:%s | 進程数:%s", - "[数据切分] 进度:%s/%s | %s": "[數據切分] 進度:%s/%s | %s", - "[数据切分][失败] %s": "[數據切分][失敗] %s", - "[数据切分][失败] %s\n%s": "[數據切分][失敗] %s\n%s", - "[数据切分][跳过] 无效或异常音频片段:%s_%s | 峰值:%s": "[數據切分][跳過] 無效或異常音頻片段:%s_%s | 峰值:%s", - "[索引训练] 写入进度:%s/%s": "[索引訓練] 写入進度:%s/%s", - "[索引训练] 外部索引链接已存在:%s": "[索引訓練] 外部索引連結已存在:%s", - "[索引训练] 已链接索引到外部目录:%s": "[索引訓練] 已連結索引到外部目录:%s", - "[索引训练] 成功构建索引:%s": "[索引訓練] 成功构建索引:%s", - "[索引训练] 正在写入特征向量": "[索引訓練] 正在写入特徵向量", - "[索引训练] 正在将%s条特征聚类为10000个中心": "[索引訓練] 正在将%s條特徵聚类為10000个中心", - "[索引训练] 正在训练索引": "[索引訓練] 正在訓練索引", - "[索引训练] 特征形状:%s | IVF数量:%s": "[索引訓練] 特徵形状:%s | IVF數量:%s", - "[索引训练][失败] 无法链接索引到外部目录:%s\n%s": "[索引訓練][失敗] 無法連結索引到外部目录:%s\n%s", - "[索引训练][失败] 聚类失败,将使用原始特征继续\n%s": "[索引訓練][失敗] 聚类失敗,将使用原始特徵繼續\n%s", - "[索引训练][失败] 请先进行特征提取": "[索引訓練][失敗] 请先進行特徵提取", - "[索引训练][跳过] added索引已存在:%s": "[索引訓練][跳過] added索引已存在:%s", - "[索引训练][跳过] trained索引已存在:%s": "[索引訓練][跳過] trained索引已存在:%s", - "ckpt处理": "ckpt處理", - "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "hubert:以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2", - "index文件路径不可包含中文": "index文件路径不可包含中文", - "pth文件路径不可包含中文": "pth文件路径不可包含中文", - "rmvpe卡号配置:以-分隔输入使用的不同进程卡号,例如0-0-1使用在卡0上跑2个进程并在卡1上跑1个进程": "rmvpe卡號配置:以-分隔輸入使用的不同進程卡號,例如0-0-1使用在卡0上跑2個進程並在卡1上跑1個進程", - "step1: 填写实验配置. 实验数据放在logs下, 每个实验一个文件夹, 需手工输入实验名路径, 内含实验配置, 日志, 训练得到的模型文件. ": "step1:填寫實驗配置。實驗數據放在logs下,每個實驗一個資料夾,需手動輸入實驗名路徑,內含實驗配置、日誌、訓練得到的模型檔案。", - "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。": "step2a: 扫描训练音频并进行切片归一化,在实验目录下生成训练wav文件。", - "step2b: 音高与hubert语义特征提取": "步驟2b: 音高與hubert語義特徵提取", - "step3: 填写训练设置, 开始训练模型和索引": "步驟3: 填寫訓練設定, 開始訓練模型和索引", - "……仅显示最近10条失败记录": "……僅顯示最近10條失敗記錄", - "……已省略前%s行,仅显示最新状态": "……已省略前%s行,僅顯示最新状态", - "一键训练": "一鍵訓練", - "上一页": "上一页", - "下一页": "下一页", - "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。": "为多说话人训练集建立清单。空行会被忽略;路径、说话人名称、说话人ID或重复次数填写不全的行会在提交时提示。", - "主结果文件夹": "主要結果資料夾", - "也可批量输入音频文件, 二选一, 优先读文件夹": "也可批量输入音频文件, 二选一, 优先读文件夹", - "人声、伴奏与混响批量处理,使用pymss/MSST模型。": "使用 pymss/MSST 模型批次處理人聲、伴奏與混響。", - "人声伴奏分离&去混响": "人聲伴奏分離&去混響", - "仅支持pm和rmvpe音高提取算法": "僅支援pm和rmvpe音高提取算法", - "从训练检查点提取的模型": "从訓練检查点提取的模型", - "以-分隔输入使用的卡号, 例如 0-1-2 使用卡0和卡1和卡2": "以-分隔輸入使用的卡號, 例如 0-1-2 使用卡0和卡1和卡2", - "以下行填写不完整或无效,已忽略:%s": "以下行填写不完整或无效,已忽略:%s", - "任务": "任务", - "使用显卡:%s": "使用顯示卡:%s", - "使用模型采样率": "使用模型采样率", - "使用设备采样率": "使用设备采样率", - "保存名": "儲存名", - "保存的文件名, 默认空为和源文件同名": "儲存的檔案名,預設空為與來源檔案同名", - "保存的模型名不带后缀": "儲存的模型名不帶副檔名", - "保存频率save_every_epoch": "保存頻率save_every_epoch", - "保护清辅音和呼吸声,防止电音撕裂等artifact,拉满0.5不开启,调低加大保护力度但可能降低索引效果": "保護清輔音和呼吸聲,防止電音撕裂等artifact,拉滿0.5不開啟,調低加大保護力度但可能降低索引效果", - "修改": "修改", - "修改模型信息(仅支持weights文件夹下提取的小模型文件)": "修改模型資訊(僅支援weights資料夾下提取的小模型檔案)", - "停止一键训练": "停止一鍵訓練", - "停止分离": "停止分離", - "停止处理数据": "停止處理資料", - "停止特征提取": "停止特徵擷取", - "停止训练模型": "停止訓練模型", - "停止训练索引": "停止訓練索引", - "停止音频转换": "停止音訊轉換", - "分离残余文件夹": "分離殘餘資料夾", - "删除末行": "删除末行", - "判别器预训练模型不存在,将不使用:assets/pretrained%s/%sD%s.pth": "判别器预訓練模型不存在,将不使用:assets/pretrained%s/%sD%s.pth", - "刷新音色列表": "重新整理音色列表", - "加载模型": "載入模型", - "加载预训练底模D路径": "加載預訓練底模D路徑", - "加载预训练底模G路径": "加載預訓練底模G路徑", - "单次推理": "单次推理", - "单说话人": "单说话人", - "卸载音色省显存": "卸載音色節省 VRAM", - "变调(整数, 半音数量, 升八度12降八度-12)": "變調(整數、半音數量、升八度12降八度-12)", - "合成": "合成", - "后处理重采样至最终采样率,0为不进行重采样": "後處理重採樣至最終採樣率,0為不進行重採樣", - "否": "否", - "响应阈值": "響應閾值", - "响度因子": "響度因子", - "处理中": "處理中", - "处理数据": "處理資料", - "处理方式": "處理方式", - "多说话人": "多说话人", - "注意:多说话人训练音色还原度不一定有单说话人分开训练好!": "注意:多說話人訓練的音色還原度不一定比各說話人分開訓練好!", - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s": "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s", - "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。": "多说话人总文件夹只扫描根目录下的直接子文件夹,根目录文件会被忽略。\n子文件夹必须命名为x_y_z:x是说话人名称,y是说话人ID(0~109,共110个),z是训练集重复次数。\n也可以到右侧“多说话人训练集辅助”编辑并提交训练集清单。", - "多说话人训练集总文件夹不存在:%s": "多说话人训练集总文件夹不存在:%s", - "多说话人训练集总文件夹中没有有效音频": "多说话人训练集总文件夹中没有有效音频", - "多说话人训练集总文件夹中没有直接子文件夹": "多说话人训练集总文件夹中没有直接子文件夹", - "多说话人训练集总文件夹路径": "多说话人训练集总文件夹路径", - "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹": "多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹", - "多说话人训练集清单包含无效条目:%s": "多说话人训练集清单包含无效条目:%s", - "多说话人训练集清单存在重复输出标识:%s": "多说话人训练集清单存在重复输出标识:%s", - "多说话人训练集清单已保存:%s;有效音频%s个": "多说话人训练集清单已保存:%s;有效音频%s个", - "多说话人训练集清单格式错误": "多说话人训练集清单格式错误", - "多说话人训练集清单没有有效音频": "多说话人训练集清单没有有效音频", - "多说话人训练集辅助": "多说话人训练集辅助", - "失败": "失敗", - "失败记录": "失敗記錄", - "子进程执行失败,返回码:%s": "子進程执行失敗,返回码:%s", - "实验名不能为空": "实验名不能为空", - "导出文件格式": "導出檔格式", - "已停止": "已停止", - "已加载判别器预训练模型:%s": "已載入判别器预訓練模型:%s", - "已加载生成器预训练模型:%s": "已載入生成器预訓練模型:%s", - "已启用索引检索": "已启用索引检索", - "已完成": "已完成", - "已完成阶段": "已完成階段", - "已恢复判别器检查点": "已恢复判别器检查点", - "已成功": "已成功", - "常见问题解答": "常見問題解答", - "常规设置": "一般設定", - "底层模型": "底層模型", - "开始音频转换": "開始音訊轉換", - "当前": "目前", - "当前设备:%s | 推理精度:%s": "目前裝置:%s | 推論精度:%s", - "当前阶段": "目前阶段", - "很遗憾您这没有能用的显卡来支持您训练": "很遗憾您这没有能用的显卡来支持您训练", - "性别因子/声线粗细": "性別因子/聲線粗細", - "性能设置": "效能設定", - "总训练轮数total_epoch": "總訓練輪數total_epoch", - "成功": "成功", - "执行命令": "执行命令", - "批量推理": "批量推理", - "批量转换, 输入待转换音频文件夹, 或上传多个音频文件, 在指定文件夹(默认opt)下输出转换的音频. ": "批量轉換,輸入待轉換音頻資料夾,或上傳多個音頻檔案,在指定資料夾(默認opt)下輸出轉換的音頻。", - "拖拽或点击上传待处理音频": "拖放或點擊上傳待處理音訊", - "指定输出文件夹": "指定輸出資料夾", - "推理时间(ms):": "推理時間(ms):", - "推理耗时:%.2f秒": "推理耗时:%.2f秒", - "推理音色": "推理音色", - "提交训练集清单": "提交训练集清单", - "提取": "提取", - "提取音高和处理数据使用的CPU进程数": "提取音高和處理數據使用的CPU進程數", - "数据切分": "數據切分", - "数据切分没有生成16k音频,已停止后续特征提取和训练": "資料切分沒有產生16k音訊,已停止後續特徵提取和訓練", - "数据切分没有生成有效训练音频,请检查训练集和数据切分日志": "資料切分沒有產生有效訓練音訊,請檢查訓練集和資料切分日誌", - "数据切分输出文件不匹配,已停止后续特征提取和训练": "資料切分輸出檔案不匹配,已停止後續特徵提取和訓練", - "数据提取开始:start_time=%.6f,请求并行数=%s,实际并行数上限=%s": "資料擷取開始:start_time=%.6f,請求並行數=%s,實際並行數上限=%s", - "数据提取结束:end_time=%.6f,总耗时=%.3f秒": "資料擷取結束:end_time=%.6f,總耗時=%.3f秒", - "新增一行": "新增一行", - "无法停止": "無法停止", - "是": "是", - "是否仅保存最新的ckpt文件以节省硬盘空间": "是否僅保存最新的ckpt檔案以節省硬碟空間", - "是否在每次保存时间点将最终小模型保存至weights文件夹": "是否在每次保存時間點將最終小模型保存至weights檔夾", - "是否缓存所有训练集至显存. 10min以下小数据可缓存以加速训练, 大数据缓存会炸显存也加不了多少速": "是否緩存所有訓練集至 VRAM。小於10分鐘的小數據可緩存以加速訓練,大數據緩存會爆 VRAM 也加不了多少速度", - "显卡信息": "顯示卡資訊", - "未使用": "未使用", - "未使用判别器预训练模型": "未使用判别器预訓練模型", - "未使用生成器预训练模型": "未使用生成器预訓練模型", - "未检测到可用显卡,将使用CPU训练,耗时可能较长": "未偵測到可用顯示卡,将使用CPU訓練,耗时可能较长", - "未运行": "未运行", - "本软件以MIT协议开源, 作者不对软件具备任何控制力, 使用软件者、传播软件导出的声音者自负全责.
如不认可该条款, 则不能使用或引用软件包内任何代码和文件. 详见根目录LICENSE.": "本軟體以MIT協議開源,作者不對軟體具備任何控制力,使用軟體者、傳播軟體導出的聲音者自負全責。
如不認可該條款,則不能使用或引用軟體包內任何程式碼和檔案。詳見根目錄使用需遵守的協議-LICENSE.txt。", - "查看": "查看", - "查看模型信息(仅支持weights文件夹下提取的小模型文件)": "查看模型資訊(僅支援weights資料夾下提取的小模型檔案)", - "检索特征占比": "檢索特徵佔比", - "模型信息:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s": "模型資訊:%s\n采样率:%s\n是否使用音高引导:%s\n版本:%s", - "模型推理": "模型推理", - "模型提取(输入logs文件夹下大文件模型路径),适用于训一半不想训了模型没有自动提取保存小文件模型,或者想测试中间模型的情况": "模型提取(輸入logs資料夾下大檔案模型路徑),適用於訓一半不想訓了模型沒有自動提取儲存小檔案模型,或者想測試中間模型的情況", - "模型是否带音高指导": "模型是否帶音高指導", - "模型是否带音高指导(唱歌一定要, 语音可以不要)": "模型是否帶音高指導(唱歌一定要,語音可以不要)", - "模型是否带音高指导,1是0否": "模型是否帶音高指導,1是0否", - "模型版本型号": "模型版本型號", - "模型融合, 可用于测试音色融合": "模型融合,可用於測試音色融合", - "模型融合失败:两个模型的结构不一致": "模型融合失敗:两个模型的结构不一致", - "模型训练": "模型訓練", - "模型路径": "模型路徑", - "正在保存最终检查点:%s": "正在儲存最终检查点:%s", - "正在保存检查点 %s_e%s:%s": "正在儲存检查点 %s_e%s:%s", - "正在加载RMVPE模型": "正在載入RMVPE模型", - "正在加载模型": "正在載入模型", - "正在启动": "正在启动", - "正在收尾": "正在收尾", - "正在预热CUDA Graph": "正在預熱 CUDA Graph", - "每张显卡的batch_size": "每张显卡的batch_size", - "没有可用于训练的有效音频,请先完成数据切分和特征提取": "沒有可用於訓練的有效音訊,請先完成資料切分和特徵提取", - "没有有效的多说话人训练集行": "没有有效的多说话人训练集行", - "淡入淡出长度": "淡入淡出長度", - "清理模型缓存": "清理模型缓存", - "版本": "版本", - "特征": "特徵", - "特征提取": "特徵提取", - "特征检索库文件路径(选择模型后自动匹配,可手动修改)": "特徵索引庫檔案路徑(選擇模型後自動配對,可手動修改)", - "状态": "状态", - "独占 WASAPI 设备": "独占 WASAPI 设备", - "生成器预训练模型不存在,将不使用:assets/pretrained%s/%sG%s.pth": "生成器预訓練模型不存在,将不使用:assets/pretrained%s/%sG%s.pth", - "留空则使用辅助页已提交的清单": "留空则使用辅助页已提交的清单", - "目标采样率": "目標取樣率", - "第%s/%s页,共%s行": "第%s/%s页,共%s行", - "等待中": "等待中", - "等待输入": "等待輸入", - "算法延迟(ms):": "算法延迟(ms):", - "索引": "索引", - "索引文件不存在,将不使用索引继续推理:%s": "索引檔案不存在,將不使用索引繼續推理:%s", - "索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index": "索引無效:必须使用added_xxxx.index,不能使用trained_xxxx.index", - "索引检索失败": "索引检索失敗", - "索引检索失败或未启用": "索引检索失敗或未启用", - "索引训练": "索引訓練", - "耗时": "耗时", - "耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒": "耗时:特徵=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒", - "融合": "融合", - "要改的模型信息": "要改的模型資訊", - "要置入的模型信息": "要置入的模型資訊", - "训练": "訓練", - "训练已完成,正在保存最终模型": "訓練已完成,正在儲存最终模型", - "训练文件列表写入完成": "訓練檔案列表写入完成", - "训练模型": "訓練模型", - "训练特征索引": "訓練特徵索引", - "训练设备规则选择的精度:%s": "訓練设备规则选择的精度:%s", - "训练轮次:{} [{:.0f}%]": "訓練輪次:{} [{:.0f}%]", - "训练集子音频文件夹目录路径": "训练集子音频文件夹目录路径", - "训练集类型": "训练集类型", - "设备类型": "设备类型", - "说话人ID(0~109)": "说话人ID(0~109)", - "说话人名称": "说话人名称", - "说话人:%s(ID:%s)": "说话人:%s(ID:%s)", - "请上传音频文件": "请上传音頻檔案", - "请填写输出文件夹路径": "请填写輸出資料夾路径", - "请指定说话人id": "請指定說話人id", - "请选择index文件": "请选择index文件", - "请选择pth文件": "请选择pth文件", - "请选择说话人id": "請選擇說話人ID", - "转换": "轉換", - "输入实验名": "輸入實驗名稱", - "输入实验名,例如:test": "輸入實驗名稱,例如:test", - "输入待处理音频文件夹路径": "輸入待處理音頻資料夾路徑", - "输入待处理音频文件夹路径(去文件管理器地址栏拷就行了)": "輸入待處理音頻資料夾路徑(去檔案管理器地址欄拷貝即可)", - "输入源音量包络替换输出音量包络融合比例,越靠近1越使用输出包络": "輸入源音量包絡替換輸出音量包絡融合比例,越靠近1越使用輸出包絡", - "输入监听": "输入监听", - "输入训练文件夹路径": "輸入訓練檔案夾路徑", - "输入设备": "輸入設備", - "输入设备:%s:%s": "輸入设备:%s:%s", - "输入降噪": "輸入降噪", - "输出信息": "輸出訊息", - "输出变声": "输出变声", - "输出设备": "輸出設備", - "输出设备:%s:%s": "輸出设备:%s:%s", - "输出降噪": "輸出降噪", - "输出音频(右下角三个点,点了可以下载)": "輸出音頻(右下角三個點,點了可以下載)", - "运行中": "运行中", - "进度": "進度", - "选择.index文件": "選擇 .index 檔案", - "选择.pth文件": "選擇 .pth 檔案", - "选择多说话人音色": "选择多说话人音色", - "选择模型": "选择模型", - "选择索引": "选择索引", - "选择音高提取算法": "選擇音高擷取演算法", - "采样率:": "采样率:", - "采样长度": "取樣長度", - "重复次数": "重复次数", - "重载设备列表": "重載設備列表", - "音调设置": "音調設定", - "音频设备": "音訊設備", - "音高全部为0,该音频无意义,跳过:%s": "音高全部為0,该音頻無意义,跳過:%s", - "音高算法": "音高演算法", - "额外推理时长": "額外推理時長" -} diff --git a/infer/__init__.py b/infer/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/infer/audio.py b/infer/audio.py deleted file mode 100644 index 552df366709acb2a372391be15b729af482b1be8..0000000000000000000000000000000000000000 --- a/infer/audio.py +++ /dev/null @@ -1,341 +0,0 @@ -import platform, os -import ffmpeg -import numpy as np -import av -from io import BytesIO -import threading - - -_USE_TORCHAUDIO_GPU = False -_AUDIO_DEVICE = None -_AUDIO_DTYPE = None -_TORCH = None -_TORCHAUDIO = None -_TORCHAUDIO_RESAMPLE = None -_RESAMPLE_TRANSFORMS = {} -_RESAMPLE_LOCK = threading.Lock() -_FORCE_CPU_AUDIO = os.environ.get("RVC_AUDIO_FORCE_CPU", "0") == "1" - -# Select the accelerated loader once, when this module is imported. The CUDA -# device and dtype come from the project's shared automatic selection rules. -# CPU and DirectML keep the original FFmpeg path. Import failures (including -# missing torchaudio DLLs) also leave FFmpeg selected. -if not _FORCE_CPU_AUDIO: - try: - import torch as _TORCH - import torchaudio as _TORCHAUDIO - from torchaudio.transforms import Resample as _TORCHAUDIO_RESAMPLE - - from configs.config import infer_device as _AUDIO_DEVICE - from configs.config import infer_dtype as _AUDIO_DTYPE - - _USE_TORCHAUDIO_GPU = ( - getattr(_AUDIO_DEVICE, "type", None) == "cuda" - and _TORCH.cuda.is_available() - ) - except Exception: - _USE_TORCHAUDIO_GPU = False - -AUDIO_LOAD_BACKEND = "torchaudio_cuda" if _USE_TORCHAUDIO_GPU else "ffmpeg" -TORCHAUDIO_GPU_ENABLED = _USE_TORCHAUDIO_GPU -AUDIO_DEVICE = _AUDIO_DEVICE -AUDIO_DTYPE = _AUDIO_DTYPE - - -def wav2(i, o, format): - inp = av.open(i, "r") - try: - if format == "m4a": - format = "mp4" - out = av.open(o, "w", format=format) - try: - if format == "ogg": - format = "libvorbis" - if format == "mp4": - format = "aac" - - if not inp.streams.audio: - raise ValueError("Input contains no audio stream") - input_stream = inp.streams.audio[0] - source_rate = input_stream.codec_context.sample_rate - ostream = ( - out.add_stream(format, rate=source_rate) - if source_rate - else out.add_stream(format) - ) - source_channels = input_stream.codec_context.channels - if source_channels == 1: - ostream.layout = "mono" - elif source_channels == 2: - ostream.layout = "stereo" - - for frame in inp.decode(input_stream): - for p in ostream.encode(frame): - out.mux(p) - - for p in ostream.encode(None): - out.mux(p) - finally: - out.close() - finally: - inp.close() - - -def transcode_audio_file(input_path, output_path, format): - """Transcode a WAV path and remove partial compressed output on failure.""" - output_path = os.fspath(output_path) - if os.path.exists(output_path): - os.remove(output_path) - try: - wav2(input_path, output_path, format) - if not os.path.isfile(output_path) or os.path.getsize(output_path) == 0: - raise RuntimeError("Audio transcoding produced no output: %s" % output_path) - except Exception: - if os.path.exists(output_path): - os.remove(output_path) - raise - - -def _probe_audio(file): - info = ffmpeg.probe(file, cmd="ffprobe") - stream = next( - item for item in info.get("streams", []) if item.get("codec_type") == "audio" - ) - return int(stream["sample_rate"]), int(stream.get("channels", 1)) - - -def _decode_audio_ffmpeg(file): - """Decode one audio stream without changing its sample rate.""" - source_sr, channels = _probe_audio(file) - channels = max(1, channels) - out, _ = ( - ffmpeg.input(file, threads=0) - .output( - "-", - format="f32le", - acodec="pcm_f32le", - ac=channels, - ar=source_sr, - ) - .run(cmd=["ffmpeg", "-nostdin"], capture_stdout=True, capture_stderr=True) - ) - samples = np.frombuffer(out, np.float32) - usable = samples.size - samples.size % channels - samples = samples[:usable] - return samples.reshape(-1, channels).T.copy(), source_sr - - -def _load_audio_ffmpeg(file, sr, force_mono=True): - # https://github.com/openai/whisper/blob/main/whisper/audio.py#L26 - # Keep the original FFmpeg path for CPU and unsupported decoders. When - # stereo is requested, retain all source channels instead of forcing ac=1. - channels = 1 - if not force_mono: - _, channels = _probe_audio(file) - channels = max(1, channels) - output = { - "format": "f32le", - "acodec": "pcm_f32le", - "ar": sr, - } - if force_mono: - output["ac"] = 1 - else: - output["ac"] = channels - out, _ = ( - ffmpeg.input(file, threads=0) - .output("-", **output) - .run(cmd=["ffmpeg", "-nostdin"], capture_stdout=True, capture_stderr=True) - ) - samples = np.frombuffer(out, np.float32) - if force_mono: - return samples.flatten() - usable = samples.size - samples.size % channels - return samples[:usable].reshape(-1, channels).T.copy() - - -def _channel_first_tensor(audio): - if not _TORCH.is_tensor(audio): - audio = _TORCH.from_numpy(np.ascontiguousarray(audio, dtype=np.float32)) - if audio.ndim == 1: - audio = audio.unsqueeze(0) - if audio.ndim != 2: - raise ValueError("Audio data must be one-dimensional or channel-first two-dimensional") - return audio - - -def _format_audio_tensor(audio, force_mono=True, keep_on_device=False): - audio = _channel_first_tensor(audio) - if force_mono: - if audio.shape[0] > 1: - audio = audio.mean(dim=0, keepdim=True) - else: - audio = audio[:1] - if keep_on_device: - audio = audio.to(device=_AUDIO_DEVICE, dtype=_AUDIO_DTYPE) - return audio.flatten() if force_mono else audio - audio = audio.detach().to(device="cpu", dtype=_TORCH.float32).contiguous().numpy() - return audio[0].flatten() if force_mono else audio - - -def _get_gpu_resampler(source_sr, target_sr): - key = (source_sr, target_sr, str(_AUDIO_DEVICE), _AUDIO_DTYPE) - transform = _RESAMPLE_TRANSFORMS.get(key) - if transform is None: - with _RESAMPLE_LOCK: - transform = _RESAMPLE_TRANSFORMS.get(key) - if transform is None: - transform = _TORCHAUDIO_RESAMPLE( - source_sr, - target_sr, - dtype=_AUDIO_DTYPE, - ).to(device=_AUDIO_DEVICE, dtype=_AUDIO_DTYPE) - _RESAMPLE_TRANSFORMS[key] = transform - return transform - - -def _resample_tensor_gpu(audio, source_sr, target_sr, force_mono=True, keep_on_device=False): - audio = _channel_first_tensor(audio) - if source_sr == target_sr: - return _format_audio_tensor(audio, force_mono, keep_on_device) - with _TORCH.inference_mode(): - audio = audio.to(device=_AUDIO_DEVICE, dtype=_AUDIO_DTYPE) - if force_mono and audio.shape[0] > 1: - audio = audio.mean(dim=0, keepdim=True) - elif force_mono: - audio = audio[:1] - audio = _get_gpu_resampler(source_sr, target_sr)(audio) - if keep_on_device: - return audio.flatten() if force_mono else audio - audio = audio.detach().to(device="cpu", dtype=_TORCH.float32).contiguous().numpy() - return audio[0].flatten() if force_mono else audio - - -def _load_audio_torchaudio_gpu(file, sr, force_mono=True, keep_on_device=False): - audio, source_sr = _TORCHAUDIO.load(file) - return _resample_tensor_gpu(audio, source_sr, sr, force_mono, keep_on_device) - - -def resample_audio(audio, source_sr, target_sr, force_mono=False, res_type=None): - """Resample channel-first audio, using the same CUDA path as load_audio.""" - tensor = _channel_first_tensor(audio) - if _USE_TORCHAUDIO_GPU: - try: - return _resample_tensor_gpu( - tensor, source_sr, target_sr, force_mono, keep_on_device=False - ) - except Exception: - try: - _TORCH.cuda.empty_cache() - except Exception: - pass - - tensor = _channel_first_tensor(tensor) - if force_mono: - if tensor.shape[0] > 1: - tensor = tensor.mean(dim=0, keepdim=True) - else: - tensor = tensor[:1] - array = tensor.detach().to(device="cpu", dtype=_TORCH.float32).numpy() - if source_sr != target_sr: - import librosa - - kwargs = {} - if res_type is not None: - kwargs["res_type"] = res_type - array = librosa.resample( - array, - orig_sr=source_sr, - target_sr=target_sr, - axis=-1, - **kwargs, - ) - return array[0].flatten() if force_mono else array - - -def resample_audio_tensor(audio, source_sr, target_sr, force_mono=False): - """Resample channel-first audio and keep the result on the selected GPU.""" - if _USE_TORCHAUDIO_GPU: - try: - return _resample_tensor_gpu( - audio, - source_sr, - target_sr, - force_mono=force_mono, - keep_on_device=True, - ) - except Exception: - try: - _TORCH.cuda.empty_cache() - except Exception: - pass - result = resample_audio( - audio, - source_sr, - target_sr, - force_mono=force_mono, - ) - tensor = _TORCH.from_numpy(np.ascontiguousarray(result, dtype=np.float32)) - if _USE_TORCHAUDIO_GPU: - tensor = tensor.to(device=_AUDIO_DEVICE, dtype=_AUDIO_DTYPE) - return tensor - - -def load_audio_tensor(file, sr, force_mono=True): - """Load audio as a tensor; stereo mode returns channel-first data.""" - file = clean_path(file) - if not _USE_TORCHAUDIO_GPU: - return _TORCH.from_numpy(_load_audio_ffmpeg(file, sr, force_mono)) - try: - return _load_audio_torchaudio_gpu( - file, sr, force_mono=force_mono, keep_on_device=True - ) - except Exception as torchaudio_error: - try: - audio, source_sr = _decode_audio_ffmpeg(file) - return _resample_tensor_gpu( - audio, source_sr, sr, force_mono=force_mono, keep_on_device=True - ) - except Exception as ffmpeg_error: - try: - audio = _TORCH.from_numpy(_load_audio_ffmpeg(file, sr, force_mono)) - return audio.to(device=_AUDIO_DEVICE, dtype=_AUDIO_DTYPE) - except Exception: - raise RuntimeError( - "Failed to load audio with torchaudio (%s) and FFmpeg (%s)" - % (torchaudio_error, ffmpeg_error) - ) from ffmpeg_error - - -def load_audio(file, sr, force_mono=True): - """Load float32 audio; mono is [T], preserved channels are [C, T].""" - file = clean_path(file) # 防止小白拷路径头尾带了空格和"和回车 - if _USE_TORCHAUDIO_GPU: - try: - return _load_audio_torchaudio_gpu(file, sr, force_mono=force_mono) - except Exception as torchaudio_error: - try: - audio, source_sr = _decode_audio_ffmpeg(file) - return _resample_tensor_gpu( - audio, source_sr, sr, force_mono=force_mono - ) - except Exception as decode_error: - # Preserve the old format coverage if both torchaudio decode - # and GPU processing are unavailable for this file. - try: - return _load_audio_ffmpeg(file, sr, force_mono) - except Exception as ffmpeg_error: - raise RuntimeError( - "Failed to load audio with torchaudio (%s), raw FFmpeg (%s), and FFmpeg (%s)" - % (torchaudio_error, decode_error, ffmpeg_error) - ) from ffmpeg_error - try: - return _load_audio_ffmpeg(file, sr, force_mono) - except Exception as error: - raise RuntimeError("Failed to load audio: %s" % error) from error - - -def clean_path(path_str): - if platform.system() == "Windows": - path_str = path_str.replace("/", "\\") - return path_str.strip(" ").strip('"').strip("\n").strip('"').strip(" ") diff --git a/infer/cli.py b/infer/cli.py deleted file mode 100644 index 190216d9c99b3ace708d614a0a6bb65dbed322f8..0000000000000000000000000000000000000000 --- a/infer/cli.py +++ /dev/null @@ -1,299 +0,0 @@ -import argparse -import os -import sys -import warnings -from io import BytesIO -from pathlib import Path - - -warnings.filterwarnings( - "ignore", - message=r"`torch\.nn\.utils\.weight_norm` is deprecated.*", - category=FutureWarning, -) - - -PROJECT_ROOT = Path(__file__).resolve().parent.parent -os.chdir(PROJECT_ROOT) -os.environ.setdefault("OPENBLAS_NUM_THREADS", "1") -os.environ.setdefault("weight_root", str(PROJECT_ROOT / "assets" / "weights")) -os.environ.setdefault("index_root", str(PROJECT_ROOT / "logs")) -os.environ.setdefault("outside_index_root", str(PROJECT_ROOT / "assets" / "indices")) -os.environ.setdefault("rmvpe_root", str(PROJECT_ROOT / "assets" / "rmvpe")) - -AUDIO_EXTENSIONS = { - ".wav", - ".flac", - ".mp3", - ".m4a", - ".ogg", - ".opus", - ".aac", - ".wma", - ".mp4", - ".mkv", - ".webm", -} -OUTPUT_FORMATS = {"wav", "flac", "mp3", "m4a"} - - -def build_parser(): - parser = argparse.ArgumentParser( - description="Offline RVC inference for single-speaker and multi-speaker models." - ) - parser.add_argument("--model", required=True, help="Model filename or .pth path.") - parser.add_argument("--input", help="Input audio file or directory.") - parser.add_argument("--output", help="Output audio file or directory.") - parser.add_argument( - "--speaker-id", - type=int, - help="Speaker ID. Multi-speaker models default to their smallest declared ID.", - ) - parser.add_argument( - "--list-speakers", - action="store_true", - help="List the model's speaker metadata and exit.", - ) - parser.add_argument("--pitch", type=int, default=0, help="Pitch shift in semitones.") - parser.add_argument( - "--f0-method", choices=["pm", "rmvpe"], default="rmvpe" - ) - parser.add_argument( - "--index", - help="Explicit added index path. The matching speaker index is selected automatically when omitted.", - ) - parser.add_argument("--index-rate", type=float, default=0.75) - parser.add_argument("--resample-sr", type=int, default=0) - parser.add_argument("--rms-mix-rate", type=float, default=1.0) - parser.add_argument("--protect", type=float, default=0.33) - parser.add_argument( - "--format", dest="output_format", choices=sorted(OUTPUT_FORMATS) - ) - parser.add_argument( - "--recursive", action="store_true", help="Scan input subdirectories." - ) - parser.add_argument("--overwrite", action="store_true") - return parser - - -def resolve_model(value): - candidate = Path(value).expanduser() - if not candidate.is_absolute(): - candidate = (PROJECT_ROOT / candidate).resolve() - if not candidate.is_file(): - candidate = (Path(os.environ["weight_root"]) / value).resolve() - if not candidate.is_file(): - raise FileNotFoundError("Model not found: %s" % value) - if candidate.suffix.lower() != ".pth": - raise ValueError("Model must be a .pth file: %s" % candidate) - return candidate - - -def load_model_metadata(model_path): - import torch - - checkpoint = torch.load(str(model_path), map_location="cpu") - weight = checkpoint.get("weight", {}) if isinstance(checkpoint, dict) else {} - embedding = weight.get("emb_g.weight") - if embedding is None: - raise ValueError("Model does not contain weight/emb_g.weight") - speaker_count = int(embedding.shape[0]) - speakers = [] - seen = set() - for item in checkpoint.get("speaker_info", []): - try: - speaker_id = int(item["id"]) - speaker_name = str(item["name"]) - except (KeyError, TypeError, ValueError): - continue - if ( - 0 <= speaker_id < speaker_count - and speaker_name - and speaker_id not in seen - ): - speakers.append({"id": speaker_id, "name": speaker_name}) - seen.add(speaker_id) - speakers.sort(key=lambda item: item["id"]) - return speaker_count, speakers - - -def select_speaker(speaker_count, speakers, requested_id): - if speakers: - valid_ids = {item["id"] for item in speakers} - speaker_id = speakers[0]["id"] if requested_id is None else requested_id - if speaker_id not in valid_ids: - raise ValueError( - "Speaker ID %s is not declared by this multi-speaker model; available IDs: %s" - % (speaker_id, ", ".join(str(value) for value in sorted(valid_ids))) - ) - return speaker_id - speaker_id = 0 if requested_id is None else requested_id - if speaker_id < 0 or speaker_id >= speaker_count: - raise ValueError( - "Speaker ID must be between 0 and %s for this model" % (speaker_count - 1) - ) - return speaker_id - - -def resolve_index(value, model_name, speaker_id, index_rate): - from infer.vc.utils import get_index_path_from_model - - if index_rate == 0: - return "" - if value: - candidate = Path(value).expanduser() - if not candidate.is_absolute(): - candidate = (PROJECT_ROOT / candidate).resolve() - if "trained" in candidate.name: - candidate = candidate.with_name(candidate.name.replace("trained", "added")) - index_path = str(candidate) - else: - index_path = get_index_path_from_model(model_name, speaker_id) - if not index_path or not Path(index_path).is_file(): - raise FileNotFoundError( - "No usable added index for speaker ID %s. Supply --index or use --index-rate 0." - % speaker_id - ) - return str(Path(index_path).resolve()) - - -def collect_jobs(input_value, output_value, output_format, recursive): - input_path = Path(input_value).expanduser().resolve() - output_path = Path(output_value).expanduser().resolve() - if not input_path.exists(): - raise FileNotFoundError("Input not found: %s" % input_path) - - if input_path.is_file(): - suffix_format = output_path.suffix.lower().lstrip(".") - if output_path.suffix and suffix_format not in OUTPUT_FORMATS: - raise ValueError("Unsupported output suffix: %s" % output_path.suffix) - selected_format = output_format or suffix_format or "wav" - if output_path.suffix: - output_file = output_path.with_suffix(".%s" % selected_format) - else: - output_path.mkdir(parents=True, exist_ok=True) - output_file = output_path / (input_path.stem + "." + selected_format) - return [(input_path, output_file, selected_format)] - - selected_format = output_format or "wav" - output_path.mkdir(parents=True, exist_ok=True) - iterator = input_path.rglob("*") if recursive else input_path.iterdir() - jobs = [] - for path in sorted(iterator): - if not path.is_file() or path.suffix.lower() not in AUDIO_EXTENSIONS: - continue - relative_parent = path.relative_to(input_path).parent if recursive else Path() - output_file = output_path / relative_parent / (path.stem + "." + selected_format) - jobs.append((path, output_file, selected_format)) - if not jobs: - raise ValueError("No supported audio files found in: %s" % input_path) - return jobs - - -def write_audio(path, audio, sample_rate, output_format): - import soundfile as sf - from infer.audio import wav2 - - path.parent.mkdir(parents=True, exist_ok=True) - if output_format in ("wav", "flac"): - sf.write(str(path), audio, sample_rate) - return - with BytesIO() as wav_file: - sf.write(wav_file, audio, sample_rate, format="wav") - wav_file.seek(0) - with open(path, "wb") as output_file: - wav2(wav_file, output_file, output_format) - - -def create_config(): - from configs.config import Config - - original_argv = sys.argv[:] - sys.argv = [sys.argv[0]] - try: - return Config() - finally: - sys.argv = original_argv - - -def main(argv=None): - parser = build_parser() - args = parser.parse_args(argv) - if not args.list_speakers and (not args.input or not args.output): - parser.error("--input and --output are required unless --list-speakers is used") - if not 0 <= args.index_rate <= 1: - parser.error("--index-rate must be between 0 and 1") - if not 0 <= args.rms_mix_rate <= 1: - parser.error("--rms-mix-rate must be between 0 and 1") - if not 0 <= args.protect <= 0.5: - parser.error("--protect must be between 0 and 0.5") - if args.resample_sr and args.resample_sr < 16000: - parser.error("--resample-sr must be 0 or at least 16000") - - model_path = resolve_model(args.model) - os.environ["weight_root"] = str(model_path.parent) - model_name = model_path.name - speaker_count, speakers = load_model_metadata(model_path) - if args.list_speakers: - if speakers: - for item in speakers: - print("%s\t%s" % (item["id"], item["name"])) - else: - print("0-%s" % (speaker_count - 1)) - return 0 - - speaker_id = select_speaker(speaker_count, speakers, args.speaker_id) - index_path = resolve_index( - args.index, model_name, speaker_id, args.index_rate - ) - jobs = collect_jobs( - args.input, args.output, args.output_format, args.recursive - ) - existing = [str(output) for _, output, _ in jobs if output.exists()] - if existing and not args.overwrite: - raise FileExistsError( - "Output already exists; use --overwrite: %s" % existing[0] - ) - - from i18n.i18n import I18nAuto - from infer.vc.modules import VC - - i18n = I18nAuto() - config = create_config() - print(i18n("当前设备:%s | 推理精度:%s") % (config.device, config.dtype)) - print("%s: %s" % (i18n("选择模型"), model_name)) - print("%s: %s" % (i18n("说话人ID(0~109)"), speaker_id)) - print("%s: %s" % (i18n("选择索引"), index_path or i18n("未使用"))) - - vc = VC(config) - vc.get_vc(model_name) - failed = 0 - for input_path, output_path, output_format in jobs: - status, result = vc.vc_single( - speaker_id, - str(input_path), - args.pitch, - args.f0_method, - index_path, - args.index_rate, - args.resample_sr, - args.rms_mix_rate, - args.protect, - ) - print(status) - if not result or result[0] is None or result[1] is None: - failed += 1 - continue - write_audio(output_path, result[1], result[0], output_format) - print(str(output_path)) - return 1 if failed else 0 - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except KeyboardInterrupt: - raise SystemExit(130) - except Exception as error: - print("rvc-cli: error: %s" % error, file=sys.stderr) - raise SystemExit(1) diff --git a/infer/fcpe.py b/infer/fcpe.py deleted file mode 100644 index 1d4f34c9721141e72a64513169d8508e44a93201..0000000000000000000000000000000000000000 --- a/infer/fcpe.py +++ /dev/null @@ -1,161 +0,0 @@ -import torch - -from tools.cuda_graph import cuda_graph_enabled, run_cuda_graph - - -def _is_directml_device(device): - """Return whether *device* is the PrivateUse1 device registered by DirectML.""" - return getattr(device, "type", None) == "privateuseone" or "privateuseone" in str( - device - ).lower() - - -class FCPEInfer: - """Project-local FCPE inference adapter with a DirectML execution path. - - DirectML does not support the complex tensor produced by ``torch.stft`` in - torchfcpe's wav2mel stage. Keep preprocessing and the small indexed - decoder on CPU while the FCPE neural network runs on DirectML. Other - devices retain torchfcpe's original end-to-end inference path. - """ - - def __init__(self, device): - from torchfcpe import spawn_bundled_infer_model - - self.device = device - self.is_directml = _is_directml_device(device) - if self.is_directml: - # Loading a checkpoint directly with map_location=privateuseone is - # not supported consistently. Load on CPU, leave wav2mel there, - # and move only the real-valued FCPE network to DirectML. - self.infer_model = spawn_bundled_infer_model("cpu") - self.infer_model.wav2mel.eval() - self.cent_table_cpu = ( - self.infer_model.model.cent_table.detach().float().cpu().clone() - ) - self.out_dims = int(self.infer_model.model.out_dims) - self.infer_model.model.to(device).eval() - else: - self.infer_model = spawn_bundled_infer_model(device) - if getattr(device, "type", None) == "cuda" or str(device).startswith( - "cuda" - ): - # torchfcpe creates this tensor on CPU and copies it to CUDA in - # every local-argmax decode. Host-to-device copies are forbidden - # during CUDA Graph capture, so keep the immutable offsets on the - # target device and use the graph-safe equivalent decoder below. - self.local_offsets = torch.arange( - 9, device=device, dtype=torch.long - ).view(1, 1, 9) - - def _graphable_model_infer(self, mel, decoder_mode, threshold): - """Run FCPE network and an exactly equivalent capture-safe decoder.""" - model = self.infer_model.model - latent = model(mel) - batch, frames, _ = latent.shape - cents = model.cent_table[None, None, :].expand(batch, frames, -1) - - if decoder_mode == "argmax": - confidence = torch.max(latent, dim=-1, keepdim=True).values - decoded = torch.sum(cents * latent, dim=-1, keepdim=True) / torch.sum( - latent, dim=-1, keepdim=True - ) - elif decoder_mode == "local_argmax": - confidence, max_index = torch.max(latent, dim=-1, keepdim=True) - local_index = self.local_offsets + (max_index - 4) - local_index = local_index.clamp(0, model.out_dims - 1) - local_cents = torch.gather(cents, -1, local_index) - local_latent = torch.gather(latent, -1, local_index) - decoded = torch.sum( - local_cents * local_latent, dim=-1, keepdim=True - ) / torch.sum(local_latent, dim=-1, keepdim=True) - else: - raise ValueError("Unknown FCPE decoder mode: %s" % decoder_mode) - - # Match torchfcpe's masking and cent-to-Hz formulas operation-for-operation. - confidence_mask = torch.ones_like(confidence) - confidence_mask.masked_fill_(confidence <= threshold, float("-inf")) - decoded = decoded * confidence_mask - return 10.0 * torch.pow(2.0, decoded / 1200.0) - - def _decode_on_cpu(self, latent, decoder_mode, threshold): - """Decode DML network logits on CPU with torchfcpe's exact formulas. - - The current DirectML backend's ``aten::gather`` returns incorrect FCPE - bin values even though its indices and the neural-network logits match - CPU. Decoding is tiny compared with the model, so keep this - compatibility boundary on CPU as well as the complex STFT. - """ - latent = latent.detach().float().cpu() - batch, frames, _ = latent.shape - cents = self.cent_table_cpu[None, None, :].expand(batch, frames, -1) - - if decoder_mode == "argmax": - confidence = torch.max(latent, dim=-1, keepdim=True).values - decoded = torch.sum(cents * latent, dim=-1, keepdim=True) / torch.sum( - latent, dim=-1, keepdim=True - ) - elif decoder_mode == "local_argmax": - confidence, max_index = torch.max(latent, dim=-1, keepdim=True) - local_index = torch.arange(9, dtype=torch.long) + (max_index - 4) - local_index.clamp_(0, self.out_dims - 1) - local_cents = torch.gather(cents, -1, local_index) - local_latent = torch.gather(latent, -1, local_index) - decoded = torch.sum( - local_cents * local_latent, dim=-1, keepdim=True - ) / torch.sum(local_latent, dim=-1, keepdim=True) - else: - raise ValueError(f"Unknown FCPE decoder mode: {decoder_mode}") - - decoded = decoded.masked_fill(confidence <= threshold, float("-inf")) - return 10.0 * torch.pow(2.0, decoded / 1200.0) - - # torch.no_grad is used instead of inference_mode because DirectML's - # PrivateUse1 backend still updates version counters in a few operators. - @torch.no_grad() - def infer( - self, - wav, - sr, - decoder_mode="local_argmax", - threshold=0.006, - ): - if not self.is_directml: - wav = wav.to(self.device) - if cuda_graph_enabled(wav.device): - # Wav2MelModule contains tensor-dependent Python conditionals and - # cannot be captured. Running it eagerly also creates/caches its - # STFT window before the graph. The much larger FCPE neural net - # and decoder form the stable-shape CUDA Graph boundary. - mel = self.infer_model.wav2mel(wav, sr) - return run_cuda_graph( - self.infer_model.model, - "fcpe-core-%s-%s" % (decoder_mode, threshold), - lambda input_mel: self._graphable_model_infer( - input_mel, - decoder_mode, - threshold, - ), - mel, - ) - return run_cuda_graph( - self.infer_model, - "fcpe-%s-%s-%s" % (sr, decoder_mode, threshold), - lambda input_wav: self.infer_model.infer( - input_wav, - sr=sr, - decoder_mode=decoder_mode, - threshold=threshold, - ), - wav, - ) - - wav_cpu = wav.detach().to(device="cpu", dtype=torch.float32) - mel_cpu = self.infer_model.wav2mel(wav_cpu, sr) - mel_dml = mel_cpu.to(device=self.device, dtype=torch.float32) - latent_dml = self.infer_model.model(mel_dml) - return self._decode_on_cpu( - latent_dml, - decoder_mode=decoder_mode, - threshold=threshold, - ) diff --git a/infer/hubert.py b/infer/hubert.py deleted file mode 100644 index 6e2bd16f1577286753e5883aab955ff924c38a0a..0000000000000000000000000000000000000000 --- a/infer/hubert.py +++ /dev/null @@ -1,127 +0,0 @@ -import logging -from functools import lru_cache -from pathlib import Path - -import torch -from torch import nn -from transformers import AutoFeatureExtractor, HubertModel - -from tools.cuda_graph import run_cuda_graph - - -logger = logging.getLogger(__name__) - -PROJECT_ROOT = Path(__file__).resolve().parent.parent - - -class HubertModelWithFinalProj(HubertModel): - def __init__(self, config): - super().__init__(config) - self.final_proj = nn.Linear(config.hidden_size, config.classifier_proj_size) - -HUBERT_MODEL_PATH = (PROJECT_ROOT / "assets" / "hubert_base").resolve() - - -def _device_type(device): - if isinstance(device, torch.device): - return device.type - return str(device).split(":", 1)[0] - - -def load_hubert_model(device, is_half=False): - """Load the local Transformers HuBERT/ContentVec model for RVC.""" - if not (HUBERT_MODEL_PATH / "config.json").is_file(): - raise FileNotFoundError( - f"Transformers HuBERT model not found: {HUBERT_MODEL_PATH}" - ) - - dtype = torch.float16 if is_half else torch.float32 - load_options = { - "local_files_only": True, - "torch_dtype": dtype, - } - # DirectML does not implement every SDPA kernel used by Transformers. - if _device_type(device) == "privateuseone": - load_options["attn_implementation"] = "eager" - - logger.info( - "Loading Transformers HuBERT from %s (%s on %s)", - HUBERT_MODEL_PATH, - dtype, - device, - ) - model = HubertModelWithFinalProj.from_pretrained( - str(HUBERT_MODEL_PATH), **load_options - ) - model = model.to(device) - return model.eval() - - -@lru_cache(maxsize=1) -def hubert_audio_requires_normalization(): - feature_extractor = AutoFeatureExtractor.from_pretrained( - str(HUBERT_MODEL_PATH), local_files_only=True - ) - return bool(feature_extractor.do_normalize) - - -def extract_hubert_features(model, source, version, padding_mask=None): - """Return the RVC v1 (256-D) or v2 (768-D) HuBERT representation. - - Transformers hidden_states[N] is numerically equivalent to the source checkpoint's - output_layer=N for this converted checkpoint. RVC v1 uses layer 9 followed - by final_proj; RVC v2 uses the final (12th) encoder layer directly. - """ - if version not in {"v1", "v2"}: - raise ValueError(f"Unsupported RVC feature version: {version!r}") - - attention_mask = None - if padding_mask is not None and bool(torch.any(padding_mask).item()): - attention_mask = (~padding_mask.bool()).long() - - if version == "v1": - if attention_mask is None: - def forward(input_values): - outputs = model( - input_values=input_values, - attention_mask=None, - output_hidden_states=True, - return_dict=True, - ) - return model.final_proj(outputs.hidden_states[9]) - - return run_cuda_graph(model, "hubert-v1-no-mask", forward, source) - - def forward(input_values, mask): - outputs = model( - input_values=input_values, - attention_mask=mask, - output_hidden_states=True, - return_dict=True, - ) - return model.final_proj(outputs.hidden_states[9]) - - return run_cuda_graph( - model, "hubert-v1-mask", forward, source, attention_mask - ) - - if attention_mask is None: - def forward(input_values): - return model( - input_values=input_values, - attention_mask=None, - output_hidden_states=False, - return_dict=True, - ).last_hidden_state - - return run_cuda_graph(model, "hubert-v2-no-mask", forward, source) - - def forward(input_values, mask): - return model( - input_values=input_values, - attention_mask=mask, - output_hidden_states=False, - return_dict=True, - ).last_hidden_state - - return run_cuda_graph(model, "hubert-v2-mask", forward, source, attention_mask) diff --git a/infer/module/attentions.py b/infer/module/attentions.py deleted file mode 100644 index 377d7f04ad00f3a2ce0d76b055a9883943516a3e..0000000000000000000000000000000000000000 --- a/infer/module/attentions.py +++ /dev/null @@ -1,459 +0,0 @@ -import copy -import math -from typing import Optional - -import numpy as np -import torch -from torch import nn -from torch.nn import functional as F - -from infer.module import commons, modules -from infer.module.modules import LayerNorm - - -class Encoder(nn.Module): - def __init__( - self, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size=1, - p_dropout=0.0, - window_size=10, - **kwargs - ): - super(Encoder, self).__init__() - self.hidden_channels = hidden_channels - self.filter_channels = filter_channels - self.n_heads = n_heads - self.n_layers = int(n_layers) - self.kernel_size = kernel_size - self.p_dropout = p_dropout - self.window_size = window_size - - self.drop = nn.Dropout(p_dropout) - self.attn_layers = nn.ModuleList() - self.norm_layers_1 = nn.ModuleList() - self.ffn_layers = nn.ModuleList() - self.norm_layers_2 = nn.ModuleList() - for i in range(self.n_layers): - self.attn_layers.append( - MultiHeadAttention( - hidden_channels, - hidden_channels, - n_heads, - p_dropout=p_dropout, - window_size=window_size, - ) - ) - self.norm_layers_1.append(LayerNorm(hidden_channels)) - self.ffn_layers.append( - FFN( - hidden_channels, - hidden_channels, - filter_channels, - kernel_size, - p_dropout=p_dropout, - ) - ) - self.norm_layers_2.append(LayerNorm(hidden_channels)) - - def forward(self, x, x_mask): - attn_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(-1) - x = x * x_mask - zippep = zip( - self.attn_layers, self.norm_layers_1, self.ffn_layers, self.norm_layers_2 - ) - for attn_layers, norm_layers_1, ffn_layers, norm_layers_2 in zippep: - y = attn_layers(x, x, attn_mask) - y = self.drop(y) - x = norm_layers_1(x + y) - - y = ffn_layers(x, x_mask) - y = self.drop(y) - x = norm_layers_2(x + y) - x = x * x_mask - return x - - -class Decoder(nn.Module): - def __init__( - self, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size=1, - p_dropout=0.0, - proximal_bias=False, - proximal_init=True, - **kwargs - ): - super(Decoder, self).__init__() - self.hidden_channels = hidden_channels - self.filter_channels = filter_channels - self.n_heads = n_heads - self.n_layers = n_layers - self.kernel_size = kernel_size - self.p_dropout = p_dropout - self.proximal_bias = proximal_bias - self.proximal_init = proximal_init - - self.drop = nn.Dropout(p_dropout) - self.self_attn_layers = nn.ModuleList() - self.norm_layers_0 = nn.ModuleList() - self.encdec_attn_layers = nn.ModuleList() - self.norm_layers_1 = nn.ModuleList() - self.ffn_layers = nn.ModuleList() - self.norm_layers_2 = nn.ModuleList() - for i in range(self.n_layers): - self.self_attn_layers.append( - MultiHeadAttention( - hidden_channels, - hidden_channels, - n_heads, - p_dropout=p_dropout, - proximal_bias=proximal_bias, - proximal_init=proximal_init, - ) - ) - self.norm_layers_0.append(LayerNorm(hidden_channels)) - self.encdec_attn_layers.append( - MultiHeadAttention( - hidden_channels, hidden_channels, n_heads, p_dropout=p_dropout - ) - ) - self.norm_layers_1.append(LayerNorm(hidden_channels)) - self.ffn_layers.append( - FFN( - hidden_channels, - hidden_channels, - filter_channels, - kernel_size, - p_dropout=p_dropout, - causal=True, - ) - ) - self.norm_layers_2.append(LayerNorm(hidden_channels)) - - def forward(self, x, x_mask, h, h_mask): - """ - x: decoder input - h: encoder output - """ - self_attn_mask = commons.subsequent_mask(x_mask.size(2)).to( - device=x.device, dtype=x.dtype - ) - encdec_attn_mask = h_mask.unsqueeze(2) * x_mask.unsqueeze(-1) - x = x * x_mask - for i in range(self.n_layers): - y = self.self_attn_layers[i](x, x, self_attn_mask) - y = self.drop(y) - x = self.norm_layers_0[i](x + y) - - y = self.encdec_attn_layers[i](x, h, encdec_attn_mask) - y = self.drop(y) - x = self.norm_layers_1[i](x + y) - - y = self.ffn_layers[i](x, x_mask) - y = self.drop(y) - x = self.norm_layers_2[i](x + y) - x = x * x_mask - return x - - -class MultiHeadAttention(nn.Module): - def __init__( - self, - channels, - out_channels, - n_heads, - p_dropout=0.0, - window_size=None, - heads_share=True, - block_length=None, - proximal_bias=False, - proximal_init=False, - ): - super(MultiHeadAttention, self).__init__() - assert channels % n_heads == 0 - - self.channels = channels - self.out_channels = out_channels - self.n_heads = n_heads - self.p_dropout = p_dropout - self.window_size = window_size - self.heads_share = heads_share - self.block_length = block_length - self.proximal_bias = proximal_bias - self.proximal_init = proximal_init - self.attn = None - - self.k_channels = channels // n_heads - self.conv_q = nn.Conv1d(channels, channels, 1) - self.conv_k = nn.Conv1d(channels, channels, 1) - self.conv_v = nn.Conv1d(channels, channels, 1) - self.conv_o = nn.Conv1d(channels, out_channels, 1) - self.drop = nn.Dropout(p_dropout) - - if window_size is not None: - n_heads_rel = 1 if heads_share else n_heads - rel_stddev = self.k_channels**-0.5 - self.emb_rel_k = nn.Parameter( - torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels) - * rel_stddev - ) - self.emb_rel_v = nn.Parameter( - torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels) - * rel_stddev - ) - - nn.init.xavier_uniform_(self.conv_q.weight) - nn.init.xavier_uniform_(self.conv_k.weight) - nn.init.xavier_uniform_(self.conv_v.weight) - if proximal_init: - with torch.no_grad(): - self.conv_k.weight.copy_(self.conv_q.weight) - self.conv_k.bias.copy_(self.conv_q.bias) - - def forward( - self, x, c, attn_mask = None - ): - q = self.conv_q(x) - k = self.conv_k(c) - v = self.conv_v(c) - - x, _ = self.attention(q, k, v, mask=attn_mask) - - x = self.conv_o(x) - return x - - def attention( - self, - query, - key, - value, - mask = None, - ): - # reshape [b, d, t] -> [b, n_h, t, d_k] - b, d, t_s = key.size() - t_t = query.size(2) - query = query.view(b, self.n_heads, self.k_channels, t_t).transpose(2, 3) - key = key.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3) - value = value.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3) - - scores = torch.matmul(query / math.sqrt(self.k_channels), key.transpose(-2, -1)) - if self.window_size is not None: - assert ( - t_s == t_t - ), "Relative attention is only available for self-attention." - key_relative_embeddings = self._get_relative_embeddings(self.emb_rel_k, t_s) - rel_logits = self._matmul_with_relative_keys( - query / math.sqrt(self.k_channels), key_relative_embeddings - ) - scores_local = self._relative_position_to_absolute_position(rel_logits) - scores = scores + scores_local - if self.proximal_bias: - assert t_s == t_t, "Proximal bias is only available for self-attention." - scores = scores + self._attention_bias_proximal(t_s).to( - device=scores.device, dtype=scores.dtype - ) - if mask is not None: - scores = scores.masked_fill(mask == 0, -1e4) - if self.block_length is not None: - assert ( - t_s == t_t - ), "Local attention is only available for self-attention." - block_mask = ( - torch.ones_like(scores) - .triu(-self.block_length) - .tril(self.block_length) - ) - scores = scores.masked_fill(block_mask == 0, -1e4) - p_attn = F.softmax(scores, dim=-1) # [b, n_h, t_t, t_s] - p_attn = self.drop(p_attn) - output = torch.matmul(p_attn, value) - if self.window_size is not None: - relative_weights = self._absolute_position_to_relative_position(p_attn) - value_relative_embeddings = self._get_relative_embeddings( - self.emb_rel_v, t_s - ) - output = output + self._matmul_with_relative_values( - relative_weights, value_relative_embeddings - ) - output = ( - output.transpose(2, 3).contiguous().view(b, d, t_t) - ) # [b, n_h, t_t, d_k] -> [b, d, t_t] - return output, p_attn - - def _matmul_with_relative_values(self, x, y): - """ - x: [b, h, l, m] - y: [h or 1, m, d] - ret: [b, h, l, d] - """ - ret = torch.matmul(x, y.unsqueeze(0)) - return ret - - def _matmul_with_relative_keys(self, x, y): - """ - x: [b, h, l, d] - y: [h or 1, m, d] - ret: [b, h, l, m] - """ - ret = torch.matmul(x, y.unsqueeze(0).transpose(-2, -1)) - return ret - - def _get_relative_embeddings(self, relative_embeddings, length): - max_relative_position = 2 * self.window_size + 1 - # Pad first before slice to avoid using cond ops. - pad_length = max(length - (self.window_size + 1), 0) - slice_start_position = max((self.window_size + 1) - length, 0) - slice_end_position = slice_start_position + 2 * length - 1 - if pad_length > 0: - padded_relative_embeddings = F.pad( - relative_embeddings, - # commons.convert_pad_shape([[0, 0], [pad_length, pad_length], [0, 0]]), - [0, 0, pad_length, pad_length, 0, 0], - ) - else: - padded_relative_embeddings = relative_embeddings - used_relative_embeddings = padded_relative_embeddings[ - :, slice_start_position:slice_end_position - ] - return used_relative_embeddings - - def _relative_position_to_absolute_position(self, x): - """ - x: [b, h, l, 2*l-1] - ret: [b, h, l, l] - """ - batch, heads, length, _ = x.size() - # Concat columns of pad to shift from relative to absolute indexing. - x = F.pad( - x, - # commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, 1]]) - [0, 1, 0, 0, 0, 0, 0, 0], - ) - - # Concat extra elements so to add up to shape (len+1, 2*len-1). - x_flat = x.view([batch, heads, length * 2 * length]) - x_flat = F.pad( - x_flat, - # commons.convert_pad_shape([[0, 0], [0, 0], [0, int(length) - 1]]) - [0, int(length) - 1, 0, 0, 0, 0], - ) - - # Reshape and slice out the padded elements. - x_final = x_flat.view([batch, heads, length + 1, 2 * length - 1])[ - :, :, :length, length - 1 : - ] - return x_final - - def _absolute_position_to_relative_position(self, x): - """ - x: [b, h, l, l] - ret: [b, h, l, 2*l-1] - """ - batch, heads, length, _ = x.size() - # padd along column - x = F.pad( - x, - # commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, int(length) - 1]]) - [0, int(length) - 1, 0, 0, 0, 0, 0, 0], - ) - x_flat = x.view([batch, heads, int(length**2) + int(length * (length - 1))]) - # add 0's in the beginning that will skew the elements after reshape - x_flat = F.pad( - x_flat, - # commons.convert_pad_shape([[0, 0], [0, 0], [int(length), 0]]) - [length, 0, 0, 0, 0, 0], - ) - x_final = x_flat.view([batch, heads, length, 2 * length])[:, :, :, 1:] - return x_final - - def _attention_bias_proximal(self, length): - """Bias for self-attention to encourage attention to close positions. - Args: - length: an integer scalar. - Returns: - a Tensor with shape [1, 1, length, length] - """ - r = torch.arange(length, dtype=torch.float32) - diff = torch.unsqueeze(r, 0) - torch.unsqueeze(r, 1) - return torch.unsqueeze(torch.unsqueeze(-torch.log1p(torch.abs(diff)), 0), 0) - - -class FFN(nn.Module): - def __init__( - self, - in_channels, - out_channels, - filter_channels, - kernel_size, - p_dropout=0.0, - activation = None, - causal=False, - ): - super(FFN, self).__init__() - self.in_channels = in_channels - self.out_channels = out_channels - self.filter_channels = filter_channels - self.kernel_size = kernel_size - self.p_dropout = p_dropout - self.activation = activation - self.causal = causal - self.is_activation = True if activation == "gelu" else False - # if causal: - # self.padding = self._causal_padding - # else: - # self.padding = self._same_padding - - self.conv_1 = nn.Conv1d(in_channels, filter_channels, kernel_size) - self.conv_2 = nn.Conv1d(filter_channels, out_channels, kernel_size) - self.drop = nn.Dropout(p_dropout) - - def padding(self, x, x_mask) : - if self.causal: - padding = self._causal_padding(x * x_mask) - else: - padding = self._same_padding(x * x_mask) - return padding - - def forward(self, x, x_mask): - x = self.conv_1(self.padding(x, x_mask)) - if self.is_activation: - x = x * torch.sigmoid(1.702 * x) - else: - x = torch.relu(x) - x = self.drop(x) - - x = self.conv_2(self.padding(x, x_mask)) - return x * x_mask - - def _causal_padding(self, x): - if self.kernel_size == 1: - return x - pad_l = self.kernel_size - 1 - pad_r = 0 - # padding = [[0, 0], [0, 0], [pad_l, pad_r]] - x = F.pad( - x, - # commons.convert_pad_shape(padding) - [pad_l, pad_r, 0, 0, 0, 0], - ) - return x - - def _same_padding(self, x): - if self.kernel_size == 1: - return x - pad_l = (self.kernel_size - 1) // 2 - pad_r = self.kernel_size // 2 - # padding = [[0, 0], [0, 0], [pad_l, pad_r]] - x = F.pad( - x, - # commons.convert_pad_shape(padding) - [pad_l, pad_r, 0, 0, 0, 0], - ) - return x diff --git a/infer/module/commons.py b/infer/module/commons.py deleted file mode 100644 index 57ab7906511b6241bc2cd46c9b280cbe38eb29c2..0000000000000000000000000000000000000000 --- a/infer/module/commons.py +++ /dev/null @@ -1,171 +0,0 @@ -from typing import List, Optional -import math - -import numpy as np -import torch -from torch import nn -from torch.nn import functional as F - - -def init_weights(m, mean=0.0, std=0.01): - classname = m.__class__.__name__ - if classname.find("Conv") != -1: - m.weight.data.normal_(mean, std) - - -def get_padding(kernel_size, dilation=1): - return int((kernel_size * dilation - dilation) / 2) - - -# def convert_pad_shape(pad_shape): -# l = pad_shape[::-1] -# pad_shape = [item for sublist in l for item in sublist] -# return pad_shape - - -def kl_divergence(m_p, logs_p, m_q, logs_q): - """KL(P||Q)""" - kl = (logs_q - logs_p) - 0.5 - kl += ( - 0.5 * (torch.exp(2.0 * logs_p) + ((m_p - m_q) ** 2)) * torch.exp(-2.0 * logs_q) - ) - return kl - - -def rand_gumbel(shape): - """Sample from the Gumbel distribution, protect from overflows.""" - uniform_samples = torch.rand(shape) * 0.99998 + 0.00001 - return -torch.log(-torch.log(uniform_samples)) - - -def rand_gumbel_like(x): - g = rand_gumbel(x.size()).to(dtype=x.dtype, device=x.device) - return g - - -def slice_segments(x, ids_str, segment_size=4): - ret = torch.zeros_like(x[:, :, :segment_size]) - for i in range(x.size(0)): - idx_str = ids_str[i] - idx_end = idx_str + segment_size - ret[i] = x[i, :, idx_str:idx_end] - return ret - - -def slice_segments2(x, ids_str, segment_size=4): - ret = torch.zeros_like(x[:, :segment_size]) - for i in range(x.size(0)): - idx_str = ids_str[i] - idx_end = idx_str + segment_size - ret[i] = x[i, idx_str:idx_end] - return ret - - -def rand_slice_segments(x, x_lengths=None, segment_size=4): - b, d, t = x.size() - if x_lengths is None: - x_lengths = t - ids_str_max = x_lengths - segment_size + 1 - ids_str = (torch.rand([b]).to(device=x.device) * ids_str_max).to(dtype=torch.long) - ret = slice_segments(x, ids_str, segment_size) - return ret, ids_str - - -def get_timing_signal_1d(length, channels, min_timescale=1.0, max_timescale=1.0e4): - position = torch.arange(length, dtype=torch.float) - num_timescales = channels // 2 - log_timescale_increment = math.log(float(max_timescale) / float(min_timescale)) / ( - num_timescales - 1 - ) - inv_timescales = min_timescale * torch.exp( - torch.arange(num_timescales, dtype=torch.float) * -log_timescale_increment - ) - scaled_time = position.unsqueeze(0) * inv_timescales.unsqueeze(1) - signal = torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], 0) - signal = F.pad(signal, [0, 0, 0, channels % 2]) - signal = signal.view(1, channels, length) - return signal - - -def add_timing_signal_1d(x, min_timescale=1.0, max_timescale=1.0e4): - b, channels, length = x.size() - signal = get_timing_signal_1d(length, channels, min_timescale, max_timescale) - return x + signal.to(dtype=x.dtype, device=x.device) - - -def cat_timing_signal_1d(x, min_timescale=1.0, max_timescale=1.0e4, axis=1): - b, channels, length = x.size() - signal = get_timing_signal_1d(length, channels, min_timescale, max_timescale) - return torch.cat([x, signal.to(dtype=x.dtype, device=x.device)], axis) - - -def subsequent_mask(length): - mask = torch.tril(torch.ones(length, length)).unsqueeze(0).unsqueeze(0) - return mask - - -def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels): - n_channels_int = n_channels[0] - in_act = input_a + input_b - t_act = torch.tanh(in_act[:, :n_channels_int, :]) - s_act = torch.sigmoid(in_act[:, n_channels_int:, :]) - acts = t_act * s_act - return acts - - -# def convert_pad_shape(pad_shape): -# l = pad_shape[::-1] -# pad_shape = [item for sublist in l for item in sublist] -# return pad_shape - - -def convert_pad_shape(pad_shape) : - return torch.tensor(pad_shape).flip(0).reshape(-1).int().tolist() - - -def shift_1d(x): - x = F.pad(x, convert_pad_shape([[0, 0], [0, 0], [1, 0]]))[:, :, :-1] - return x - - -def sequence_mask(length, max_length = None): - if max_length is None: - max_length = length.max() - x = torch.arange(max_length, dtype=length.dtype, device=length.device) - return x.unsqueeze(0) < length.unsqueeze(1) - - -def generate_path(duration, mask): - """ - duration: [b, 1, t_x] - mask: [b, 1, t_y, t_x] - """ - device = duration.device - - b, _, t_y, t_x = mask.shape - cum_duration = torch.cumsum(duration, -1) - - cum_duration_flat = cum_duration.view(b * t_x) - path = sequence_mask(cum_duration_flat, t_y).to(mask.dtype) - path = path.view(b, t_x, t_y) - path = path - F.pad(path, convert_pad_shape([[0, 0], [1, 0], [0, 0]]))[:, :-1] - path = path.unsqueeze(1).transpose(2, 3) * mask - return path - - -def clip_grad_value_(parameters, clip_value, norm_type=2): - if isinstance(parameters, torch.Tensor): - parameters = [parameters] - parameters = list(filter(lambda p: p.grad is not None, parameters)) - norm_type = float(norm_type) - if clip_value is not None: - clip_value = float(clip_value) - - total_norm = 0 - for p in parameters: - param_norm = p.grad.data.norm(norm_type) - total_norm += param_norm.item() ** norm_type - if clip_value is not None: - p.grad.data.clamp_(min=-clip_value, max=clip_value) - total_norm = total_norm ** (1.0 / norm_type) - return total_norm diff --git a/infer/module/models.py b/infer/module/models.py deleted file mode 100644 index d0e612452671f7188e8a13431ac6a9eab29b4ee0..0000000000000000000000000000000000000000 --- a/infer/module/models.py +++ /dev/null @@ -1,1094 +0,0 @@ -import math -import logging -from typing import Optional - -logger = logging.getLogger(__name__) - -import numpy as np -import torch -from torch import nn -from torch.nn import AvgPool1d, Conv1d, Conv2d, ConvTranspose1d -from torch.nn import functional as F -from torch.nn.utils import remove_weight_norm, spectral_norm, weight_norm -from infer.module import attentions, commons, modules -from infer.module.commons import get_padding, init_weights - -class TextEncoder(nn.Module): - def __init__( - self, - in_channels, - out_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - p_dropout, - f0=True, - ): - super(TextEncoder, self).__init__() - self.out_channels = out_channels - self.hidden_channels = hidden_channels - self.filter_channels = filter_channels - self.n_heads = n_heads - self.n_layers = n_layers - self.kernel_size = kernel_size - self.p_dropout = float(p_dropout) - self.emb_phone = nn.Linear(in_channels, hidden_channels) - self.lrelu = nn.LeakyReLU(0.1, inplace=True) - if f0 == True: - self.emb_pitch = nn.Embedding(256, hidden_channels) # pitch 256 - self.encoder = attentions.Encoder( - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - float(p_dropout), - ) - self.proj = nn.Conv1d(hidden_channels, out_channels * 2, 1) - - def forward( - self, - phone, - pitch, - lengths, - skip_head = None, - ): - if pitch is None: - x = self.emb_phone(phone) - else: - x = self.emb_phone(phone) + self.emb_pitch(pitch) - x = x * math.sqrt(self.hidden_channels) # [b, t, h] - x = self.lrelu(x) - x = torch.transpose(x, 1, -1) # [b, h, t] - x_mask = torch.unsqueeze(commons.sequence_mask(lengths, x.size(2)), 1).to( - x.dtype - ) - x = self.encoder(x * x_mask, x_mask) - if skip_head is not None: - head = ( - int(skip_head.item()) - if isinstance(skip_head, torch.Tensor) - else int(skip_head) - ) - x = x[:, :, head:] - x_mask = x_mask[:, :, head:] - stats = self.proj(x) * x_mask - m, logs = torch.split(stats, self.out_channels, dim=1) - return m, logs, x_mask - - -class ResidualCouplingBlock(nn.Module): - def __init__( - self, - channels, - hidden_channels, - kernel_size, - dilation_rate, - n_layers, - n_flows=4, - gin_channels=0, - ): - super(ResidualCouplingBlock, self).__init__() - self.channels = channels - self.hidden_channels = hidden_channels - self.kernel_size = kernel_size - self.dilation_rate = dilation_rate - self.n_layers = n_layers - self.n_flows = n_flows - self.gin_channels = gin_channels - - self.flows = nn.ModuleList() - for i in range(n_flows): - self.flows.append( - modules.ResidualCouplingLayer( - channels, - hidden_channels, - kernel_size, - dilation_rate, - n_layers, - gin_channels=gin_channels, - mean_only=True, - ) - ) - self.flows.append(modules.Flip()) - - def forward( - self, - x, - x_mask, - g = None, - reverse = False, - ): - if not reverse: - for flow in self.flows: - x, _ = flow(x, x_mask, g=g, reverse=reverse) - else: - for flow in self.flows[::-1]: - x, _ = flow.forward(x, x_mask, g=g, reverse=reverse) - return x - - def remove_weight_norm(self): - for i in range(self.n_flows): - self.flows[i * 2].remove_weight_norm() - -class PosteriorEncoder(nn.Module): - def __init__( - self, - in_channels, - out_channels, - hidden_channels, - kernel_size, - dilation_rate, - n_layers, - gin_channels=0, - ): - super(PosteriorEncoder, self).__init__() - self.in_channels = in_channels - self.out_channels = out_channels - self.hidden_channels = hidden_channels - self.kernel_size = kernel_size - self.dilation_rate = dilation_rate - self.n_layers = n_layers - self.gin_channels = gin_channels - - self.pre = nn.Conv1d(in_channels, hidden_channels, 1) - self.enc = modules.WN( - hidden_channels, - kernel_size, - dilation_rate, - n_layers, - gin_channels=gin_channels, - ) - self.proj = nn.Conv1d(hidden_channels, out_channels * 2, 1) - - def forward( - self, x, x_lengths, g = None - ): - x_mask = torch.unsqueeze(commons.sequence_mask(x_lengths, x.size(2)), 1).to( - x.dtype - ) - x = self.pre(x) * x_mask - x = self.enc(x, x_mask, g=g) - stats = self.proj(x) * x_mask - m, logs = torch.split(stats, self.out_channels, dim=1) - z = (m + torch.randn_like(m) * torch.exp(logs)) * x_mask - return z, m, logs, x_mask - - def remove_weight_norm(self): - self.enc.remove_weight_norm() - -class Generator(torch.nn.Module): - def __init__( - self, - initial_channel, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - gin_channels=0, - ): - super(Generator, self).__init__() - self.num_kernels = len(resblock_kernel_sizes) - self.num_upsamples = len(upsample_rates) - self.conv_pre = Conv1d( - initial_channel, upsample_initial_channel, 7, 1, padding=3 - ) - resblock = modules.ResBlock1 if resblock == "1" else modules.ResBlock2 - - self.ups = nn.ModuleList() - for i, (u, k) in enumerate(zip(upsample_rates, upsample_kernel_sizes)): - self.ups.append( - weight_norm( - ConvTranspose1d( - upsample_initial_channel // (2**i), - upsample_initial_channel // (2 ** (i + 1)), - k, - u, - padding=(k - u) // 2, - ) - ) - ) - - self.resblocks = nn.ModuleList() - for i in range(len(self.ups)): - ch = upsample_initial_channel // (2 ** (i + 1)) - for j, (k, d) in enumerate( - zip(resblock_kernel_sizes, resblock_dilation_sizes) - ): - self.resblocks.append(resblock(ch, k, d)) - - self.conv_post = Conv1d(ch, 1, 7, 1, padding=3, bias=False) - self.ups.apply(init_weights) - - if gin_channels != 0: - self.cond = nn.Conv1d(gin_channels, upsample_initial_channel, 1) - - def forward( - self, - x, - g = None, - n_res = None, - ): - if n_res is not None: - n = int(n_res.item()) if isinstance(n_res, torch.Tensor) else int(n_res) - if n != x.shape[-1]: - x = F.interpolate(x, size=n, mode="linear") - x = self.conv_pre(x) - if g is not None: - x = x + self.cond(g) - - for i in range(self.num_upsamples): - x = F.leaky_relu(x, modules.LRELU_SLOPE) - x = self.ups[i](x) - xs = None - for j in range(self.num_kernels): - if xs is None: - xs = self.resblocks[i * self.num_kernels + j](x) - else: - xs += self.resblocks[i * self.num_kernels + j](x) - x = xs / self.num_kernels - x = F.leaky_relu(x) - x = self.conv_post(x) - x = torch.tanh(x) - - return x - - def remove_weight_norm(self): - for l in self.ups: - remove_weight_norm(l) - for l in self.resblocks: - l.remove_weight_norm() - - -class SineGen(torch.nn.Module): - """Definition of sine generator - SineGen(samp_rate, harmonic_num = 0, - sine_amp = 0.1, noise_std = 0.003, - voiced_threshold = 0, - flag_for_pulse=False) - samp_rate: sampling rate in Hz - harmonic_num: number of harmonic overtones (default 0) - sine_amp: amplitude of sine-wavefrom (default 0.1) - noise_std: std of Gaussian noise (default 0.003) - voiced_thoreshold: F0 threshold for U/V classification (default 0) - flag_for_pulse: this SinGen is used inside PulseGen (default False) - Note: when flag_for_pulse is True, the first time step of a voiced - segment is always sin(torch.pi) or cos(0) - """ - - def __init__( - self, - samp_rate, - harmonic_num=0, - sine_amp=0.1, - noise_std=0.003, - voiced_threshold=0, - flag_for_pulse=False, - ): - super(SineGen, self).__init__() - self.sine_amp = sine_amp - self.noise_std = noise_std - self.harmonic_num = harmonic_num - self.dim = self.harmonic_num + 1 - self.sampling_rate = samp_rate - self.voiced_threshold = voiced_threshold - - def _f02uv(self, f0): - # generate uv signal - uv = torch.ones_like(f0) - uv = uv * (f0 > self.voiced_threshold) - if uv.device.type == "privateuseone": # for DirectML - uv = uv.float() - return uv - - ### @yxlllc - def _f02sine(self, f0, upp): - rad = f0 / self.sampling_rate * torch.arange( - 1, upp + 1, device=f0.device - ) - rad2 = torch.fmod(rad[..., -1:].float() + 0.5, 1.0) - 0.5 - rad_acc = rad2.cumsum(dim=1).fmod(1.0).to(f0) - rad += F.pad(rad_acc, (0, 0, 1, -1)) - rad = rad.reshape(f0.shape[0], -1, 1) - rad = torch.multiply( - rad, - torch.arange(1, self.dim + 1, device=f0.device).reshape(1, 1, -1), - ) - rand_ini = torch.rand(1, 1, self.dim, device=f0.device) - rand_ini[..., 0] = 0 - rad += rand_ini - return torch.sin(2 * np.pi * rad) - - def forward(self, f0, upp): - """sine_tensor, uv = forward(f0) - input F0: tensor(batchsize=1, length, dim=1) - f0 for unvoiced steps should be 0 - output sine_tensor: tensor(batchsize=1, length, dim) - output uv: tensor(batchsize=1, length, 1) - """ - with torch.no_grad(): - f0 = f0[:, None].transpose(1, 2) - sine_waves = self._f02sine(f0, upp) * self.sine_amp - uv = self._f02uv(f0) - uv = F.interpolate( - uv.transpose(2, 1), scale_factor=float(upp), mode="nearest" - ).transpose(2, 1) - noise_amp = uv * self.noise_std + (1 - uv) * self.sine_amp / 3 - noise = noise_amp * torch.randn_like(sine_waves) - sine_waves = sine_waves * uv + noise - return sine_waves, uv, noise - - -class SourceModuleHnNSF(torch.nn.Module): - """SourceModule for hn-nsf - SourceModule(sampling_rate, harmonic_num=0, sine_amp=0.1, - add_noise_std=0.003, voiced_threshod=0) - sampling_rate: sampling_rate in Hz - harmonic_num: number of harmonic above F0 (default: 0) - sine_amp: amplitude of sine source signal (default: 0.1) - add_noise_std: std of additive Gaussian noise (default: 0.003) - note that amplitude of noise in unvoiced is decided - by sine_amp - voiced_threshold: threhold to set U/V given F0 (default: 0) - Sine_source, noise_source = SourceModuleHnNSF(F0_sampled) - F0_sampled (batchsize, length, 1) - Sine_source (batchsize, length, 1) - noise_source (batchsize, length 1) - uv (batchsize, length, 1) - """ - - def __init__( - self, - sampling_rate, - harmonic_num=0, - sine_amp=0.1, - add_noise_std=0.003, - voiced_threshod=0, - is_half=True, - ): - super(SourceModuleHnNSF, self).__init__() - - self.sine_amp = sine_amp - self.noise_std = add_noise_std - self.is_half = is_half - # to produce sine waveforms - self.l_sin_gen = SineGen( - sampling_rate, harmonic_num, sine_amp, add_noise_std, voiced_threshod - ) - - # to merge source harmonics into a single excitation - self.l_linear = torch.nn.Linear(harmonic_num + 1, 1) - self.l_tanh = torch.nn.Tanh() - # self.ddtype:int = -1 - - def forward(self, x, upp = 1): - # if self.ddtype ==-1: - # self.ddtype = self.l_linear.weight.dtype - sine_wavs, uv, _ = self.l_sin_gen(x, upp) - # print(x.dtype,sine_wavs.dtype,self.l_linear.weight.dtype) - # if self.is_half: - # sine_wavs = sine_wavs.half() - # sine_merge = self.l_tanh(self.l_linear(sine_wavs.to(x))) - # print(sine_wavs.dtype,self.ddtype) - # if sine_wavs.dtype != self.l_linear.weight.dtype: - sine_wavs = sine_wavs.to(dtype=self.l_linear.weight.dtype) - sine_merge = self.l_tanh(self.l_linear(sine_wavs)) - return sine_merge, None, None # noise, uv - - -class GeneratorNSF(torch.nn.Module): - def __init__( - self, - initial_channel, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - gin_channels, - sr, - is_half=False, - ): - super(GeneratorNSF, self).__init__() - self.num_kernels = len(resblock_kernel_sizes) - self.num_upsamples = len(upsample_rates) - - self.f0_upsamp = torch.nn.Upsample(scale_factor=math.prod(upsample_rates)) - self.m_source = SourceModuleHnNSF( - sampling_rate=sr, harmonic_num=0, is_half=is_half - ) - self.noise_convs = nn.ModuleList() - self.conv_pre = Conv1d( - initial_channel, upsample_initial_channel, 7, 1, padding=3 - ) - resblock = modules.ResBlock1 if resblock == "1" else modules.ResBlock2 - - self.ups = nn.ModuleList() - for i, (u, k) in enumerate(zip(upsample_rates, upsample_kernel_sizes)): - c_cur = upsample_initial_channel // (2 ** (i + 1)) - self.ups.append( - weight_norm( - ConvTranspose1d( - upsample_initial_channel // (2**i), - upsample_initial_channel // (2 ** (i + 1)), - k, - u, - padding=(k - u) // 2, - ) - ) - ) - if i + 1 < len(upsample_rates): - stride_f0 = math.prod(upsample_rates[i + 1 :]) - self.noise_convs.append( - Conv1d( - 1, - c_cur, - kernel_size=stride_f0 * 2, - stride=stride_f0, - padding=stride_f0 // 2, - ) - ) - else: - self.noise_convs.append(Conv1d(1, c_cur, kernel_size=1)) - - self.resblocks = nn.ModuleList() - for i in range(len(self.ups)): - ch = upsample_initial_channel // (2 ** (i + 1)) - for j, (k, d) in enumerate( - zip(resblock_kernel_sizes, resblock_dilation_sizes) - ): - self.resblocks.append(resblock(ch, k, d)) - - self.conv_post = Conv1d(ch, 1, 7, 1, padding=3, bias=False) - self.ups.apply(init_weights) - - if gin_channels != 0: - self.cond = nn.Conv1d(gin_channels, upsample_initial_channel, 1) - - self.upp = math.prod(upsample_rates) - - self.lrelu_slope = modules.LRELU_SLOPE - - def forward( - self, - x, - f0, - g = None, - n_res = None, - ): - har_source, noi_source, uv = self.m_source(f0, self.upp) - har_source = har_source.transpose(1, 2) - if n_res is not None: - n = int(n_res.item()) if isinstance(n_res, torch.Tensor) else int(n_res) - if n * self.upp != har_source.shape[-1]: - har_source = F.interpolate(har_source, size=n * self.upp, mode="linear") - if n != x.shape[-1]: - x = F.interpolate(x, size=n, mode="linear") - x = self.conv_pre(x) - if g is not None: - x = x + self.cond(g) - for i, (ups, noise_convs) in enumerate(zip(self.ups, self.noise_convs)): - if i < self.num_upsamples: - x = F.leaky_relu(x, self.lrelu_slope) - x = ups(x) - x_source = noise_convs(har_source) - x = x + x_source - xs = None - l = [i * self.num_kernels + j for j in range(self.num_kernels)] - for j, resblock in enumerate(self.resblocks): - if j in l: - if xs is None: - xs = resblock(x) - else: - xs += resblock(x) - assert isinstance(xs, torch.Tensor) - x = xs / self.num_kernels - x = F.leaky_relu(x) - x = self.conv_post(x) - x = torch.tanh(x) - - return x - - def remove_weight_norm(self): - for l in self.ups: - remove_weight_norm(l) - for l in self.resblocks: - l.remove_weight_norm() - -sr2sr = { - "32k": 32000, - "40k": 40000, - "48k": 48000, -} - - -class SynthesizerTrnMs256NSFsid(nn.Module): - def __init__( - self, - spec_channels, - segment_size, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - p_dropout, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - spk_embed_dim, - gin_channels, - sr, - **kwargs - ): - super(SynthesizerTrnMs256NSFsid, self).__init__() - if isinstance(sr, str): - sr = sr2sr[sr] - self.spec_channels = spec_channels - self.inter_channels = inter_channels - self.hidden_channels = hidden_channels - self.filter_channels = filter_channels - self.n_heads = n_heads - self.n_layers = n_layers - self.kernel_size = kernel_size - self.p_dropout = float(p_dropout) - self.resblock = resblock - self.resblock_kernel_sizes = resblock_kernel_sizes - self.resblock_dilation_sizes = resblock_dilation_sizes - self.upsample_rates = upsample_rates - self.upsample_initial_channel = upsample_initial_channel - self.upsample_kernel_sizes = upsample_kernel_sizes - self.segment_size = segment_size - self.gin_channels = gin_channels - # self.hop_length = hop_length# - self.spk_embed_dim = spk_embed_dim - self.enc_p = TextEncoder( - 256, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - float(p_dropout), - ) - self.dec = GeneratorNSF( - inter_channels, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - gin_channels=gin_channels, - sr=sr, - is_half=kwargs["is_half"], - ) - self.enc_q = PosteriorEncoder( - spec_channels, - inter_channels, - hidden_channels, - 5, - 1, - 16, - gin_channels=gin_channels, - ) - self.flow = ResidualCouplingBlock( - inter_channels, hidden_channels, 5, 1, 3, gin_channels=gin_channels - ) - self.emb_g = nn.Embedding(self.spk_embed_dim, gin_channels) - logger.debug( - "gin_channels: " - + str(gin_channels) - + ", self.spk_embed_dim: " - + str(self.spk_embed_dim) - ) - - def remove_weight_norm(self): - self.dec.remove_weight_norm() - self.flow.remove_weight_norm() - if hasattr(self, "enc_q"): - self.enc_q.remove_weight_norm() - - def forward( - self, - phone, - phone_lengths, - pitch, - pitchf, - y, - y_lengths, - ds = None, - ): # 这里ds是id,[bs,1] - # print(1,pitch.shape)#[bs,t] - g = self.emb_g(ds).unsqueeze(-1) # [b, 256, 1]##1是t,广播的 - m_p, logs_p, x_mask = self.enc_p(phone, pitch, phone_lengths) - z, m_q, logs_q, y_mask = self.enc_q(y, y_lengths, g=g) - z_p = self.flow(z, y_mask, g=g) - z_slice, ids_slice = commons.rand_slice_segments( - z, y_lengths, self.segment_size - ) - # print(-1,pitchf.shape,ids_slice,self.segment_size,self.hop_length,self.segment_size//self.hop_length) - pitchf = commons.slice_segments2(pitchf, ids_slice, self.segment_size) - # print(-2,pitchf.shape,z_slice.shape) - o = self.dec(z_slice, pitchf, g=g) - return o, ids_slice, x_mask, y_mask, (z, z_p, m_p, logs_p, m_q, logs_q) - - def infer( - self, - phone, - phone_lengths, - pitch, - nsff0, - sid, - skip_head = None, - return_length = None, - return_length2 = None, - ): - g = self.emb_g(sid).unsqueeze(-1) - if skip_head is not None and return_length is not None: - head = int(skip_head.item()) if isinstance(skip_head, torch.Tensor) else int(skip_head) - length = ( - int(return_length.item()) - if isinstance(return_length, torch.Tensor) - else int(return_length) - ) - flow_head = max(head - 24, 0) - dec_head = head - flow_head - m_p, logs_p, x_mask = self.enc_p(phone, pitch, phone_lengths, flow_head) - z_p = (m_p + torch.exp(logs_p) * torch.randn_like(m_p) * 0.66666) * x_mask - z = self.flow(z_p, x_mask, g=g, reverse=True) - z = z[:, :, dec_head : dec_head + length] - x_mask = x_mask[:, :, dec_head : dec_head + length] - nsff0 = nsff0[:, head : head + length] - else: - m_p, logs_p, x_mask = self.enc_p(phone, pitch, phone_lengths) - z_p = (m_p + torch.exp(logs_p) * torch.randn_like(m_p) * 0.66666) * x_mask - z = self.flow(z_p, x_mask, g=g, reverse=True) - o = self.dec(z * x_mask, nsff0, g=g, n_res=return_length2) - return o, x_mask, (z, z_p, m_p, logs_p) - - -class SynthesizerTrnMs768NSFsid(SynthesizerTrnMs256NSFsid): - def __init__( - self, - spec_channels, - segment_size, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - p_dropout, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - spk_embed_dim, - gin_channels, - sr, - **kwargs - ): - super(SynthesizerTrnMs768NSFsid, self).__init__( - spec_channels, - segment_size, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - p_dropout, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - spk_embed_dim, - gin_channels, - sr, - **kwargs - ) - del self.enc_p - self.enc_p = TextEncoder( - 768, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - float(p_dropout), - ) - - -class SynthesizerTrnMs256NSFsid_nono(nn.Module): - def __init__( - self, - spec_channels, - segment_size, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - p_dropout, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - spk_embed_dim, - gin_channels, - sr=None, - **kwargs - ): - super(SynthesizerTrnMs256NSFsid_nono, self).__init__() - self.spec_channels = spec_channels - self.inter_channels = inter_channels - self.hidden_channels = hidden_channels - self.filter_channels = filter_channels - self.n_heads = n_heads - self.n_layers = n_layers - self.kernel_size = kernel_size - self.p_dropout = float(p_dropout) - self.resblock = resblock - self.resblock_kernel_sizes = resblock_kernel_sizes - self.resblock_dilation_sizes = resblock_dilation_sizes - self.upsample_rates = upsample_rates - self.upsample_initial_channel = upsample_initial_channel - self.upsample_kernel_sizes = upsample_kernel_sizes - self.segment_size = segment_size - self.gin_channels = gin_channels - # self.hop_length = hop_length# - self.spk_embed_dim = spk_embed_dim - self.enc_p = TextEncoder( - 256, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - float(p_dropout), - f0=False, - ) - self.dec = Generator( - inter_channels, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - gin_channels=gin_channels, - ) - self.enc_q = PosteriorEncoder( - spec_channels, - inter_channels, - hidden_channels, - 5, - 1, - 16, - gin_channels=gin_channels, - ) - self.flow = ResidualCouplingBlock( - inter_channels, hidden_channels, 5, 1, 3, gin_channels=gin_channels - ) - self.emb_g = nn.Embedding(self.spk_embed_dim, gin_channels) - logger.debug( - "gin_channels: " - + str(gin_channels) - + ", self.spk_embed_dim: " - + str(self.spk_embed_dim) - ) - - def remove_weight_norm(self): - self.dec.remove_weight_norm() - self.flow.remove_weight_norm() - if hasattr(self, "enc_q"): - self.enc_q.remove_weight_norm() - - def forward(self, phone, phone_lengths, y, y_lengths, ds): # 这里ds是id,[bs,1] - g = self.emb_g(ds).unsqueeze(-1) # [b, 256, 1]##1是t,广播的 - m_p, logs_p, x_mask = self.enc_p(phone, None, phone_lengths) - z, m_q, logs_q, y_mask = self.enc_q(y, y_lengths, g=g) - z_p = self.flow(z, y_mask, g=g) - z_slice, ids_slice = commons.rand_slice_segments( - z, y_lengths, self.segment_size - ) - o = self.dec(z_slice, g=g) - return o, ids_slice, x_mask, y_mask, (z, z_p, m_p, logs_p, m_q, logs_q) - - def infer( - self, - phone, - phone_lengths, - sid, - skip_head = None, - return_length = None, - return_length2 = None, - ): - g = self.emb_g(sid).unsqueeze(-1) - if skip_head is not None and return_length is not None: - head = int(skip_head.item()) if isinstance(skip_head, torch.Tensor) else int(skip_head) - length = ( - int(return_length.item()) - if isinstance(return_length, torch.Tensor) - else int(return_length) - ) - flow_head = max(head - 24, 0) - dec_head = head - flow_head - m_p, logs_p, x_mask = self.enc_p(phone, None, phone_lengths, flow_head) - z_p = (m_p + torch.exp(logs_p) * torch.randn_like(m_p) * 0.66666) * x_mask - z = self.flow(z_p, x_mask, g=g, reverse=True) - z = z[:, :, dec_head : dec_head + length] - x_mask = x_mask[:, :, dec_head : dec_head + length] - else: - m_p, logs_p, x_mask = self.enc_p(phone, None, phone_lengths) - z_p = (m_p + torch.exp(logs_p) * torch.randn_like(m_p) * 0.66666) * x_mask - z = self.flow(z_p, x_mask, g=g, reverse=True) - o = self.dec(z * x_mask, g=g, n_res=return_length2) - return o, x_mask, (z, z_p, m_p, logs_p) - - -class SynthesizerTrnMs768NSFsid_nono(SynthesizerTrnMs256NSFsid_nono): - def __init__( - self, - spec_channels, - segment_size, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - p_dropout, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - spk_embed_dim, - gin_channels, - sr=None, - **kwargs - ): - super(SynthesizerTrnMs768NSFsid_nono, self).__init__( - spec_channels, - segment_size, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - p_dropout, - resblock, - resblock_kernel_sizes, - resblock_dilation_sizes, - upsample_rates, - upsample_initial_channel, - upsample_kernel_sizes, - spk_embed_dim, - gin_channels, - sr, - **kwargs - ) - del self.enc_p - self.enc_p = TextEncoder( - 768, - inter_channels, - hidden_channels, - filter_channels, - n_heads, - n_layers, - kernel_size, - float(p_dropout), - f0=False, - ) - - -class MultiPeriodDiscriminator(torch.nn.Module): - def __init__(self, use_spectral_norm=False): - super(MultiPeriodDiscriminator, self).__init__() - periods = [2, 3, 5, 7, 11, 17] - # periods = [3, 5, 7, 11, 17, 23, 37] - - discs = [DiscriminatorS(use_spectral_norm=use_spectral_norm)] - discs = discs + [ - DiscriminatorP(i, use_spectral_norm=use_spectral_norm) for i in periods - ] - self.discriminators = nn.ModuleList(discs) - - def forward(self, y, y_hat): - y_d_rs = [] # - y_d_gs = [] - fmap_rs = [] - fmap_gs = [] - for i, d in enumerate(self.discriminators): - y_d_r, fmap_r = d(y) - y_d_g, fmap_g = d(y_hat) - # for j in range(len(fmap_r)): - # print(i,j,y.shape,y_hat.shape,fmap_r[j].shape,fmap_g[j].shape) - y_d_rs.append(y_d_r) - y_d_gs.append(y_d_g) - fmap_rs.append(fmap_r) - fmap_gs.append(fmap_g) - - return y_d_rs, y_d_gs, fmap_rs, fmap_gs - - -class MultiPeriodDiscriminatorV2(torch.nn.Module): - def __init__(self, use_spectral_norm=False): - super(MultiPeriodDiscriminatorV2, self).__init__() - # periods = [2, 3, 5, 7, 11, 17] - periods = [2, 3, 5, 7, 11, 17, 23, 37] - - discs = [DiscriminatorS(use_spectral_norm=use_spectral_norm)] - discs = discs + [ - DiscriminatorP(i, use_spectral_norm=use_spectral_norm) for i in periods - ] - self.discriminators = nn.ModuleList(discs) - - def forward(self, y, y_hat): - y_d_rs = [] # - y_d_gs = [] - fmap_rs = [] - fmap_gs = [] - for i, d in enumerate(self.discriminators): - y_d_r, fmap_r = d(y) - y_d_g, fmap_g = d(y_hat) - # for j in range(len(fmap_r)): - # print(i,j,y.shape,y_hat.shape,fmap_r[j].shape,fmap_g[j].shape) - y_d_rs.append(y_d_r) - y_d_gs.append(y_d_g) - fmap_rs.append(fmap_r) - fmap_gs.append(fmap_g) - - return y_d_rs, y_d_gs, fmap_rs, fmap_gs - - -class DiscriminatorS(torch.nn.Module): - def __init__(self, use_spectral_norm=False): - super(DiscriminatorS, self).__init__() - norm_f = weight_norm if use_spectral_norm == False else spectral_norm - self.convs = nn.ModuleList( - [ - norm_f(Conv1d(1, 16, 15, 1, padding=7)), - norm_f(Conv1d(16, 64, 41, 4, groups=4, padding=20)), - norm_f(Conv1d(64, 256, 41, 4, groups=16, padding=20)), - norm_f(Conv1d(256, 1024, 41, 4, groups=64, padding=20)), - norm_f(Conv1d(1024, 1024, 41, 4, groups=256, padding=20)), - norm_f(Conv1d(1024, 1024, 5, 1, padding=2)), - ] - ) - self.conv_post = norm_f(Conv1d(1024, 1, 3, 1, padding=1)) - - def forward(self, x): - fmap = [] - - for l in self.convs: - x = l(x) - x = F.leaky_relu(x, modules.LRELU_SLOPE) - fmap.append(x) - x = self.conv_post(x) - fmap.append(x) - x = torch.flatten(x, 1, -1) - - return x, fmap - - -class DiscriminatorP(torch.nn.Module): - def __init__(self, period, kernel_size=5, stride=3, use_spectral_norm=False): - super(DiscriminatorP, self).__init__() - self.period = period - self.use_spectral_norm = use_spectral_norm - norm_f = weight_norm if use_spectral_norm == False else spectral_norm - self.convs = nn.ModuleList( - [ - norm_f( - Conv2d( - 1, - 32, - (kernel_size, 1), - (stride, 1), - padding=(get_padding(kernel_size, 1), 0), - ) - ), - norm_f( - Conv2d( - 32, - 128, - (kernel_size, 1), - (stride, 1), - padding=(get_padding(kernel_size, 1), 0), - ) - ), - norm_f( - Conv2d( - 128, - 512, - (kernel_size, 1), - (stride, 1), - padding=(get_padding(kernel_size, 1), 0), - ) - ), - norm_f( - Conv2d( - 512, - 1024, - (kernel_size, 1), - (stride, 1), - padding=(get_padding(kernel_size, 1), 0), - ) - ), - norm_f( - Conv2d( - 1024, - 1024, - (kernel_size, 1), - 1, - padding=(get_padding(kernel_size, 1), 0), - ) - ), - ] - ) - self.conv_post = norm_f(Conv2d(1024, 1, (3, 1), 1, padding=(1, 0))) - - def forward(self, x): - fmap = [] - - # 1d to 2d - b, c, t = x.shape - if t % self.period != 0: # pad first - n_pad = self.period - (t % self.period) - x = F.pad(x, (0, n_pad), "reflect") - t = t + n_pad - x = x.view(b, c, t // self.period, self.period) - - for l in self.convs: - x = l(x) - x = F.leaky_relu(x, modules.LRELU_SLOPE) - fmap.append(x) - x = self.conv_post(x) - fmap.append(x) - x = torch.flatten(x, 1, -1) - - return x, fmap diff --git a/infer/module/modules.py b/infer/module/modules.py deleted file mode 100644 index df73687949afb32c250e51885bb334ad3cf87885..0000000000000000000000000000000000000000 --- a/infer/module/modules.py +++ /dev/null @@ -1,548 +0,0 @@ -import copy -import math -from typing import Optional, Tuple - -import numpy as np -import scipy -import torch -from torch import nn -from torch.nn import AvgPool1d, Conv1d, Conv2d, ConvTranspose1d -from torch.nn import functional as F -from torch.nn.utils import remove_weight_norm, weight_norm - -from infer.module import commons -from infer.module.commons import get_padding, init_weights -from infer.module.transforms import piecewise_rational_quadratic_transform - -LRELU_SLOPE = 0.1 - - -class LayerNorm(nn.Module): - def __init__(self, channels, eps=1e-5): - super(LayerNorm, self).__init__() - self.channels = channels - self.eps = eps - - self.gamma = nn.Parameter(torch.ones(channels)) - self.beta = nn.Parameter(torch.zeros(channels)) - - def forward(self, x): - x = x.transpose(1, -1) - x = F.layer_norm(x, (self.channels,), self.gamma, self.beta, self.eps) - return x.transpose(1, -1) - - -class ConvReluNorm(nn.Module): - def __init__( - self, - in_channels, - hidden_channels, - out_channels, - kernel_size, - n_layers, - p_dropout, - ): - super(ConvReluNorm, self).__init__() - self.in_channels = in_channels - self.hidden_channels = hidden_channels - self.out_channels = out_channels - self.kernel_size = kernel_size - self.n_layers = n_layers - self.p_dropout = float(p_dropout) - assert n_layers > 1, "Number of layers should be larger than 0." - - self.conv_layers = nn.ModuleList() - self.norm_layers = nn.ModuleList() - self.conv_layers.append( - nn.Conv1d( - in_channels, hidden_channels, kernel_size, padding=kernel_size // 2 - ) - ) - self.norm_layers.append(LayerNorm(hidden_channels)) - self.relu_drop = nn.Sequential(nn.ReLU(), nn.Dropout(float(p_dropout))) - for _ in range(n_layers - 1): - self.conv_layers.append( - nn.Conv1d( - hidden_channels, - hidden_channels, - kernel_size, - padding=kernel_size // 2, - ) - ) - self.norm_layers.append(LayerNorm(hidden_channels)) - self.proj = nn.Conv1d(hidden_channels, out_channels, 1) - self.proj.weight.data.zero_() - self.proj.bias.data.zero_() - - def forward(self, x, x_mask): - x_org = x - for i in range(self.n_layers): - x = self.conv_layers[i](x * x_mask) - x = self.norm_layers[i](x) - x = self.relu_drop(x) - x = x_org + self.proj(x) - return x * x_mask - - -class DDSConv(nn.Module): - """ - Dialted and Depth-Separable Convolution - """ - - def __init__(self, channels, kernel_size, n_layers, p_dropout=0.0): - super(DDSConv, self).__init__() - self.channels = channels - self.kernel_size = kernel_size - self.n_layers = n_layers - self.p_dropout = float(p_dropout) - - self.drop = nn.Dropout(float(p_dropout)) - self.convs_sep = nn.ModuleList() - self.convs_1x1 = nn.ModuleList() - self.norms_1 = nn.ModuleList() - self.norms_2 = nn.ModuleList() - for i in range(n_layers): - dilation = kernel_size**i - padding = (kernel_size * dilation - dilation) // 2 - self.convs_sep.append( - nn.Conv1d( - channels, - channels, - kernel_size, - groups=channels, - dilation=dilation, - padding=padding, - ) - ) - self.convs_1x1.append(nn.Conv1d(channels, channels, 1)) - self.norms_1.append(LayerNorm(channels)) - self.norms_2.append(LayerNorm(channels)) - - def forward(self, x, x_mask, g = None): - if g is not None: - x = x + g - for i in range(self.n_layers): - y = self.convs_sep[i](x * x_mask) - y = self.norms_1[i](y) - y = F.gelu(y) - y = self.convs_1x1[i](y) - y = self.norms_2[i](y) - y = F.gelu(y) - y = self.drop(y) - x = x + y - return x * x_mask - - -class WN(torch.nn.Module): - def __init__( - self, - hidden_channels, - kernel_size, - dilation_rate, - n_layers, - gin_channels=0, - p_dropout=0, - ): - super(WN, self).__init__() - assert kernel_size % 2 == 1 - self.hidden_channels = hidden_channels - self.kernel_size = (kernel_size,) - self.dilation_rate = dilation_rate - self.n_layers = n_layers - self.gin_channels = gin_channels - self.p_dropout = float(p_dropout) - - self.in_layers = torch.nn.ModuleList() - self.res_skip_layers = torch.nn.ModuleList() - self.drop = nn.Dropout(float(p_dropout)) - - if gin_channels != 0: - cond_layer = torch.nn.Conv1d( - gin_channels, 2 * hidden_channels * n_layers, 1 - ) - self.cond_layer = torch.nn.utils.weight_norm(cond_layer, name="weight") - - for i in range(n_layers): - dilation = dilation_rate**i - padding = int((kernel_size * dilation - dilation) / 2) - in_layer = torch.nn.Conv1d( - hidden_channels, - 2 * hidden_channels, - kernel_size, - dilation=dilation, - padding=padding, - ) - in_layer = torch.nn.utils.weight_norm(in_layer, name="weight") - self.in_layers.append(in_layer) - - # last one is not necessary - if i < n_layers - 1: - res_skip_channels = 2 * hidden_channels - else: - res_skip_channels = hidden_channels - - res_skip_layer = torch.nn.Conv1d(hidden_channels, res_skip_channels, 1) - res_skip_layer = torch.nn.utils.weight_norm(res_skip_layer, name="weight") - self.res_skip_layers.append(res_skip_layer) - - def forward( - self, x, x_mask, g = None - ): - output = torch.zeros_like(x) - n_channels_tensor = torch.IntTensor([self.hidden_channels]) - - if g is not None: - g = self.cond_layer(g) - - for i, (in_layer, res_skip_layer) in enumerate( - zip(self.in_layers, self.res_skip_layers) - ): - x_in = in_layer(x) - if g is not None: - cond_offset = i * 2 * self.hidden_channels - g_l = g[:, cond_offset : cond_offset + 2 * self.hidden_channels, :] - else: - g_l = torch.zeros_like(x_in) - - acts = commons.fused_add_tanh_sigmoid_multiply(x_in, g_l, n_channels_tensor) - acts = self.drop(acts) - - res_skip_acts = res_skip_layer(acts) - if i < self.n_layers - 1: - res_acts = res_skip_acts[:, : self.hidden_channels, :] - x = (x + res_acts) * x_mask - output = output + res_skip_acts[:, self.hidden_channels :, :] - else: - output = output + res_skip_acts - return output * x_mask - - def remove_weight_norm(self): - if self.gin_channels != 0: - torch.nn.utils.remove_weight_norm(self.cond_layer) - for l in self.in_layers: - torch.nn.utils.remove_weight_norm(l) - for l in self.res_skip_layers: - torch.nn.utils.remove_weight_norm(l) - -class ResBlock1(torch.nn.Module): - def __init__(self, channels, kernel_size=3, dilation=(1, 3, 5)): - super(ResBlock1, self).__init__() - self.convs1 = nn.ModuleList( - [ - weight_norm( - Conv1d( - channels, - channels, - kernel_size, - 1, - dilation=dilation[0], - padding=get_padding(kernel_size, dilation[0]), - ) - ), - weight_norm( - Conv1d( - channels, - channels, - kernel_size, - 1, - dilation=dilation[1], - padding=get_padding(kernel_size, dilation[1]), - ) - ), - weight_norm( - Conv1d( - channels, - channels, - kernel_size, - 1, - dilation=dilation[2], - padding=get_padding(kernel_size, dilation[2]), - ) - ), - ] - ) - self.convs1.apply(init_weights) - - self.convs2 = nn.ModuleList( - [ - weight_norm( - Conv1d( - channels, - channels, - kernel_size, - 1, - dilation=1, - padding=get_padding(kernel_size, 1), - ) - ), - weight_norm( - Conv1d( - channels, - channels, - kernel_size, - 1, - dilation=1, - padding=get_padding(kernel_size, 1), - ) - ), - weight_norm( - Conv1d( - channels, - channels, - kernel_size, - 1, - dilation=1, - padding=get_padding(kernel_size, 1), - ) - ), - ] - ) - self.convs2.apply(init_weights) - self.lrelu_slope = LRELU_SLOPE - - def forward(self, x, x_mask = None): - for c1, c2 in zip(self.convs1, self.convs2): - xt = F.leaky_relu(x, self.lrelu_slope) - if x_mask is not None: - xt = xt * x_mask - xt = c1(xt) - xt = F.leaky_relu(xt, self.lrelu_slope) - if x_mask is not None: - xt = xt * x_mask - xt = c2(xt) - x = xt + x - if x_mask is not None: - x = x * x_mask - return x - - def remove_weight_norm(self): - for l in self.convs1: - remove_weight_norm(l) - for l in self.convs2: - remove_weight_norm(l) - -class ResBlock2(torch.nn.Module): - def __init__(self, channels, kernel_size=3, dilation=(1, 3)): - super(ResBlock2, self).__init__() - self.convs = nn.ModuleList( - [ - weight_norm( - Conv1d( - channels, - channels, - kernel_size, - 1, - dilation=dilation[0], - padding=get_padding(kernel_size, dilation[0]), - ) - ), - weight_norm( - Conv1d( - channels, - channels, - kernel_size, - 1, - dilation=dilation[1], - padding=get_padding(kernel_size, dilation[1]), - ) - ), - ] - ) - self.convs.apply(init_weights) - self.lrelu_slope = LRELU_SLOPE - - def forward(self, x, x_mask = None): - for c in self.convs: - xt = F.leaky_relu(x, self.lrelu_slope) - if x_mask is not None: - xt = xt * x_mask - xt = c(xt) - x = xt + x - if x_mask is not None: - x = x * x_mask - return x - - def remove_weight_norm(self): - for l in self.convs: - remove_weight_norm(l) - -class Log(nn.Module): - def forward( - self, - x, - x_mask, - g = None, - reverse = False, - ) : - if not reverse: - y = torch.log(torch.clamp_min(x, 1e-5)) * x_mask - logdet = torch.sum(-y, [1, 2]) - return y, logdet - else: - x = torch.exp(x) * x_mask - return x - - -class Flip(nn.Module): - def forward( - self, - x, - x_mask, - g = None, - reverse = False, - ) : - x = torch.flip(x, [1]) - if not reverse: - logdet = torch.zeros(x.size(0)).to(dtype=x.dtype, device=x.device) - return x, logdet - else: - return x, torch.zeros([1], device=x.device) - - -class ElementwiseAffine(nn.Module): - def __init__(self, channels): - super(ElementwiseAffine, self).__init__() - self.channels = channels - self.m = nn.Parameter(torch.zeros(channels, 1)) - self.logs = nn.Parameter(torch.zeros(channels, 1)) - - def forward(self, x, x_mask, reverse=False, **kwargs): - if not reverse: - y = self.m + torch.exp(self.logs) * x - y = y * x_mask - logdet = torch.sum(self.logs * x_mask, [1, 2]) - return y, logdet - else: - x = (x - self.m) * torch.exp(-self.logs) * x_mask - return x - - -class ResidualCouplingLayer(nn.Module): - def __init__( - self, - channels, - hidden_channels, - kernel_size, - dilation_rate, - n_layers, - p_dropout=0, - gin_channels=0, - mean_only=False, - ): - assert channels % 2 == 0, "channels should be divisible by 2" - super(ResidualCouplingLayer, self).__init__() - self.channels = channels - self.hidden_channels = hidden_channels - self.kernel_size = kernel_size - self.dilation_rate = dilation_rate - self.n_layers = n_layers - self.half_channels = channels // 2 - self.mean_only = mean_only - - self.pre = nn.Conv1d(self.half_channels, hidden_channels, 1) - self.enc = WN( - hidden_channels, - kernel_size, - dilation_rate, - n_layers, - p_dropout=float(p_dropout), - gin_channels=gin_channels, - ) - self.post = nn.Conv1d(hidden_channels, self.half_channels * (2 - mean_only), 1) - self.post.weight.data.zero_() - self.post.bias.data.zero_() - - def forward( - self, - x, - x_mask, - g = None, - reverse = False, - ): - x0, x1 = torch.split(x, [self.half_channels] * 2, 1) - h = self.pre(x0) * x_mask - h = self.enc(h, x_mask, g=g) - stats = self.post(h) * x_mask - if not self.mean_only: - m, logs = torch.split(stats, [self.half_channels] * 2, 1) - else: - m = stats - logs = torch.zeros_like(m) - - if not reverse: - x1 = m + x1 * torch.exp(logs) * x_mask - x = torch.cat([x0, x1], 1) - logdet = torch.sum(logs, [1, 2]) - return x, logdet - else: - x1 = (x1 - m) * torch.exp(-logs) * x_mask - x = torch.cat([x0, x1], 1) - return x, torch.zeros([1]) - - def remove_weight_norm(self): - self.enc.remove_weight_norm() - -class ConvFlow(nn.Module): - def __init__( - self, - in_channels, - filter_channels, - kernel_size, - n_layers, - num_bins=10, - tail_bound=5.0, - ): - super(ConvFlow, self).__init__() - self.in_channels = in_channels - self.filter_channels = filter_channels - self.kernel_size = kernel_size - self.n_layers = n_layers - self.num_bins = num_bins - self.tail_bound = tail_bound - self.half_channels = in_channels // 2 - - self.pre = nn.Conv1d(self.half_channels, filter_channels, 1) - self.convs = DDSConv(filter_channels, kernel_size, n_layers, p_dropout=0.0) - self.proj = nn.Conv1d( - filter_channels, self.half_channels * (num_bins * 3 - 1), 1 - ) - self.proj.weight.data.zero_() - self.proj.bias.data.zero_() - - def forward( - self, - x, - x_mask, - g = None, - reverse=False, - ): - x0, x1 = torch.split(x, [self.half_channels] * 2, 1) - h = self.pre(x0) - h = self.convs(h, x_mask, g=g) - h = self.proj(h) * x_mask - - b, c, t = x0.shape - h = h.reshape(b, c, -1, t).permute(0, 1, 3, 2) # [b, cx?, t] -> [b, c, t, ?] - - unnormalized_widths = h[..., : self.num_bins] / math.sqrt(self.filter_channels) - unnormalized_heights = h[..., self.num_bins : 2 * self.num_bins] / math.sqrt( - self.filter_channels - ) - unnormalized_derivatives = h[..., 2 * self.num_bins :] - - x1, logabsdet = piecewise_rational_quadratic_transform( - x1, - unnormalized_widths, - unnormalized_heights, - unnormalized_derivatives, - inverse=reverse, - tails="linear", - tail_bound=self.tail_bound, - ) - - x = torch.cat([x0, x1], 1) * x_mask - logdet = torch.sum(logabsdet * x_mask, [1, 2]) - if not reverse: - return x, logdet - else: - return x diff --git a/infer/module/transforms.py b/infer/module/transforms.py deleted file mode 100644 index 6d07b3b12cee87869440feb1496dd634d334e96f..0000000000000000000000000000000000000000 --- a/infer/module/transforms.py +++ /dev/null @@ -1,207 +0,0 @@ -import numpy as np -import torch -from torch.nn import functional as F - -DEFAULT_MIN_BIN_WIDTH = 1e-3 -DEFAULT_MIN_BIN_HEIGHT = 1e-3 -DEFAULT_MIN_DERIVATIVE = 1e-3 - - -def piecewise_rational_quadratic_transform( - inputs, - unnormalized_widths, - unnormalized_heights, - unnormalized_derivatives, - inverse=False, - tails=None, - tail_bound=1.0, - min_bin_width=DEFAULT_MIN_BIN_WIDTH, - min_bin_height=DEFAULT_MIN_BIN_HEIGHT, - min_derivative=DEFAULT_MIN_DERIVATIVE, -): - if tails is None: - spline_fn = rational_quadratic_spline - spline_kwargs = {} - else: - spline_fn = unconstrained_rational_quadratic_spline - spline_kwargs = {"tails": tails, "tail_bound": tail_bound} - - outputs, logabsdet = spline_fn( - inputs=inputs, - unnormalized_widths=unnormalized_widths, - unnormalized_heights=unnormalized_heights, - unnormalized_derivatives=unnormalized_derivatives, - inverse=inverse, - min_bin_width=min_bin_width, - min_bin_height=min_bin_height, - min_derivative=min_derivative, - **spline_kwargs - ) - return outputs, logabsdet - - -def searchsorted(bin_locations, inputs, eps=1e-6): - bin_locations[..., -1] += eps - return torch.sum(inputs[..., None] >= bin_locations, dim=-1) - 1 - - -def unconstrained_rational_quadratic_spline( - inputs, - unnormalized_widths, - unnormalized_heights, - unnormalized_derivatives, - inverse=False, - tails="linear", - tail_bound=1.0, - min_bin_width=DEFAULT_MIN_BIN_WIDTH, - min_bin_height=DEFAULT_MIN_BIN_HEIGHT, - min_derivative=DEFAULT_MIN_DERIVATIVE, -): - inside_interval_mask = (inputs >= -tail_bound) & (inputs <= tail_bound) - outside_interval_mask = ~inside_interval_mask - - outputs = torch.zeros_like(inputs) - logabsdet = torch.zeros_like(inputs) - - if tails == "linear": - unnormalized_derivatives = F.pad(unnormalized_derivatives, pad=(1, 1)) - constant = np.log(np.exp(1 - min_derivative) - 1) - unnormalized_derivatives[..., 0] = constant - unnormalized_derivatives[..., -1] = constant - - outputs[outside_interval_mask] = inputs[outside_interval_mask] - logabsdet[outside_interval_mask] = 0 - else: - raise RuntimeError("{} tails are not implemented.".format(tails)) - - ( - outputs[inside_interval_mask], - logabsdet[inside_interval_mask], - ) = rational_quadratic_spline( - inputs=inputs[inside_interval_mask], - unnormalized_widths=unnormalized_widths[inside_interval_mask, :], - unnormalized_heights=unnormalized_heights[inside_interval_mask, :], - unnormalized_derivatives=unnormalized_derivatives[inside_interval_mask, :], - inverse=inverse, - left=-tail_bound, - right=tail_bound, - bottom=-tail_bound, - top=tail_bound, - min_bin_width=min_bin_width, - min_bin_height=min_bin_height, - min_derivative=min_derivative, - ) - - return outputs, logabsdet - - -def rational_quadratic_spline( - inputs, - unnormalized_widths, - unnormalized_heights, - unnormalized_derivatives, - inverse=False, - left=0.0, - right=1.0, - bottom=0.0, - top=1.0, - min_bin_width=DEFAULT_MIN_BIN_WIDTH, - min_bin_height=DEFAULT_MIN_BIN_HEIGHT, - min_derivative=DEFAULT_MIN_DERIVATIVE, -): - if torch.min(inputs) < left or torch.max(inputs) > right: - raise ValueError("Input to a transform is not within its domain") - - num_bins = unnormalized_widths.shape[-1] - - if min_bin_width * num_bins > 1.0: - raise ValueError("Minimal bin width too large for the number of bins") - if min_bin_height * num_bins > 1.0: - raise ValueError("Minimal bin height too large for the number of bins") - - widths = F.softmax(unnormalized_widths, dim=-1) - widths = min_bin_width + (1 - min_bin_width * num_bins) * widths - cumwidths = torch.cumsum(widths, dim=-1) - cumwidths = F.pad(cumwidths, pad=(1, 0), mode="constant", value=0.0) - cumwidths = (right - left) * cumwidths + left - cumwidths[..., 0] = left - cumwidths[..., -1] = right - widths = cumwidths[..., 1:] - cumwidths[..., :-1] - - derivatives = min_derivative + F.softplus(unnormalized_derivatives) - - heights = F.softmax(unnormalized_heights, dim=-1) - heights = min_bin_height + (1 - min_bin_height * num_bins) * heights - cumheights = torch.cumsum(heights, dim=-1) - cumheights = F.pad(cumheights, pad=(1, 0), mode="constant", value=0.0) - cumheights = (top - bottom) * cumheights + bottom - cumheights[..., 0] = bottom - cumheights[..., -1] = top - heights = cumheights[..., 1:] - cumheights[..., :-1] - - if inverse: - bin_idx = searchsorted(cumheights, inputs)[..., None] - else: - bin_idx = searchsorted(cumwidths, inputs)[..., None] - - input_cumwidths = cumwidths.gather(-1, bin_idx)[..., 0] - input_bin_widths = widths.gather(-1, bin_idx)[..., 0] - - input_cumheights = cumheights.gather(-1, bin_idx)[..., 0] - delta = heights / widths - input_delta = delta.gather(-1, bin_idx)[..., 0] - - input_derivatives = derivatives.gather(-1, bin_idx)[..., 0] - input_derivatives_plus_one = derivatives[..., 1:].gather(-1, bin_idx)[..., 0] - - input_heights = heights.gather(-1, bin_idx)[..., 0] - - if inverse: - a = (inputs - input_cumheights) * ( - input_derivatives + input_derivatives_plus_one - 2 * input_delta - ) + input_heights * (input_delta - input_derivatives) - b = input_heights * input_derivatives - (inputs - input_cumheights) * ( - input_derivatives + input_derivatives_plus_one - 2 * input_delta - ) - c = -input_delta * (inputs - input_cumheights) - - discriminant = b.pow(2) - 4 * a * c - assert (discriminant >= 0).all() - - root = (2 * c) / (-b - torch.sqrt(discriminant)) - outputs = root * input_bin_widths + input_cumwidths - - theta_one_minus_theta = root * (1 - root) - denominator = input_delta + ( - (input_derivatives + input_derivatives_plus_one - 2 * input_delta) - * theta_one_minus_theta - ) - derivative_numerator = input_delta.pow(2) * ( - input_derivatives_plus_one * root.pow(2) - + 2 * input_delta * theta_one_minus_theta - + input_derivatives * (1 - root).pow(2) - ) - logabsdet = torch.log(derivative_numerator) - 2 * torch.log(denominator) - - return outputs, -logabsdet - else: - theta = (inputs - input_cumwidths) / input_bin_widths - theta_one_minus_theta = theta * (1 - theta) - - numerator = input_heights * ( - input_delta * theta.pow(2) + input_derivatives * theta_one_minus_theta - ) - denominator = input_delta + ( - (input_derivatives + input_derivatives_plus_one - 2 * input_delta) - * theta_one_minus_theta - ) - outputs = input_cumheights + numerator / denominator - - derivative_numerator = input_delta.pow(2) * ( - input_derivatives_plus_one * theta.pow(2) - + 2 * input_delta * theta_one_minus_theta - + input_derivatives * (1 - theta).pow(2) - ) - logabsdet = torch.log(derivative_numerator) - 2 * torch.log(denominator) - - return outputs, logabsdet diff --git a/infer/rmvpe.py b/infer/rmvpe.py deleted file mode 100644 index f0496bdba0042d97fe2dd8e18086d6aabb26e98b..0000000000000000000000000000000000000000 --- a/infer/rmvpe.py +++ /dev/null @@ -1,658 +0,0 @@ -import os -from typing import List, Optional, Tuple -import numpy as np -import torch - -import torch.nn as nn -import torch.nn.functional as F -from librosa.util import normalize, pad_center, tiny -from scipy.signal import get_window - -from tools.cuda_graph import run_cuda_graph - -import logging - -logger = logging.getLogger(__name__) - - -class STFT(torch.nn.Module): - def __init__( - self, filter_length=1024, hop_length=512, win_length=None, window="hann" - ): - """ - This module implements an STFT using 1D convolution and 1D transpose convolutions. - This is a bit tricky so there are some cases that probably won't work as working - out the same sizes before and after in all overlap add setups is tough. Right now, - this code should work with hop lengths that are half the filter length (50% overlap - between frames). - - Keyword Arguments: - filter_length {int} -- Length of filters used (default: {1024}) - hop_length {int} -- Hop length of STFT (restrict to 50% overlap between frames) (default: {512}) - win_length {[type]} -- Length of the window function applied to each frame (if not specified, it - equals the filter length). (default: {None}) - window {str} -- Type of window to use (options are bartlett, hann, hamming, blackman, blackmanharris) - (default: {'hann'}) - """ - super(STFT, self).__init__() - self.filter_length = filter_length - self.hop_length = hop_length - self.win_length = win_length if win_length else filter_length - self.window = window - self.forward_transform = None - self.pad_amount = int(self.filter_length / 2) - fourier_basis = np.fft.fft(np.eye(self.filter_length)) - - cutoff = int((self.filter_length / 2 + 1)) - fourier_basis = np.vstack( - [np.real(fourier_basis[:cutoff, :]), np.imag(fourier_basis[:cutoff, :])] - ) - forward_basis = torch.FloatTensor(fourier_basis) - inverse_basis = torch.FloatTensor(np.linalg.pinv(fourier_basis)) - - assert filter_length >= self.win_length - # get window and zero center pad it to filter_length - fft_window = get_window(window, self.win_length, fftbins=True) - fft_window = pad_center(fft_window, size=filter_length) - fft_window = torch.from_numpy(fft_window).float() - - # window the bases - forward_basis *= fft_window - inverse_basis = (inverse_basis.T * fft_window).T - - self.register_buffer("forward_basis", forward_basis.float()) - self.register_buffer("inverse_basis", inverse_basis.float()) - self.register_buffer("fft_window", fft_window.float()) - - def transform(self, input_data, return_phase=False): - """Take input data (audio) to STFT domain. - - Arguments: - input_data {tensor} -- Tensor of floats, with shape (num_batch, num_samples) - - Returns: - magnitude {tensor} -- Magnitude of STFT with shape (num_batch, - num_frequencies, num_frames) - phase {tensor} -- Phase of STFT with shape (num_batch, - num_frequencies, num_frames) - """ - input_data = F.pad( - input_data, - (self.pad_amount, self.pad_amount), - mode="reflect", - ) - forward_transform = input_data.unfold( - 1, self.filter_length, self.hop_length - ).permute(0, 2, 1) - forward_transform = torch.matmul(self.forward_basis, forward_transform) - cutoff = int((self.filter_length / 2) + 1) - real_part = forward_transform[:, :cutoff, :] - imag_part = forward_transform[:, cutoff:, :] - magnitude = torch.sqrt(real_part**2 + imag_part**2) - if return_phase: - phase = torch.atan2(imag_part.data, real_part.data) - return magnitude, phase - else: - return magnitude - - def inverse(self, magnitude, phase): - """Call the inverse STFT (iSTFT), given magnitude and phase tensors produced - by the ```transform``` function. - - Arguments: - magnitude {tensor} -- Magnitude of STFT with shape (num_batch, - num_frequencies, num_frames) - phase {tensor} -- Phase of STFT with shape (num_batch, - num_frequencies, num_frames) - - Returns: - inverse_transform {tensor} -- Reconstructed audio given magnitude and phase. Of - shape (num_batch, num_samples) - """ - cat = torch.cat( - [magnitude * torch.cos(phase), magnitude * torch.sin(phase)], dim=1 - ) - fold = torch.nn.Fold( - output_size=(1, (cat.size(-1) - 1) * self.hop_length + self.filter_length), - kernel_size=(1, self.filter_length), - stride=(1, self.hop_length), - ) - inverse_transform = torch.matmul(self.inverse_basis, cat) - inverse_transform = fold(inverse_transform)[ - :, 0, 0, self.pad_amount : -self.pad_amount - ] - window_square_sum = ( - self.fft_window.pow(2).repeat(cat.size(-1), 1).T.unsqueeze(0) - ) - window_square_sum = fold(window_square_sum)[ - :, 0, 0, self.pad_amount : -self.pad_amount - ] - inverse_transform /= window_square_sum - return inverse_transform - - def forward(self, input_data): - """Take input data (audio) to STFT domain and then back to audio. - - Arguments: - input_data {tensor} -- Tensor of floats, with shape (num_batch, num_samples) - - Returns: - reconstruction {tensor} -- Reconstructed audio given magnitude and phase. Of - shape (num_batch, num_samples) - """ - self.magnitude, self.phase = self.transform(input_data, return_phase=True) - reconstruction = self.inverse(self.magnitude, self.phase) - return reconstruction - - -from time import time as ttime - - -class BiGRU(nn.Module): - def __init__(self, input_features, hidden_features, num_layers): - super(BiGRU, self).__init__() - self.gru = nn.GRU( - input_features, - hidden_features, - num_layers=num_layers, - batch_first=True, - bidirectional=True, - ) - - def forward(self, x): - return self.gru(x)[0] - - -class ConvBlockRes(nn.Module): - def __init__(self, in_channels, out_channels, momentum=0.01): - super(ConvBlockRes, self).__init__() - self.conv = nn.Sequential( - nn.Conv2d( - in_channels=in_channels, - out_channels=out_channels, - kernel_size=(3, 3), - stride=(1, 1), - padding=(1, 1), - bias=False, - ), - nn.BatchNorm2d(out_channels, momentum=momentum), - nn.ReLU(), - nn.Conv2d( - in_channels=out_channels, - out_channels=out_channels, - kernel_size=(3, 3), - stride=(1, 1), - padding=(1, 1), - bias=False, - ), - nn.BatchNorm2d(out_channels, momentum=momentum), - nn.ReLU(), - ) - # self.shortcut:Optional[nn.Module] = None - if in_channels != out_channels: - self.shortcut = nn.Conv2d(in_channels, out_channels, (1, 1)) - - def forward(self, x): - if not hasattr(self, "shortcut"): - return self.conv(x) + x - else: - return self.conv(x) + self.shortcut(x) - - -class Encoder(nn.Module): - def __init__( - self, - in_channels, - in_size, - n_encoders, - kernel_size, - n_blocks, - out_channels=16, - momentum=0.01, - ): - super(Encoder, self).__init__() - self.n_encoders = n_encoders - self.bn = nn.BatchNorm2d(in_channels, momentum=momentum) - self.layers = nn.ModuleList() - self.latent_channels = [] - for i in range(self.n_encoders): - self.layers.append( - ResEncoderBlock( - in_channels, out_channels, kernel_size, n_blocks, momentum=momentum - ) - ) - self.latent_channels.append([out_channels, in_size]) - in_channels = out_channels - out_channels *= 2 - in_size //= 2 - self.out_size = in_size - self.out_channel = out_channels - - def forward(self, x): - concat_tensors = [] - x = self.bn(x) - for i, layer in enumerate(self.layers): - t, x = layer(x) - concat_tensors.append(t) - return x, concat_tensors - - -class ResEncoderBlock(nn.Module): - def __init__( - self, in_channels, out_channels, kernel_size, n_blocks=1, momentum=0.01 - ): - super(ResEncoderBlock, self).__init__() - self.n_blocks = n_blocks - self.conv = nn.ModuleList() - self.conv.append(ConvBlockRes(in_channels, out_channels, momentum)) - for i in range(n_blocks - 1): - self.conv.append(ConvBlockRes(out_channels, out_channels, momentum)) - self.kernel_size = kernel_size - if self.kernel_size is not None: - self.pool = nn.AvgPool2d(kernel_size=kernel_size) - - def forward(self, x): - for i, conv in enumerate(self.conv): - x = conv(x) - if self.kernel_size is not None: - return x, self.pool(x) - else: - return x - - -class Intermediate(nn.Module): # - def __init__(self, in_channels, out_channels, n_inters, n_blocks, momentum=0.01): - super(Intermediate, self).__init__() - self.n_inters = n_inters - self.layers = nn.ModuleList() - self.layers.append( - ResEncoderBlock(in_channels, out_channels, None, n_blocks, momentum) - ) - for i in range(self.n_inters - 1): - self.layers.append( - ResEncoderBlock(out_channels, out_channels, None, n_blocks, momentum) - ) - - def forward(self, x): - for i, layer in enumerate(self.layers): - x = layer(x) - return x - - -class ResDecoderBlock(nn.Module): - def __init__(self, in_channels, out_channels, stride, n_blocks=1, momentum=0.01): - super(ResDecoderBlock, self).__init__() - out_padding = (0, 1) if stride == (1, 2) else (1, 1) - self.n_blocks = n_blocks - self.conv1 = nn.Sequential( - nn.ConvTranspose2d( - in_channels=in_channels, - out_channels=out_channels, - kernel_size=(3, 3), - stride=stride, - padding=(1, 1), - output_padding=out_padding, - bias=False, - ), - nn.BatchNorm2d(out_channels, momentum=momentum), - nn.ReLU(), - ) - self.conv2 = nn.ModuleList() - self.conv2.append(ConvBlockRes(out_channels * 2, out_channels, momentum)) - for i in range(n_blocks - 1): - self.conv2.append(ConvBlockRes(out_channels, out_channels, momentum)) - - def forward(self, x, concat_tensor): - x = self.conv1(x) - x = torch.cat((x, concat_tensor), dim=1) - for i, conv2 in enumerate(self.conv2): - x = conv2(x) - return x - - -class Decoder(nn.Module): - def __init__(self, in_channels, n_decoders, stride, n_blocks, momentum=0.01): - super(Decoder, self).__init__() - self.layers = nn.ModuleList() - self.n_decoders = n_decoders - for i in range(self.n_decoders): - out_channels = in_channels // 2 - self.layers.append( - ResDecoderBlock(in_channels, out_channels, stride, n_blocks, momentum) - ) - in_channels = out_channels - - def forward(self, x, concat_tensors): - for i, layer in enumerate(self.layers): - x = layer(x, concat_tensors[-1 - i]) - return x - - -class DeepUnet(nn.Module): - def __init__( - self, - kernel_size, - n_blocks, - en_de_layers=5, - inter_layers=4, - in_channels=1, - en_out_channels=16, - ): - super(DeepUnet, self).__init__() - self.encoder = Encoder( - in_channels, 128, en_de_layers, kernel_size, n_blocks, en_out_channels - ) - self.intermediate = Intermediate( - self.encoder.out_channel // 2, - self.encoder.out_channel, - inter_layers, - n_blocks, - ) - self.decoder = Decoder( - self.encoder.out_channel, en_de_layers, kernel_size, n_blocks - ) - - def forward(self, x) : - x, concat_tensors = self.encoder(x) - x = self.intermediate(x) - x = self.decoder(x, concat_tensors) - return x - - -class E2E(nn.Module): - def __init__( - self, - n_blocks, - n_gru, - kernel_size, - en_de_layers=5, - inter_layers=4, - in_channels=1, - en_out_channels=16, - ): - super(E2E, self).__init__() - self.unet = DeepUnet( - kernel_size, - n_blocks, - en_de_layers, - inter_layers, - in_channels, - en_out_channels, - ) - self.cnn = nn.Conv2d(en_out_channels, 3, (3, 3), padding=(1, 1)) - if n_gru: - self.fc = nn.Sequential( - BiGRU(3 * 128, 256, n_gru), - nn.Linear(512, 360), - nn.Dropout(0.25), - nn.Sigmoid(), - ) - else: - self.fc = nn.Sequential( - nn.Linear(3 * nn.N_MELS, nn.N_CLASS), nn.Dropout(0.25), nn.Sigmoid() - ) - - def forward(self, mel): - # print(mel.shape) - mel = mel.transpose(-1, -2).unsqueeze(1) - x = self.cnn(self.unet(mel)).transpose(1, 2).flatten(-2) - x = self.fc(x) - # print(x.shape) - return x - - -from librosa.filters import mel - - -class MelSpectrogram(torch.nn.Module): - def __init__( - self, - is_half, - n_mel_channels, - sampling_rate, - win_length, - hop_length, - n_fft=None, - mel_fmin=0, - mel_fmax=None, - clamp=1e-5, - ): - super().__init__() - n_fft = win_length if n_fft is None else n_fft - self.hann_window = {} - mel_basis = mel( - sr=sampling_rate, - n_fft=n_fft, - n_mels=n_mel_channels, - fmin=mel_fmin, - fmax=mel_fmax, - htk=True, - ) - mel_basis = torch.from_numpy(mel_basis).float() - self.register_buffer("mel_basis", mel_basis) - self.n_fft = win_length if n_fft is None else n_fft - self.hop_length = hop_length - self.win_length = win_length - self.sampling_rate = sampling_rate - self.n_mel_channels = n_mel_channels - self.clamp = clamp - self.is_half = is_half - - def forward(self, audio, keyshift=0, speed=1, center=True): - factor = 2 ** (keyshift / 12) - n_fft_new = int(np.round(self.n_fft * factor)) - win_length_new = int(np.round(self.win_length * factor)) - hop_length_new = int(np.round(self.hop_length * speed)) - keyshift_key = str(keyshift) + "_" + str(audio.device) - if keyshift_key not in self.hann_window: - self.hann_window[keyshift_key] = torch.hann_window(win_length_new).to( - audio.device - ) - if "privateuseone" in str(audio.device): - if not hasattr(self, "stft"): - self.stft = STFT( - filter_length=n_fft_new, - hop_length=hop_length_new, - win_length=win_length_new, - window="hann", - ).to(audio.device) - magnitude = self.stft.transform(audio) - else: - fft = torch.stft( - audio, - n_fft=n_fft_new, - hop_length=hop_length_new, - win_length=win_length_new, - window=self.hann_window[keyshift_key], - center=center, - return_complex=True, - ) - magnitude = torch.sqrt(fft.real.pow(2) + fft.imag.pow(2)) - if keyshift != 0: - size = self.n_fft // 2 + 1 - resize = magnitude.size(1) - if resize < size: - magnitude = F.pad(magnitude, (0, 0, 0, size - resize)) - magnitude = magnitude[:, :size, :] * self.win_length / win_length_new - mel_output = torch.matmul(self.mel_basis, magnitude) - if self.is_half == True: - mel_output = mel_output.half() - log_mel_spec = torch.log(torch.clamp(mel_output, min=self.clamp)) - return log_mel_spec - - -class RMVPE: - def __init__(self, model_path, is_half, device=None): - self.resample_kernel = {} - self.resample_kernel = {} - if isinstance(is_half, str): - is_half = is_half.lower() == "true" - if device is None: - from configs.config import infer_device, infer_dtype - - device = str(infer_device) - is_half = infer_dtype == torch.float16 - elif str(device).startswith("cuda"): - from configs.config import get_device_dtype_sm - - parsed_device = torch.device(device) - device_index = parsed_device.index - if device_index is None: - device_index = torch.cuda.current_device() - selected_device, selected_dtype, _, _ = get_device_dtype_sm(device_index) - device = str(selected_device) - is_half = selected_dtype == torch.float16 - else: - is_half = False - self.is_half = is_half - self.device = device - self.mel_extractor = MelSpectrogram( - is_half, 128, 16000, 1024, 160, None, 30, 8000 - ).to(device) - if "privateuseone" in str(device): - import onnxruntime as ort - - ort_session = ort.InferenceSession( - os.path.splitext(model_path)[0] + ".onnx", - providers=["DmlExecutionProvider"], - ) - self.model = ort_session - else: - if str(self.device) == "cuda": - self.device = torch.device("cuda:0") - - def get_default_model(): - model = E2E(4, 1, (2, 2)) - ckpt = torch.load(model_path, map_location="cpu") - model.load_state_dict(ckpt) - model.eval() - if is_half: - model = model.half() - else: - model = model.float() - return model - - self.model = get_default_model() - - self.model = self.model.to(device) - cents_mapping = 20 * np.arange(360) + 1997.3794084376191 - self.cents_mapping = np.pad(cents_mapping, (4, 4)) # 368 - - def mel2hidden(self, mel): - with torch.no_grad(): - n_frames = mel.shape[-1] - n_pad = 32 * ((n_frames - 1) // 32 + 1) - n_frames - if n_pad > 0: - mel = F.pad(mel, (0, n_pad), mode="constant") - if "privateuseone" in str(self.device): - onnx_input_name = self.model.get_inputs()[0].name - onnx_outputs_names = self.model.get_outputs()[0].name - hidden = self.model.run( - [onnx_outputs_names], - input_feed={onnx_input_name: mel.cpu().numpy()}, - )[0] - else: - mel = mel.half() if self.is_half else mel.float() - hidden = run_cuda_graph( - self.model, - "rmvpe-network", - lambda input_mel: self.model(input_mel), - mel, - ) - return hidden[:, :n_frames] - - def extract_mel(self, audio, center=True): - if not torch.is_tensor(audio): - audio = torch.from_numpy(audio) - audio = audio.float().to(self.device) - if audio.dim() == 1: - audio = audio.unsqueeze(0) - if "privateuseone" in str(self.device): - return self.mel_extractor(audio, center=center) - return run_cuda_graph( - self.mel_extractor, - "rmvpe-mel-center-%s" % int(bool(center)), - lambda input_audio: self.mel_extractor(input_audio, center=center), - audio, - ) - - def decode(self, hidden, thred=0.03): - cents_pred = self.to_local_average_cents(hidden, thred=thred) - f0 = 10 * (2 ** (cents_pred / 1200)) - f0[f0 == 10] = 0 - # f0 = np.array([10 * (2 ** (cent_pred / 1200)) if cent_pred else 0 for cent_pred in cents_pred]) - return f0 - - def infer_from_audio(self, audio, thred=0.03): - # torch.cuda.synchronize() - # t0 = ttime() - mel = self.extract_mel(audio, center=True) - # print(123123123,mel.device.type) - # torch.cuda.synchronize() - # t1 = ttime() - hidden = self.mel2hidden(mel) - # torch.cuda.synchronize() - # t2 = ttime() - # print(234234,hidden.device.type) - if "privateuseone" not in str(self.device): - hidden = hidden.squeeze(0).cpu().numpy() - else: - hidden = hidden[0] - if self.is_half == True: - hidden = hidden.astype("float32") - - f0 = self.decode(hidden, thred=thred) - # torch.cuda.synchronize() - # t3 = ttime() - # print("hmvpe:%s\t%s\t%s\t%s"%(t1-t0,t2-t1,t3-t2,t3-t0)) - return f0 - - def to_local_average_cents(self, salience, thred=0.05): - # t0 = ttime() - center = np.argmax(salience, axis=1) # 帧长#index - salience = np.pad(salience, ((0, 0), (4, 4))) # 帧长,368 - # t1 = ttime() - center += 4 - todo_salience = [] - todo_cents_mapping = [] - starts = center - 4 - ends = center + 5 - for idx in range(salience.shape[0]): - todo_salience.append(salience[:, starts[idx] : ends[idx]][idx]) - todo_cents_mapping.append(self.cents_mapping[starts[idx] : ends[idx]]) - # t2 = ttime() - todo_salience = np.array(todo_salience) # 帧长,9 - todo_cents_mapping = np.array(todo_cents_mapping) # 帧长,9 - product_sum = np.sum(todo_salience * todo_cents_mapping, 1) - weight_sum = np.sum(todo_salience, 1) # 帧长 - devided = product_sum / weight_sum # 帧长 - # t3 = ttime() - maxx = np.max(salience, axis=1) # 帧长 - devided[maxx <= thred] = 0 - # t4 = ttime() - # print("decode:%s\t%s\t%s\t%s" % (t1 - t0, t2 - t1, t3 - t2, t4 - t3)) - return devided - - -if __name__ == "__main__": - import librosa - import soundfile as sf - - audio, sampling_rate = sf.read(r"C:\Users\liujing04\Desktop\Z\冬之花clip1.wav") - if len(audio.shape) > 1: - audio = librosa.to_mono(audio.transpose(1, 0)) - audio_bak = audio.copy() - if sampling_rate != 16000: - audio = librosa.resample(audio, orig_sr=sampling_rate, target_sr=16000) - model_path = r"D:\BaiduNetdiskDownload\RVC-beta-v2-0727AMD_realtime\rmvpe.pt" - thred = 0.03 # 0.01 - device = "cuda" if torch.cuda.is_available() else "cpu" - rmvpe = RMVPE(model_path, is_half=False, device=device) - t0 = ttime() - f0 = rmvpe.infer_from_audio(audio, thred=thred) - # f0 = rmvpe.infer_from_audio(audio, thred=thred) - # f0 = rmvpe.infer_from_audio(audio, thred=thred) - # f0 = rmvpe.infer_from_audio(audio, thred=thred) - # f0 = rmvpe.infer_from_audio(audio, thred=thred) - t1 = ttime() - logger.info("%s %.2f", f0.shape, t1 - t0) diff --git a/infer/rtrvc.py b/infer/rtrvc.py deleted file mode 100644 index ecd6b31699fa2600aa3b2c9338065ce3e263e0f8..0000000000000000000000000000000000000000 --- a/infer/rtrvc.py +++ /dev/null @@ -1,365 +0,0 @@ -import traceback -from time import time as ttime -import faiss -import numpy as np -import parselmouth -import torch -import torch.nn as nn -import torch.nn.functional as F -from torchaudio.transforms import Resample - -from infer.hubert import extract_hubert_features, load_hubert_model -from i18n.i18n import I18nAuto -from tools.cuda_graph import run_cuda_graph - - -i18n = I18nAuto() - - -def printt(strr, *args): - if len(args) == 0: - print(strr) - else: - print(strr % args) - - -def get_synthesizer(pth_path, device=torch.device("cpu")): - from infer.module.models import ( - SynthesizerTrnMs256NSFsid, - SynthesizerTrnMs256NSFsid_nono, - SynthesizerTrnMs768NSFsid, - SynthesizerTrnMs768NSFsid_nono, - ) - - cpt = torch.load(pth_path, map_location=torch.device("cpu")) - cpt["config"][-3] = cpt["weight"]["emb_g.weight"].shape[0] - if_f0 = cpt.get("f0", 1) - version = cpt.get("version", "v1") - if version == "v1": - if if_f0 == 1: - net_g = SynthesizerTrnMs256NSFsid(*cpt["config"], is_half=False) - else: - net_g = SynthesizerTrnMs256NSFsid_nono(*cpt["config"]) - elif version == "v2": - if if_f0 == 1: - net_g = SynthesizerTrnMs768NSFsid(*cpt["config"], is_half=False) - else: - net_g = SynthesizerTrnMs768NSFsid_nono(*cpt["config"]) - del net_g.enc_q - net_g.load_state_dict(cpt["weight"], strict=False) - net_g = net_g.float() - net_g.eval().to(device) - net_g.remove_weight_norm() - return net_g, cpt - - -# config.device=torch.device("cpu")########强制cpu测试 -# config.is_half=False########强制cpu测试 -class RVC: - def __init__( - self, - key, - formant, - pth_path, - index_path, - index_rate, - config, - last_rvc=None, - ) : - """ - 初始化 - """ - try: - # global config - self.config = config - # device="cpu"########强制cpu测试 - self.device = config.device - self.f0_up_key = key - self.formant_shift = formant - self.f0_min = 50 - self.f0_max = 1100 - self.f0_mel_min = 1127 * np.log(1 + self.f0_min / 700) - self.f0_mel_max = 1127 * np.log(1 + self.f0_max / 700) - self.is_half = config.is_half - if index_rate != 0: - self.index = faiss.read_index(index_path) - self.big_npy = self.index.reconstruct_n(0, self.index.ntotal) - printt(i18n("已启用索引检索")) - self.pth_path = pth_path - self.index_path = index_path - self.index_rate = index_rate - self.cache_pitch = torch.zeros( - 1024, device=self.device, dtype=torch.long - ) - self.cache_pitchf = torch.zeros( - 1024, device=self.device, dtype=torch.float32 - ) - self.infer_count = 0 - - self.resample_kernel = {} - - if last_rvc is None: - self.model = load_hubert_model(self.device, self.is_half) - else: - self.model = last_rvc.model - - self.net_g = None - - def set_synthesizer(): - self.net_g, cpt = get_synthesizer(self.pth_path, self.device) - self.tgt_sr = cpt["config"][-1] - cpt["config"][-3] = cpt["weight"]["emb_g.weight"].shape[0] - self.if_f0 = cpt.get("f0", 1) - self.version = cpt.get("version", "v1") - if self.is_half: - self.net_g = self.net_g.half() - else: - self.net_g = self.net_g.float() - - if last_rvc is None or last_rvc.pth_path != self.pth_path: - set_synthesizer() - else: - self.tgt_sr = last_rvc.tgt_sr - self.if_f0 = last_rvc.if_f0 - self.version = last_rvc.version - self.is_half = last_rvc.is_half - self.net_g = last_rvc.net_g - - if last_rvc is not None and hasattr(last_rvc, "model_rmvpe"): - self.model_rmvpe = last_rvc.model_rmvpe - if last_rvc is not None and hasattr(last_rvc, "model_fcpe"): - self.model_fcpe = last_rvc.model_fcpe - except: - printt(traceback.format_exc()) - - def change_key(self, new_key): - self.f0_up_key = new_key - - def change_formant(self, new_formant): - self.formant_shift = new_formant - - def change_index_rate(self, new_index_rate): - if new_index_rate != 0 and self.index_rate == 0: - self.index = faiss.read_index(self.index_path) - self.big_npy = self.index.reconstruct_n(0, self.index.ntotal) - printt(i18n("已启用索引检索")) - self.index_rate = new_index_rate - - def get_f0_post(self, f0): - if not torch.is_tensor(f0): - f0 = torch.from_numpy(f0) - f0 = f0.float().to(self.device).squeeze() - f0_mel = 1127 * torch.log(1 + f0 / 700) - f0_mel[f0_mel > 0] = (f0_mel[f0_mel > 0] - self.f0_mel_min) * 254 / ( - self.f0_mel_max - self.f0_mel_min - ) + 1 - f0_mel[f0_mel <= 1] = 1 - f0_mel[f0_mel > 255] = 255 - f0_coarse = torch.round(f0_mel).long() - return f0_coarse, f0 - - def get_f0(self, x, f0_up_key, method="rmvpe"): - if method == "rmvpe": - return self.get_f0_rmvpe(x, f0_up_key) - if method == "fcpe": - return self.get_f0_fcpe(x, f0_up_key) - if method != "pm": - raise ValueError(f"Unsupported F0 method: {method}") - x = x.cpu().numpy() - p_len = x.shape[0] // 160 + 1 - f0_min = 65 - l_pad = int(np.ceil(1.5 / f0_min * 16000)) - r_pad = l_pad + 1 - s = parselmouth.Sound(np.pad(x, (l_pad, r_pad)), 16000).to_pitch_ac( - time_step=0.01, - voicing_threshold=0.6, - pitch_floor=f0_min, - pitch_ceiling=1100, - ) - assert np.abs(s.t1 - 1.5 / f0_min) < 0.001 - f0 = s.selected_array["frequency"] - if len(f0) < p_len: - f0 = np.pad(f0, (0, p_len - len(f0))) - f0 = f0[:p_len] - uv = f0 == 0 - if np.any(~uv): - f0[uv] = np.interp(np.where(uv)[0], np.where(~uv)[0], f0[~uv]) - f0 *= pow(2, f0_up_key / 12) - return self.get_f0_post(f0) - - def get_f0_rmvpe(self, x, f0_up_key): - if hasattr(self, "model_rmvpe") == False: - from infer.rmvpe import RMVPE - - printt(i18n("正在加载RMVPE模型")) - self.model_rmvpe = RMVPE( - "assets/rmvpe/rmvpe.pt", - is_half=self.is_half, - device=self.device, - ) - f0 = self.model_rmvpe.infer_from_audio(x, thred=0.03) - uv = f0 == 0 - if np.any(~uv): - f0[uv] = np.interp(np.where(uv)[0], np.where(~uv)[0], f0[~uv]) - f0 *= pow(2, f0_up_key / 12) - return self.get_f0_post(f0) - - def get_f0_fcpe(self, x, f0_up_key): - if hasattr(self, "model_fcpe") == False: - from infer.fcpe import FCPEInfer - - printt("Loading fcpe model") - self.model_fcpe = FCPEInfer(self.device) - f0 = self.model_fcpe.infer( - x.unsqueeze(0).float(), - sr=16000, - decoder_mode="local_argmax", - threshold=0.006, - ).squeeze().detach().cpu().numpy() - uv = f0 == 0 - if np.any(~uv): - f0[uv] = np.interp(np.where(uv)[0], np.where(~uv)[0], f0[~uv]) - f0 *= pow(2, f0_up_key / 12) - return self.get_f0_post(f0) - - def infer( - self, - input_wav, - block_frame_16k, - skip_head, - return_length, - f0method, - ) : - report_status = self.infer_count < 3 or self.infer_count % 100 == 0 - self.infer_count += 1 - t1 = ttime() - with torch.no_grad(): - if self.config.is_half: - feats = input_wav.half().view(1, -1) - else: - feats = input_wav.float().view(1, -1) - padding_mask = torch.BoolTensor(feats.shape).to(self.device).fill_(False) - feats = extract_hubert_features( - self.model, - feats, - self.version, - padding_mask=padding_mask, - ) - feats = torch.cat((feats, feats[:, -1:, :]), 1) - t2 = ttime() - try: - if hasattr(self, "index") and self.index_rate != 0: - npy = feats[0][skip_head // 2 :].cpu().numpy().astype("float32") - score, ix = self.index.search(npy, k=8) - if (ix >= 0).all(): - weight = np.square(1 / score) - weight /= weight.sum(axis=1, keepdims=True) - npy = np.sum( - self.big_npy[ix] * np.expand_dims(weight, axis=2), axis=1 - ) - if self.config.is_half: - npy = npy.astype("float16") - feats[0][skip_head // 2 :] = ( - torch.from_numpy(npy).unsqueeze(0).to(self.device) - * self.index_rate - + (1 - self.index_rate) * feats[0][skip_head // 2 :] - ) - else: - printt( - i18n("索引无效:必须使用added_xxxx.index,不能使用trained_xxxx.index") - ) - else: - if report_status: - printt(i18n("索引检索失败或未启用")) - except Exception: - traceback.print_exc() - printt(i18n("索引检索失败")) - t3 = ttime() - p_len = input_wav.shape[0] // 160 - factor = pow(2, self.formant_shift / 12) - return_length2 = int(np.ceil(return_length * factor)) - if self.if_f0 == 1: - f0_extractor_frame = block_frame_16k + 800 - if f0method == "rmvpe": - f0_extractor_frame = 5120 * ((f0_extractor_frame - 1) // 5120 + 1) - 160 - pitch, pitchf = self.get_f0( - input_wav[-f0_extractor_frame:], - self.f0_up_key - self.formant_shift, - f0method, - ) - shift = block_frame_16k // 160 - self.cache_pitch[:-shift] = self.cache_pitch[shift:].clone() - self.cache_pitchf[:-shift] = self.cache_pitchf[shift:].clone() - self.cache_pitch[4 - pitch.shape[0] :] = pitch[3:-1] - self.cache_pitchf[4 - pitch.shape[0] :] = pitchf[3:-1] - cache_pitch = self.cache_pitch[None, -p_len:] - cache_pitchf = self.cache_pitchf[None, -p_len:] * return_length2 / return_length - t4 = ttime() - feats = F.interpolate(feats.permute(0, 2, 1), scale_factor=2).permute(0, 2, 1) - feats = feats[:, :p_len, :] - p_len_tensor = torch.LongTensor([p_len]).to(self.device) - sid = torch.LongTensor([0]).to(self.device) - skip_head_value = int(skip_head) - return_length_value = int(return_length) - return_length2_value = int(return_length2) - with torch.no_grad(): - if self.if_f0 == 1: - infered_audio = run_cuda_graph( - self.net_g, - "rvc-realtime-f0-%s-%s-%s" - % (skip_head_value, return_length_value, return_length2_value), - lambda phone, lengths, coarse, continuous, speaker: self.net_g.infer( - phone, - lengths, - coarse, - continuous, - speaker, - skip_head_value, - return_length_value, - return_length2_value, - )[0], - feats, - p_len_tensor, - cache_pitch, - cache_pitchf, - sid, - ) - else: - infered_audio = run_cuda_graph( - self.net_g, - "rvc-realtime-no-f0-%s-%s-%s" - % (skip_head_value, return_length_value, return_length2_value), - lambda phone, lengths, speaker: self.net_g.infer( - phone, - lengths, - speaker, - skip_head_value, - return_length_value, - return_length2_value, - )[0], - feats, - p_len_tensor, - sid, - ) - infered_audio = infered_audio.squeeze(1).float() - upp_res = int(np.floor(factor * self.tgt_sr // 100)) - if upp_res != self.tgt_sr // 100: - if upp_res not in self.resample_kernel: - self.resample_kernel[upp_res] = Resample( - orig_freq=upp_res, - new_freq=self.tgt_sr // 100, - dtype=torch.float32, - ).to(self.device) - infered_audio = self.resample_kernel[upp_res]( - infered_audio[:, : return_length * upp_res] - ) - t5 = ttime() - if report_status: - printt( - i18n("耗时:特征=%.3f秒,索引=%.3f秒,音高=%.3f秒,模型=%.3f秒"), - t2 - t1, - t3 - t2, - t4 - t3, - t5 - t4, - ) - return infered_audio.squeeze() diff --git a/infer/vc/__init__.py b/infer/vc/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/infer/vc/modules.py b/infer/vc/modules.py deleted file mode 100644 index 0fd9354857d350362890b4c7d005b29158c7f9e5..0000000000000000000000000000000000000000 --- a/infer/vc/modules.py +++ /dev/null @@ -1,427 +0,0 @@ -import traceback -import logging - -logger = logging.getLogger(__name__) - -import numpy as np -import soundfile as sf -import torch -from io import BytesIO - -from infer.audio import load_audio, wav2 -from infer.module.models import ( - SynthesizerTrnMs256NSFsid, - SynthesizerTrnMs256NSFsid_nono, - SynthesizerTrnMs768NSFsid, - SynthesizerTrnMs768NSFsid_nono, -) -from infer.vc.pipeline import Pipeline -from infer.vc.utils import * -from i18n.i18n import I18nAuto -from tools.progress import batch_status, should_report -from tools.cuda_graph import clear_cuda_graph_cache - - -i18n = I18nAuto() - - -def inference_status(title, state, detail=""): - lines = ["【%s】" % i18n(title), "%s:%s" % (i18n("状态"), i18n(state))] - if detail: - lines.extend(["", str(detail).strip()]) - return "\n".join(lines) - - -def normalized_speaker_info(checkpoint, n_spk): - speaker_info = [] - seen = set() - for item in checkpoint.get("speaker_info", []): - try: - speaker_id = int(item["id"]) - speaker_name = str(item["name"]) - except (KeyError, TypeError, ValueError): - continue - if ( - speaker_id < 0 - or speaker_id >= n_spk - or not speaker_name - or speaker_id in seen - ): - continue - seen.add(speaker_id) - speaker_info.append({"id": speaker_id, "name": speaker_name}) - speaker_info.sort(key=lambda item: item["id"]) - return speaker_info - - -def speaker_selector_updates(checkpoint, n_spk): - speaker_info = normalized_speaker_info(checkpoint, n_spk) - if speaker_info: - choices = [ - i18n("说话人:%s(ID:%s)") % (item["name"], item["id"]) - for item in speaker_info - ] - return ( - { - "visible": False, - "value": speaker_info[0]["id"], - "__type__": "update", - }, - { - "visible": True, - "choices": choices, - "value": choices[0], - "__type__": "update", - }, - ) - return ( - { - "visible": True, - "maximum": max(n_spk - 1, 0), - "__type__": "update", - }, - {"visible": False, "value": None, "__type__": "update"}, - ) - - -class VC: - def __init__(self, config): - self.n_spk = None - self.tgt_sr = None - self.net_g = None - self.pipeline = None - self.cpt = None - self.version = None - self.if_f0 = None - self.version = None - self.hubert_model = None - - self.config = config - - def get_vc(self, sid, *to_return_protect): - logger.info("%s: %s", i18n("选择模型"), sid) - - to_return_protect0 = { - "visible": self.if_f0 != 0, - "value": ( - to_return_protect[0] if self.if_f0 != 0 and to_return_protect else 0.5 - ), - "__type__": "update", - } - to_return_protect1 = { - "visible": self.if_f0 != 0, - "value": ( - to_return_protect[1] if self.if_f0 != 0 and to_return_protect else 0.33 - ), - "__type__": "update", - } - - if sid == "" or sid == []: - if ( - self.hubert_model is not None - ): # 考虑到轮询, 需要加个判断看是否 sid 是由有模型切换到无模型的 - logger.info(i18n("清理模型缓存")) - clear_cuda_graph_cache(self.net_g) - clear_cuda_graph_cache(self.hubert_model) - del (self.net_g, self.n_spk, self.hubert_model, self.tgt_sr) # ,cpt - self.hubert_model = self.net_g = self.n_spk = self.hubert_model = ( - self.tgt_sr - ) = None - if torch.cuda.is_available(): - torch.cuda.empty_cache() - ###楼下不这么折腾清理不干净 - self.if_f0 = self.cpt.get("f0", 1) - self.version = self.cpt.get("version", "v1") - if self.version == "v1": - if self.if_f0 == 1: - self.net_g = SynthesizerTrnMs256NSFsid( - *self.cpt["config"], is_half=self.config.is_half - ) - else: - self.net_g = SynthesizerTrnMs256NSFsid_nono(*self.cpt["config"]) - elif self.version == "v2": - if self.if_f0 == 1: - self.net_g = SynthesizerTrnMs768NSFsid( - *self.cpt["config"], is_half=self.config.is_half - ) - else: - self.net_g = SynthesizerTrnMs768NSFsid_nono(*self.cpt["config"]) - del self.net_g, self.cpt - if torch.cuda.is_available(): - torch.cuda.empty_cache() - return ( - {"visible": False, "__type__": "update"}, - {"visible": False, "value": None, "__type__": "update"}, - { - "visible": True, - "value": to_return_protect0, - "__type__": "update", - }, - { - "visible": True, - "value": to_return_protect1, - "__type__": "update", - }, - "", - "", - ) - person = f'{os.getenv("weight_root")}/{sid}' - logger.info("%s: %s", i18n("正在加载模型"), person) - - if self.net_g is not None: - clear_cuda_graph_cache(self.net_g) - - self.cpt = torch.load(person, map_location="cpu") - self.tgt_sr = self.cpt["config"][-1] - self.cpt["config"][-3] = self.cpt["weight"]["emb_g.weight"].shape[0] # n_spk - self.if_f0 = self.cpt.get("f0", 1) - self.version = self.cpt.get("version", "v1") - - synthesizer_class = { - ("v1", 1): SynthesizerTrnMs256NSFsid, - ("v1", 0): SynthesizerTrnMs256NSFsid_nono, - ("v2", 1): SynthesizerTrnMs768NSFsid, - ("v2", 0): SynthesizerTrnMs768NSFsid_nono, - } - - self.net_g = synthesizer_class.get( - (self.version, self.if_f0), SynthesizerTrnMs256NSFsid - )(*self.cpt["config"], is_half=self.config.is_half) - - del self.net_g.enc_q - - self.net_g.load_state_dict(self.cpt["weight"], strict=False) - self.net_g.eval().to(self.config.device) - if self.config.is_half: - self.net_g = self.net_g.half() - else: - self.net_g = self.net_g.float() - - self.pipeline = Pipeline(self.tgt_sr, self.config) - n_spk = self.cpt["config"][-3] - speaker_info = normalized_speaker_info(self.cpt, n_spk) - speaker_slider_update, speaker_dropdown_update = speaker_selector_updates( - self.cpt, n_spk - ) - default_speaker_id = speaker_info[0]["id"] if speaker_info else 0 - index = { - "value": get_index_path_from_model(sid, default_speaker_id), - "__type__": "update", - } - logger.info("%s: %s", i18n("选择索引"), index["value"]) - - return ( - ( - speaker_slider_update, - speaker_dropdown_update, - to_return_protect0, - to_return_protect1, - index, - index, - ) - if to_return_protect - else speaker_slider_update - ) - - def vc_single( - self, - sid, - input_audio_path, - f0_up_key, - f0_method, - file_index, - index_rate, - resample_sr, - rms_mix_rate, - protect, - ): - if input_audio_path is None: - return inference_status("单次推理", "等待输入", i18n("请上传音频文件")), None - f0_up_key = int(f0_up_key) - try: - audio = load_audio(input_audio_path, 16000) - audio_max = np.abs(audio).max() / 0.95 - if audio_max > 1: - audio /= audio_max - times = [0, 0, 0] - - if self.hubert_model is None: - self.hubert_model = load_hubert(self.config) - - if file_index: - file_index = ( - file_index.strip(" ") - .strip('"') - .strip("\n") - .strip('"') - .strip(" ") - .replace("trained", "added") - ) - else: - file_index = "" # 防止小白写错,自动帮他替换掉 - - audio_opt = self.pipeline.pipeline( - self.hubert_model, - self.net_g, - sid, - audio, - times, - f0_up_key, - f0_method, - file_index, - index_rate, - self.if_f0, - self.tgt_sr, - resample_sr, - rms_mix_rate, - self.version, - protect, - ) - if self.tgt_sr != resample_sr >= 16000: - tgt_sr = resample_sr - else: - tgt_sr = self.tgt_sr - index_info = ( - "%s:%s" % (i18n("索引"), file_index) - if os.path.exists(file_index) - else "%s:%s" % (i18n("索引"), i18n("未使用")) - ) - return ( - inference_status( - "单次推理", - "成功", - "%s\n%s:%s %.2fs | F0 %.2fs | %s %.2fs" - % ( - index_info, - i18n("耗时"), - i18n("特征"), - times[0], - times[1], - i18n("合成"), - times[2], - ), - ), - (tgt_sr, audio_opt), - ) - except Exception: - info = traceback.format_exc() - logger.warning(info) - return inference_status("单次推理", "失败", info), (None, None) - - def vc_multi( - self, - sid, - dir_path, - opt_root, - paths, - f0_up_key, - f0_method, - file_index, - index_rate, - resample_sr, - rms_mix_rate, - protect, - format1, - ): - try: - dir_path = ( - (dir_path or "") - .strip(" ") - .strip('"') - .strip("\n") - .strip('"') - .strip(" ") - ) # 防止小白拷路径头尾带了空格和"和回车 - opt_root = ( - (opt_root or "") - .strip(" ") - .strip('"') - .strip("\n") - .strip('"') - .strip(" ") - ) - if not opt_root: - yield inference_status( - "批量推理", "等待输入", i18n("请填写输出文件夹路径") - ) - return - os.makedirs(opt_root, exist_ok=True) - try: - if dir_path != "": - paths = [ - os.path.join(dir_path, name) for name in os.listdir(dir_path) - ] - else: - paths = [path if isinstance(path, str) else path.name for path in (paths or [])] - except Exception: - traceback.print_exc() - paths = [ - path if isinstance(path, str) else path.name for path in (paths or []) - ] - total = len(paths) - if total == 0: - yield batch_status(i18n("批量推理"), 0, 0, 0, 0) - return - success = 0 - failed = 0 - failures = [] - for idx, path in enumerate(paths): - item_failed = False - info, opt = self.vc_single( - sid, - path, - f0_up_key, - f0_method, - file_index, - index_rate, - resample_sr, - rms_mix_rate, - protect, - ) - if opt and opt[0] is not None and opt[1] is not None: - try: - tgt_sr, audio_opt = opt - if format1 in ["wav", "flac"]: - sf.write( - "%s/%s.%s" - % ( - opt_root, - os.path.splitext(os.path.basename(path))[0], - format1, - ), - audio_opt, - tgt_sr, - ) - else: - path = "%s/%s.%s" % ( - opt_root, - os.path.splitext(os.path.basename(path))[0], - format1, - ) - with BytesIO() as wavf: - sf.write(wavf, audio_opt, tgt_sr, format="wav") - wavf.seek(0, 0) - with open(path, "wb") as outf: - wav2(wavf, outf, format1) - success += 1 - except Exception: - info = "%s\n%s" % (info, traceback.format_exc()) - failed += 1 - item_failed = True - failures.append("%s:%s" % (os.path.basename(path), info)) - else: - failed += 1 - item_failed = True - failures.append("%s:%s" % (os.path.basename(path), info)) - if should_report(idx, total) or item_failed: - yield batch_status( - i18n("批量推理"), - idx + 1, - total, - success, - failed, - os.path.basename(path), - failures, - ) - except Exception: - yield inference_status("批量推理", "失败", traceback.format_exc()) diff --git a/infer/vc/pipeline.py b/infer/vc/pipeline.py deleted file mode 100644 index 2aa3235d5464018b5017f60898264c4dd1b8bab8..0000000000000000000000000000000000000000 --- a/infer/vc/pipeline.py +++ /dev/null @@ -1,410 +0,0 @@ -import os -import traceback -import logging - -logger = logging.getLogger(__name__) - -from time import time as ttime - -import faiss -import librosa -import numpy as np -import parselmouth -import torch -import torch.nn.functional as F -from scipy import signal - -from infer.hubert import extract_hubert_features -from tools.cuda_graph import cuda_graph_enabled, run_cuda_graph - -bh, ah = signal.butter(N=5, Wn=48, btype="high", fs=16000) - - -def change_rms(data1, sr1, data2, sr2, rate): # 1是输入音频,2是输出音频,rate是2的占比 - # print(data1.max(),data2.max()) - rms1 = librosa.feature.rms( - y=data1, frame_length=sr1 // 2 * 2, hop_length=sr1 // 2 - ) # 每半秒一个点 - rms2 = librosa.feature.rms(y=data2, frame_length=sr2 // 2 * 2, hop_length=sr2 // 2) - rms1 = torch.from_numpy(rms1) - rms1 = F.interpolate( - rms1.unsqueeze(0), size=data2.shape[0], mode="linear" - ).squeeze() - rms2 = torch.from_numpy(rms2) - rms2 = F.interpolate( - rms2.unsqueeze(0), size=data2.shape[0], mode="linear" - ).squeeze() - rms2 = torch.max(rms2, torch.zeros_like(rms2) + 1e-6) - data2 *= ( - torch.pow(rms1, torch.tensor(1 - rate)) - * torch.pow(rms2, torch.tensor(rate - 1)) - ).numpy() - return data2 - - -class Pipeline(object): - def __init__(self, tgt_sr, config): - self.x_pad, self.x_query, self.x_center, self.x_max, self.is_half = ( - config.x_pad, - config.x_query, - config.x_center, - config.x_max, - config.is_half, - ) - self.sr = 16000 # hubert输入采样率 - self.window = 160 # 每帧点数 - self.t_pad = self.sr * self.x_pad # 每条前后pad时间 - self.t_pad_tgt = tgt_sr * self.x_pad - self.t_pad2 = self.t_pad * 2 - self.t_query = self.sr * self.x_query # 查询切点前后查询时间 - self.t_center = self.sr * self.x_center # 查询切点位置 - self.t_max = self.sr * self.x_max # 免查询时长阈值 - self.device = config.device - - def get_f0( - self, - x, - p_len, - f0_up_key, - f0_method, - ): - if f0_method not in ("pm", "rmvpe", "fcpe"): - raise ValueError(f"Unsupported F0 method: {f0_method}") - time_step = self.window / self.sr * 1000 - f0_min = 50 - f0_max = 1100 - f0_mel_min = 1127 * np.log(1 + f0_min / 700) - f0_mel_max = 1127 * np.log(1 + f0_max / 700) - if f0_method == "pm": - f0 = ( - parselmouth.Sound(x, self.sr) - .to_pitch_ac( - time_step=time_step / 1000, - voicing_threshold=0.6, - pitch_floor=f0_min, - pitch_ceiling=f0_max, - ) - .selected_array["frequency"] - ) - pad_size = (p_len - len(f0) + 1) // 2 - if pad_size > 0 or p_len - len(f0) - pad_size > 0: - f0 = np.pad( - f0, [[pad_size, p_len - len(f0) - pad_size]], mode="constant" - ) - elif f0_method == "rmvpe": - if not hasattr(self, "model_rmvpe"): - from infer.rmvpe import RMVPE - - logger.info( - "Loading rmvpe model,%s" % "%s/rmvpe.pt" % os.environ["rmvpe_root"] - ) - self.model_rmvpe = RMVPE( - "%s/rmvpe.pt" % os.environ["rmvpe_root"], - is_half=self.is_half, - device=self.device, - ) - f0 = self.model_rmvpe.infer_from_audio(x, thred=0.03) - - if "privateuseone" in str(self.device): # clean ortruntime memory - del self.model_rmvpe.model - del self.model_rmvpe - logger.info("Cleaning ortruntime memory") - elif f0_method == "fcpe": - if not hasattr(self, "model_fcpe"): - from infer.fcpe import FCPEInfer - - logger.info("Loading fcpe model") - self.model_fcpe = FCPEInfer(self.device) - f0 = self.model_fcpe.infer( - torch.from_numpy(x).unsqueeze(0).float(), - sr=self.sr, - decoder_mode="local_argmax", - threshold=0.006, - ).squeeze().detach().cpu().numpy() - - try: - uv = f0 == 0 - f0[uv] = np.interp(np.where(uv)[0], np.where(~uv)[0], f0[~uv]) - except Exception: - traceback.print_exc() - f0 *= pow(2, f0_up_key / 12) - f0bak = f0.copy() - f0_mel = 1127 * np.log(1 + f0 / 700) - f0_mel[f0_mel > 0] = (f0_mel[f0_mel > 0] - f0_mel_min) * 254 / ( - f0_mel_max - f0_mel_min - ) + 1 - f0_mel[f0_mel <= 1] = 1 - f0_mel[f0_mel > 255] = 255 - f0_coarse = np.rint(f0_mel).astype(np.int32) - return f0_coarse, f0bak # 1-0 - - def vc( - self, - model, - net_g, - sid, - audio0, - pitch, - pitchf, - times, - index, - index_vectors, - index_rate, - version, - protect, - ): - feats = torch.from_numpy(audio0) - if self.is_half: - feats = feats.half() - else: - feats = feats.float() - if feats.dim() == 2: # double channels - feats = feats.mean(-1) - assert feats.dim() == 1, feats.dim() - feats = feats.view(1, -1) - padding_mask = torch.BoolTensor(feats.shape).to(self.device).fill_(False) - - t0 = ttime() - with torch.no_grad(): - feats = extract_hubert_features( - model, - feats.to(self.device), - version, - padding_mask=padding_mask, - ) - if protect < 0.5 and pitch is not None and pitchf is not None: - feats0 = feats.clone() - if ( - not isinstance(index, type(None)) - and not isinstance(index_vectors, type(None)) - and index_rate != 0 - ): - npy = feats[0].cpu().numpy() - if self.is_half: - npy = npy.astype("float32") - - score, ix = index.search(npy, k=8) - weight = np.square(1 / score) - weight /= weight.sum(axis=1, keepdims=True) - npy = np.sum(index_vectors[ix] * np.expand_dims(weight, axis=2), axis=1) - - if self.is_half: - npy = npy.astype("float16") - feats = ( - torch.from_numpy(npy).unsqueeze(0).to(self.device) * index_rate - + (1 - index_rate) * feats - ) - - feats = F.interpolate(feats.permute(0, 2, 1), scale_factor=2).permute(0, 2, 1) - if protect < 0.5 and pitch is not None and pitchf is not None: - feats0 = F.interpolate(feats0.permute(0, 2, 1), scale_factor=2).permute( - 0, 2, 1 - ) - t1 = ttime() - p_len = audio0.shape[0] // self.window - if feats.shape[1] < p_len: - p_len = feats.shape[1] - if pitch is not None and pitchf is not None: - pitch = pitch[:, :p_len] - pitchf = pitchf[:, :p_len] - - if protect < 0.5 and pitch is not None and pitchf is not None: - pitchff = pitchf.clone() - pitchff[pitchf > 0] = 1 - pitchff[pitchf < 1] = protect - pitchff = pitchff.unsqueeze(-1) - feats = feats * pitchff + feats0 * (1 - pitchff) - feats = feats.to(feats0.dtype) - p_len = torch.tensor([p_len], device=self.device).long() - with torch.no_grad(): - hasp = pitch is not None and pitchf is not None - if hasp: - synthesized = run_cuda_graph( - net_g, - "rvc-synth-f0", - lambda phone, lengths, coarse, continuous, speaker: net_g.infer( - phone, lengths, coarse, continuous, speaker - )[0], - feats, - p_len, - pitch, - pitchf, - sid, - ) - else: - synthesized = run_cuda_graph( - net_g, - "rvc-synth-no-f0", - lambda phone, lengths, speaker: net_g.infer( - phone, lengths, speaker - )[0], - feats, - p_len, - sid, - ) - audio1 = synthesized[0, 0].data.cpu().float().numpy() - del hasp, synthesized - del feats, p_len, padding_mask - if torch.cuda.is_available() and not cuda_graph_enabled(self.device): - torch.cuda.empty_cache() - t2 = ttime() - times[0] += t1 - t0 - times[2] += t2 - t1 - return audio1 - - def pipeline( - self, - model, - net_g, - sid, - audio, - times, - f0_up_key, - f0_method, - file_index, - index_rate, - if_f0, - tgt_sr, - resample_sr, - rms_mix_rate, - version, - protect, - ): - if ( - file_index != "" - and os.path.exists(file_index) - and index_rate != 0 - ): - try: - index = faiss.read_index(file_index) - index_vectors = index.reconstruct_n(0, index.ntotal) - except: - traceback.print_exc() - index = index_vectors = None - else: - index = index_vectors = None - audio = signal.filtfilt(bh, ah, audio) - audio_pad = np.pad(audio, (self.window // 2, self.window // 2), mode="reflect") - opt_ts = [] - if audio_pad.shape[0] > self.t_max: - audio_sum = np.zeros_like(audio) - for i in range(self.window): - audio_sum += np.abs(audio_pad[i : i - self.window]) - for t in range(self.t_center, audio.shape[0], self.t_center): - opt_ts.append( - t - - self.t_query - + np.where( - audio_sum[t - self.t_query : t + self.t_query] - == audio_sum[t - self.t_query : t + self.t_query].min() - )[0][0] - ) - s = 0 - audio_opt = [] - t = None - t1 = ttime() - audio_pad = np.pad(audio, (self.t_pad, self.t_pad), mode="reflect") - p_len = audio_pad.shape[0] // self.window - sid = torch.tensor(sid, device=self.device).unsqueeze(0).long() - pitch, pitchf = None, None - if if_f0 == 1: - pitch, pitchf = self.get_f0( - audio_pad, - p_len, - f0_up_key, - f0_method, - ) - pitch = pitch[:p_len] - pitchf = pitchf[:p_len] - pitchf = pitchf.astype(np.float32) - pitch = torch.tensor(pitch, device=self.device).unsqueeze(0).long() - pitchf = torch.tensor(pitchf, device=self.device).unsqueeze(0).float() - t2 = ttime() - times[1] += t2 - t1 - for t in opt_ts: - t = t // self.window * self.window - if if_f0 == 1: - audio_opt.append( - self.vc( - model, - net_g, - sid, - audio_pad[s : t + self.t_pad2 + self.window], - pitch[:, s // self.window : (t + self.t_pad2) // self.window], - pitchf[:, s // self.window : (t + self.t_pad2) // self.window], - times, - index, - index_vectors, - index_rate, - version, - protect, - )[self.t_pad_tgt : -self.t_pad_tgt] - ) - else: - audio_opt.append( - self.vc( - model, - net_g, - sid, - audio_pad[s : t + self.t_pad2 + self.window], - None, - None, - times, - index, - index_vectors, - index_rate, - version, - protect, - )[self.t_pad_tgt : -self.t_pad_tgt] - ) - s = t - if if_f0 == 1: - audio_opt.append( - self.vc( - model, - net_g, - sid, - audio_pad[t:], - pitch[:, t // self.window :] if t is not None else pitch, - pitchf[:, t // self.window :] if t is not None else pitchf, - times, - index, - index_vectors, - index_rate, - version, - protect, - )[self.t_pad_tgt : -self.t_pad_tgt] - ) - else: - audio_opt.append( - self.vc( - model, - net_g, - sid, - audio_pad[t:], - None, - None, - times, - index, - index_vectors, - index_rate, - version, - protect, - )[self.t_pad_tgt : -self.t_pad_tgt] - ) - audio_opt = np.concatenate(audio_opt) - if rms_mix_rate != 1: - audio_opt = change_rms(audio, 16000, audio_opt, tgt_sr, rms_mix_rate) - if tgt_sr != resample_sr >= 16000: - audio_opt = librosa.resample( - audio_opt, orig_sr=tgt_sr, target_sr=resample_sr - ) - audio_max = np.abs(audio_opt).max() / 0.99 - max_int16 = 32768 - if audio_max > 1: - max_int16 /= audio_max - audio_opt = (audio_opt * max_int16).astype(np.int16) - del pitch, pitchf, sid - if torch.cuda.is_available() and not cuda_graph_enabled(self.device): - torch.cuda.empty_cache() - return audio_opt diff --git a/infer/vc/utils.py b/infer/vc/utils.py deleted file mode 100644 index 338ccfc7ce2ab97e4bf57ad2ceacaeb87522edff..0000000000000000000000000000000000000000 --- a/infer/vc/utils.py +++ /dev/null @@ -1,61 +0,0 @@ -import os -import re - -from infer.hubert import load_hubert_model - - -def get_index_path_from_model(sid, speaker_id=None): - model_stem = os.path.splitext(os.path.basename(str(sid or "")))[0] - experiment_name = re.sub(r"_e\d+_s\d+$", "", model_stem, flags=re.IGNORECASE) - if not experiment_name: - return "" - - try: - target_speaker_id = None if speaker_id is None else int(speaker_id) - except (TypeError, ValueError): - target_speaker_id = None - candidates = [] - roots = [os.getenv("outside_index_root"), os.getenv("index_root")] - for index_root in roots: - if not index_root or not os.path.isdir(index_root): - continue - for root, _, files in os.walk(index_root, topdown=False): - for name in files: - if not name.lower().endswith(".index") or "trained" in name.lower(): - continue - index_stem = os.path.splitext(name)[0] - lower_index = index_stem.lower() - lower_experiment = experiment_name.lower() - speaker_match = re.search(r"_spkid(\d+)$", index_stem, re.IGNORECASE) - indexed_speaker_id = ( - int(speaker_match.group(1)) if speaker_match else None - ) - if target_speaker_id is None and indexed_speaker_id is not None: - continue - if ( - target_speaker_id is not None - and indexed_speaker_id is not None - and indexed_speaker_id != target_speaker_id - ): - continue - standard_match = ( - lower_index.startswith(lower_experiment + "_added_") - or ("_" + lower_experiment + "_v1") in lower_index - or ("_" + lower_experiment + "_v2") in lower_index - ) - exact_model_match = model_stem.lower() in lower_index - if standard_match or exact_model_match: - path = os.path.abspath(os.path.join(root, name)) - score = ( - 0 if indexed_speaker_id == target_speaker_id else 1, - 0 if standard_match else 1, - 0 if os.path.abspath(index_root) == os.path.abspath(roots[0]) else 1, - -os.path.getmtime(path), - path.lower(), - ) - candidates.append((score, path)) - return min(candidates, default=(None, ""), key=lambda item: item[0])[1] - - -def load_hubert(config): - return load_hubert_model(config.device, config.is_half) diff --git a/inference_simple.py b/inference_simple.py new file mode 100644 index 0000000000000000000000000000000000000000..4ba58a0e8a4cc667d850b934e046293f8d812400 --- /dev/null +++ b/inference_simple.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +"""Simple inference module for compatibility.""" +# The conversion logic is in app.py directly +# This file exists for import compatibility + +def convert_voice(input_audio_path, output_audio_path, **kwargs): + """Placeholder - actual implementation in app.py""" + pass + +MODEL_PATH = None +vc = None + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("--input", required=True) + parser.add_argument("--output", required=True) + parser.add_argument("--pitch", type=float, default=-4) + parser.add_argument("--formant", type=float, default=-3) + parser.add_argument("--breathiness", type=float, default=0.15) + args = parser.parse_args() + print(f"Use app.py for conversion: {args.input} -> {args.output}") \ No newline at end of file diff --git a/tools/cuda_graph.py b/tools/cuda_graph.py deleted file mode 100644 index 992e7fb033d86ef601778cf90361eb577a79973a..0000000000000000000000000000000000000000 --- a/tools/cuda_graph.py +++ /dev/null @@ -1,227 +0,0 @@ -import logging -import os -import threading -import time -from collections import OrderedDict - -import torch - - -logger = logging.getLogger(__name__) - -ENV_NAME = "RVC_CUDA_GRAPH" -MAX_CACHE_ENV = "RVC_CUDA_GRAPH_MAX_CACHE" -_probe_lock = threading.Lock() -_probe_result = None - - -def _device_type(device): - if isinstance(device, torch.device): - return device.type - return str(device).split(":", 1)[0].lower() - - -def _cuda_device(device): - parsed = device if isinstance(device, torch.device) else torch.device(device) - if parsed.index is None: - parsed = torch.device("cuda", torch.cuda.current_device()) - return parsed - - -def _clone_output(value): - if torch.is_tensor(value): - return value.clone() - if isinstance(value, tuple): - return tuple(_clone_output(item) for item in value) - if isinstance(value, list): - return [_clone_output(item) for item in value] - if isinstance(value, dict): - return {key: _clone_output(item) for key, item in value.items()} - return value - - -def detect_cuda_graph_support(device): - if _device_type(device) != "cuda" or not torch.cuda.is_available(): - return False - if not hasattr(torch.cuda, "CUDAGraph") or not hasattr(torch.cuda, "graph"): - return False - cuda_device = _cuda_device(device) - try: - with torch.cuda.device(cuda_device): - current = torch.cuda.current_stream(cuda_device) - warmup = torch.cuda.Stream(device=cuda_device) - warmup.wait_stream(current) - with torch.cuda.stream(warmup): - probe = torch.arange(32, device=cuda_device, dtype=torch.float32) - for _ in range(3): - expected = probe.square().add_(1) - current.wait_stream(warmup) - torch.cuda.synchronize(cuda_device) - graph = torch.cuda.CUDAGraph() - with torch.cuda.graph(graph): - captured = probe.square() + 1 - probe.copy_(torch.arange(32, device=cuda_device, dtype=torch.float32)) - graph.replay() - torch.cuda.synchronize(cuda_device) - valid = torch.equal( - captured.cpu(), torch.arange(32, dtype=torch.float32).square() + 1 - ) - del captured, expected, graph, probe - return bool(valid) - except Exception: - logger.exception("CUDA Graph support probe failed on %s", cuda_device) - return False - - -def configure_cuda_graph(device): - global _probe_result - explicit = os.environ.get(ENV_NAME) - if explicit in {"0", "1"}: - if explicit == "0": - return False - if _device_type(device) != "cuda": - os.environ[ENV_NAME] = "0" - return False - with _probe_lock: - if _probe_result is None: - _probe_result = detect_cuda_graph_support(device) - os.environ[ENV_NAME] = "1" if _probe_result else "0" - return bool(_probe_result) - - -def cuda_graph_enabled(device): - return ( - os.environ.get(ENV_NAME) == "1" - and _device_type(device) == "cuda" - and torch.cuda.is_available() - ) - - -def _tensor_signature(tensor): - return ( - tuple(tensor.shape), - tuple(tensor.stride()), - str(tensor.dtype), - str(tensor.device), - bool(tensor.requires_grad), - ) - - -class _CapturedCall: - def __init__(self, function, inputs): - started = time.perf_counter() - self.lock = threading.RLock() - self.inputs = tuple(torch.empty_like(value) for value in inputs) - for static, value in zip(self.inputs, inputs): - static.copy_(value) - device = self.inputs[0].device - current = torch.cuda.current_stream(device) - warmup = torch.cuda.Stream(device=device) - warmup.wait_stream(current) - with torch.cuda.stream(warmup), torch.no_grad(): - for _ in range(3): - output = function(*self.inputs) - current.wait_stream(warmup) - torch.cuda.synchronize(device) - self.graph = torch.cuda.CUDAGraph() - with torch.cuda.graph(self.graph), torch.no_grad(): - self.output = function(*self.inputs) - self.capture_ms = (time.perf_counter() - started) * 1000.0 - self.done_event = None - del output - - def replay(self, inputs): - with self.lock: - stream = torch.cuda.current_stream(self.inputs[0].device) - if self.done_event is not None: - stream.wait_event(self.done_event) - for static, value in zip(self.inputs, inputs): - static.copy_(value, non_blocking=True) - self.graph.replay() - output = _clone_output(self.output) - self.done_event = torch.cuda.Event(blocking=False) - self.done_event.record(stream) - return output - - -class _GraphCache: - def __init__(self): - self.entries = OrderedDict() - self.failures = set() - self.lock = threading.RLock() - self.capture_count = 0 - self.replay_count = 0 - self.fallback_count = 0 - self.eviction_count = 0 - self.capture_ms = 0.0 - - def run(self, key, function, inputs): - signature = key + tuple(_tensor_signature(value) for value in inputs) - with self.lock: - if signature in self.failures: - self.fallback_count += 1 - return function(*inputs) - entry = self.entries.get(signature) - if entry is None: - try: - entry = _CapturedCall(function, inputs) - self.entries[signature] = entry - self.capture_count += 1 - self.capture_ms += entry.capture_ms - max_entries = max(1, int(os.environ.get(MAX_CACHE_ENV, "8"))) - while len(self.entries) > max_entries: - self.entries.popitem(last=False) - self.eviction_count += 1 - except Exception: - self.failures.add(signature) - self.fallback_count += 1 - logger.exception("CUDA Graph capture failed for %s; using eager", key) - return function(*inputs) - else: - self.entries.move_to_end(signature) - output = entry.replay(inputs) - with self.lock: - self.replay_count += 1 - return output - - -def run_cuda_graph(owner, namespace, function, *inputs): - if not inputs or not cuda_graph_enabled(inputs[0].device): - return function(*inputs) - cache = getattr(owner, "_rvc_cuda_graph_cache", None) - if cache is None: - cache = _GraphCache() - setattr(owner, "_rvc_cuda_graph_cache", cache) - return cache.run((str(namespace),), function, tuple(inputs)) - - -def clear_cuda_graph_cache(owner): - cache = getattr(owner, "_rvc_cuda_graph_cache", None) - if cache is not None: - cache.entries.clear() - cache.failures.clear() - delattr(owner, "_rvc_cuda_graph_cache") - - -def get_cuda_graph_stats(owner): - cache = getattr(owner, "_rvc_cuda_graph_cache", None) - if cache is None: - return { - "entries": 0, - "failures": 0, - "captures": 0, - "replays": 0, - "fallbacks": 0, - "evictions": 0, - "capture_ms": 0.0, - } - with cache.lock: - return { - "entries": len(cache.entries), - "failures": len(cache.failures), - "captures": cache.capture_count, - "replays": cache.replay_count, - "fallbacks": cache.fallback_count, - "evictions": cache.eviction_count, - "capture_ms": cache.capture_ms, - } diff --git a/tools/file_io.py b/tools/file_io.py deleted file mode 100644 index 62dc2f2d84d68cefb2508542e33adad71e132add..0000000000000000000000000000000000000000 --- a/tools/file_io.py +++ /dev/null @@ -1,15 +0,0 @@ -def read_text(path, errors="strict", newline=None): - last_error = None - for encoding in (None, "utf8", "gbk"): - try: - kwargs = {"errors": "strict", "newline": newline} - if encoding is not None: - kwargs["encoding"] = encoding - with open(path, "r", **kwargs) as file: - return file.read() - except UnicodeDecodeError as error: - last_error = error - if errors != "strict": - with open(path, "r", encoding="gbk", errors=errors, newline=newline) as file: - return file.read() - raise last_error diff --git a/tools/multispeaker.py b/tools/multispeaker.py deleted file mode 100644 index f1b28c304fe96643973f1412fa32964a40a6d6a5..0000000000000000000000000000000000000000 --- a/tools/multispeaker.py +++ /dev/null @@ -1,253 +0,0 @@ -import hashlib -import json -import os -import re - - -AUDIO_EXTENSIONS = { - ".wav", - ".flac", - ".mp3", - ".m4a", - ".ogg", - ".opus", - ".aac", - ".wma", - ".mp4", - ".mkv", - ".webm", -} -SPEAKER_ID_MIN = 0 -SPEAKER_ID_MAX = 109 -MANIFEST_VERSION = 1 -SPEAKER_DIR_RE = re.compile(r"^(.+)_(\d+)_(\d+)$") - - -class ManifestError(Exception): - def __init__(self, key, *values): - self.key = key - self.values = values - super().__init__(key, *values) - - -def audio_files(folder): - result = [] - if not os.path.isdir(folder): - return result - for root, dirs, files in os.walk(folder): - dirs.sort() - for name in sorted(files): - if os.path.splitext(name)[1].lower() in AUDIO_EXTENSIONS: - result.append(os.path.abspath(os.path.join(root, name))) - return result - - -def _manifest_entry(path, speaker_name, speaker_id, repeat, index): - digest = hashlib.sha1( - os.path.normcase(os.path.abspath(path)).encode("utf8") - ).hexdigest()[:10] - return { - "path": os.path.abspath(path), - "speaker_name": speaker_name, - "speaker_id": int(speaker_id), - "repeat": int(repeat), - "output_key": "ms%04d_s%03d_%s" % (index, int(speaker_id), digest), - } - - -def build_manifest_from_root(root): - root = os.path.abspath(str(root or "").strip()) - if not os.path.isdir(root): - raise ManifestError("多说话人训练集总文件夹不存在:%s", root) - entries = [] - invalid = [] - names_by_id = {} - child_dirs = [ - os.path.join(root, name) - for name in sorted(os.listdir(root)) - if os.path.isdir(os.path.join(root, name)) - ] - if not child_dirs: - raise ManifestError("多说话人训练集总文件夹中没有直接子文件夹") - for child in child_dirs: - name = os.path.basename(child) - match = SPEAKER_DIR_RE.match(name) - if not match: - invalid.append(name) - continue - speaker_name = match.group(1).strip() - speaker_id = int(match.group(2)) - repeat = int(match.group(3)) - files = audio_files(child) - invalid_name = ( - not speaker_name - or "|" in speaker_name - or "\n" in speaker_name - or "\r" in speaker_name - ) - inconsistent = ( - speaker_id in names_by_id and names_by_id[speaker_id] != speaker_name - ) - if ( - invalid_name - or speaker_id < SPEAKER_ID_MIN - or speaker_id > SPEAKER_ID_MAX - or repeat < 1 - or not files - or inconsistent - ): - invalid.append(name) - continue - names_by_id[speaker_id] = speaker_name - for path in files: - entries.append( - _manifest_entry( - path, speaker_name, speaker_id, repeat, len(entries) - ) - ) - if invalid: - raise ManifestError( - "多说话人子文件夹无效(格式应为名称_ID_重复次数、ID为0~109、重复次数为正整数、同一ID的名称需一致且目录需有音频):%s", - ", ".join(invalid), - ) - if not entries: - raise ManifestError("多说话人训练集总文件夹中没有有效音频") - return { - "version": MANIFEST_VERSION, - "source": "folder_scan", - "root": root, - "speakers": [ - {"id": speaker_id, "name": names_by_id[speaker_id]} - for speaker_id in sorted(names_by_id) - ], - "entries": entries, - } - - -def build_manifest_from_rows(rows, root=""): - entries = [] - valid_rows = [] - invalid_rows = [] - names_by_id = {} - for row_index, row in enumerate(rows, 1): - path, speaker_name, speaker_id, repeat = [ - "" if value is None else str(value).strip() for value in row - ] - if not path and not speaker_name and not speaker_id and not repeat: - continue - try: - speaker_id_int = int(float(speaker_id)) - repeat_int = int(float(repeat)) - if str(speaker_id_int) != speaker_id and str(float(speaker_id_int)) != speaker_id: - raise ValueError - if str(repeat_int) != repeat and str(float(repeat_int)) != repeat: - raise ValueError - if speaker_id_int < SPEAKER_ID_MIN or speaker_id_int > SPEAKER_ID_MAX or repeat_int < 1: - raise ValueError - except (TypeError, ValueError): - invalid_rows.append(row_index) - continue - invalid_name = ( - not speaker_name - or "|" in speaker_name - or "\n" in speaker_name - or "\r" in speaker_name - ) - inconsistent = ( - speaker_id_int in names_by_id - and names_by_id[speaker_id_int] != speaker_name - ) - path = os.path.abspath(path) - files = audio_files(path) - if invalid_name or inconsistent or not files: - invalid_rows.append(row_index) - continue - names_by_id[speaker_id_int] = speaker_name - valid_rows.append( - { - "path": path, - "speaker_name": speaker_name, - "speaker_id": speaker_id_int, - "repeat": repeat_int, - } - ) - for file_path in files: - entries.append( - _manifest_entry( - file_path, - speaker_name, - speaker_id_int, - repeat_int, - len(entries), - ) - ) - if not entries: - raise ManifestError("没有有效的多说话人训练集行") - manifest = { - "version": MANIFEST_VERSION, - "source": "helper", - "root": os.path.abspath(root) if root else "", - "rows": valid_rows, - "speakers": [ - {"id": speaker_id, "name": names_by_id[speaker_id]} - for speaker_id in sorted(names_by_id) - ], - "entries": entries, - } - return manifest, invalid_rows - - -def write_manifest(exp_dir, manifest): - os.makedirs(exp_dir, exist_ok=True) - path = os.path.join(exp_dir, "multispeaker_manifest.json") - with open(path, "w", encoding="utf8") as file: - json.dump(manifest, file, ensure_ascii=False, indent=2) - file.write("\n") - return path - - -def load_manifest(exp_dir): - path = os.path.join(exp_dir, "multispeaker_manifest.json") - if not os.path.isfile(path): - raise ManifestError("多说话人训练集清单不存在,请先提交辅助清单或填写总文件夹") - with open(path, "r", encoding="utf8") as file: - manifest = json.load(file) - entries = manifest.get("entries") if isinstance(manifest, dict) else None - if not isinstance(entries, list) or not entries: - raise ManifestError("多说话人训练集清单没有有效音频") - seen = set() - names_by_id = {} - for entry in entries: - try: - path_value = os.path.abspath(str(entry["path"])) - speaker_name = str(entry["speaker_name"]).strip() - speaker_id = int(entry["speaker_id"]) - repeat = int(entry["repeat"]) - output_key = str(entry["output_key"]) - except (KeyError, TypeError, ValueError): - raise ManifestError("多说话人训练集清单格式错误") - inconsistent = ( - speaker_id in names_by_id and names_by_id[speaker_id] != speaker_name - ) - if ( - not os.path.isfile(path_value) - or not speaker_name - or "|" in speaker_name - or "\n" in speaker_name - or "\r" in speaker_name - or speaker_id < 0 - or speaker_id > 109 - or repeat < 1 - or not output_key - or inconsistent - ): - raise ManifestError("多说话人训练集清单包含无效条目:%s", path_value) - if output_key in seen: - raise ManifestError("多说话人训练集清单存在重复输出标识:%s", output_key) - seen.add(output_key) - names_by_id[speaker_id] = speaker_name - manifest["speakers"] = [ - {"id": speaker_id, "name": names_by_id[speaker_id]} - for speaker_id in sorted(names_by_id) - ] - return manifest diff --git a/tools/process_utils.py b/tools/process_utils.py deleted file mode 100644 index a59a5079db512db31deb03b0d60e99d0f3fc8d0a..0000000000000000000000000000000000000000 --- a/tools/process_utils.py +++ /dev/null @@ -1,71 +0,0 @@ -import logging -import os -import signal -import subprocess -import time - - -logger = logging.getLogger(__name__) - - -def kill_process_tree(process, process_name="", task_logger=None): - """Terminate a Popen process and every child process it created.""" - if process is None: - return False - try: - if process.poll() is not None: - return False - except (OSError, ProcessLookupError): - return False - - pid = process.pid - if os.name == "nt": - try: - subprocess.run( - ["taskkill", "/t", "/f", "/pid", str(pid)], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=False, - ) - except OSError: - try: - process.terminate() - except (OSError, ProcessLookupError): - pass - else: - try: - process_group = os.getpgid(pid) - except (OSError, ProcessLookupError): - process_group = None - try: - if process_group is not None and process_group != os.getpgrp(): - os.killpg(process_group, signal.SIGTERM) - else: - os.kill(pid, signal.SIGTERM) - except (OSError, ProcessLookupError): - pass - - for _ in range(10): - if process.poll() is not None: - break - time.sleep(0.1) - if process.poll() is None: - try: - if process_group is not None and process_group != os.getpgrp(): - os.killpg(process_group, signal.SIGKILL) - else: - os.kill(pid, signal.SIGKILL) - except (OSError, ProcessLookupError): - pass - - try: - process.wait(timeout=5) - except (OSError, ProcessLookupError, subprocess.TimeoutExpired): - try: - process.kill() - except (OSError, ProcessLookupError): - pass - - log = task_logger or logger - log.info("%s process tree terminated (pid=%s)", process_name or "Child", pid) - return True diff --git a/tools/progress.py b/tools/progress.py deleted file mode 100644 index 253e3a6a908ec2d8649deabc216a5f51926e8fe3..0000000000000000000000000000000000000000 --- a/tools/progress.py +++ /dev/null @@ -1,46 +0,0 @@ -import math - -from i18n.i18n import I18nAuto - - -i18n = I18nAuto() - - -def should_report(index, total, max_updates=12): - if total <= 0: - return False - if total <= max_updates: - return True - interval = max(1, math.ceil(total / max_updates)) - return index == 0 or index + 1 == total or (index + 1) % interval == 0 - - -def batch_status(title, current, total, success, failed, latest="", failures=None): - if total <= 0: - state = i18n("等待输入") - elif current >= total: - state = i18n("已完成") - else: - state = i18n("处理中") - lines = [ - "【%s】" % title, - "%s:%s" % (i18n("状态"), state), - "%s:%s/%s | %s:%s | %s:%s" - % ( - i18n("进度"), - current, - total, - i18n("成功"), - success, - i18n("失败"), - failed, - ), - ] - if latest: - lines.append("%s:%s" % (i18n("当前"), latest)) - if failures: - lines.append("%s:" % i18n("失败记录")) - lines.extend(failures[-10:]) - if len(failures) > 10: - lines.append(i18n("……仅显示最近10条失败记录")) - return "\n".join(lines) diff --git a/tools/pymss/LICENSE b/tools/pymss/LICENSE deleted file mode 100644 index f62265c9157a627e2eb4b9cac902e305bd763515..0000000000000000000000000000000000000000 --- a/tools/pymss/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 KitsuneX07 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/tools/pymss/__init__.py b/tools/pymss/__init__.py deleted file mode 100644 index 681bc01587f15571e92af531c9301b21c74f566a..0000000000000000000000000000000000000000 --- a/tools/pymss/__init__.py +++ /dev/null @@ -1,68 +0,0 @@ -"""Public Python API for pymss. - -pymss provides model catalog helpers, model downloading, audio I/O, ensemble -utilities, logging helpers, and the ``MSSeparator`` runtime for music source -separation. Most users can import from this top-level package instead of -importing submodules directly. - -Exports: - MSSeparator: Main runtime class for loading separation models and producing - stems. Prefer ``MSSeparator.from_model_name(...)`` for catalog models. - get_separation_logger: Create or reuse the package logger. - create_separator: Create ``MSSeparator`` from a catalog model name. - get_model_entry: Resolve catalog metadata for one model name or alias. - list_models: List model catalog entries. - resolve_model: Resolve catalog model paths without constructing a - separator. - download_model: Download all files required by one catalog model. - ensemble_audios: Load and combine multiple audio files. - save_ensemble_audio: Ensemble multiple audio files and save the result. - WorkflowRunner: Run a multi-model audio workflow. - load_audio: Load an audio file into a NumPy array. - save_audio: Save a NumPy audio array to wav/flac/mp3/m4a. - -Example: - >>> from pymss import MSSeparator - >>> separator = MSSeparator.from_model_name( - ... "bs_roformer_voc_hyperacev2", - ... download=True, - ... model_dir="models", - ... ) - >>> separator.process_folder("song.wav") - -Example: - >>> from pymss import download_model, list_models - >>> models = list_models(supported=True) - >>> download_model(models[0].name, model_dir="models") - -Example: - >>> from pymss import ensemble_audios, save_ensemble_audio - >>> audio, sample_rate = ensemble_audios(["a.wav", "b.wav"], weights=[1, 1]) - >>> save_ensemble_audio(["a.wav", "b.wav"], "ensemble.wav") -""" - -from .separator import MSSeparator -from .logger import get_separation_logger -from .model_registry import create_separator, get_model_entry, list_models, resolve_model -from .model_download import download_model -from .ensemble import ensemble_audios, save_ensemble_audio -from .audio_io import load_audio, save_audio -from .workflow import WorkflowRunner, load_workflow_file, run_workflow_file, validate_workflow - -__all__ = ( - "MSSeparator", - "get_separation_logger", - "create_separator", - "get_model_entry", - "list_models", - "resolve_model", - "download_model", - "ensemble_audios", - "save_ensemble_audio", - "WorkflowRunner", - "load_workflow_file", - "run_workflow_file", - "validate_workflow", - "load_audio", - "save_audio", -) diff --git a/tools/pymss/audio_io.py b/tools/pymss/audio_io.py deleted file mode 100644 index 630e6c74e68850cd9956fd085cc47955a515b1cf..0000000000000000000000000000000000000000 --- a/tools/pymss/audio_io.py +++ /dev/null @@ -1,280 +0,0 @@ -import json -import subprocess - -import av -import numpy as np - - -def _frame_to_audio(frame, mono): - """Implement the frame to audio helper. - - Args: - frame (Any): Frame value. - mono (bool): Mono value. - - Returns: - Any: Computed result.""" - audio = frame.to_ndarray() - audio = audio[None, :] if audio.ndim == 1 else audio - return (audio.mean(axis=0, keepdims=True) if mono and audio.shape[0] > 1 else audio).astype(np.float32, copy=False) - - -def _ffmpeg_audio_stream_info(path): - """Return basic audio stream information from ffprobe.""" - command = [ - "ffprobe", - "-v", - "error", - "-select_streams", - "a:0", - "-show_entries", - "stream=sample_rate,channels", - "-of", - "json", - str(path), - ] - result = subprocess.run(command, check=True, capture_output=True, text=True) - streams = json.loads(result.stdout or "{}").get("streams") or [] - if not streams: - raise ValueError(f"No audio stream found in {path!s}.") - stream = streams[0] - return int(stream["sample_rate"]), int(stream["channels"]) - - -def _load_audio_ffmpeg(path, sr=None, mono=False, offset=0.0, duration=None): - """Load audio through the ffmpeg CLI as a fallback for damaged streams.""" - source_rate, source_channels = _ffmpeg_audio_stream_info(path) - out_rate = int(sr or source_rate) - channels = 1 if mono else source_channels - command = ["ffmpeg", "-nostdin", "-v", "error"] - if offset: - command += ["-ss", str(float(offset))] - command += ["-i", str(path), "-map", "0:a:0", "-vn"] - if duration is not None: - command += ["-t", str(float(duration))] - command += ["-f", "f32le", "-acodec", "pcm_f32le", "-ar", str(out_rate), "-ac", str(channels), "-"] - result = subprocess.run(command, check=True, capture_output=True) - audio = np.frombuffer(result.stdout, dtype=" 1 and (mono or audio.shape[0] == 1) else audio), int(out_rate) - - -def _load_audio_av(path, sr=None, mono=False, offset=0.0, duration=None): - """Load audio through PyAV.""" - chunks = [] - out_rate = None - with av.open(path) as container: - stream = container.streams.audio[0] - out_rate = int(sr or stream.rate) - resampler = None - stop_samples = None if duration is None else int(round((offset + duration) * out_rate)) - decoded = 0 - - for frame in container.decode(stream): - if resampler is None: - resampler = av.AudioResampler(format="fltp", layout=frame.layout.name, rate=out_rate) - - for out in resampler.resample(frame): - chunks.append(audio := _frame_to_audio(out, mono)) - decoded += audio.shape[-1] - if stop_samples is not None and decoded >= stop_samples: - break - - if resampler is not None: - for out in resampler.resample(None): - chunks.append(_frame_to_audio(out, mono)) - - start = int(round(offset * out_rate)) - stop = None if duration is None else start + int(round(duration * out_rate)) - channels = 1 if mono else 0 - audio = np.ascontiguousarray( - (np.concatenate(chunks, axis=-1) if chunks else np.empty((channels, 0), dtype=np.float32))[..., start:stop] - ) - return (audio[0] if mono or audio.shape[0] == 1 else audio), out_rate - - -def load_audio(path, sr=None, mono=False, offset=0.0, duration=None): - """Load an audio file as float32 NumPy samples. - - Audio decoding is attempted in this order: PyAV, librosa, then the - ffmpeg CLI fallback. Stereo or multi-channel output is returned - channel-first as ``(channels, samples)``. Mono output is returned as a - one-dimensional array. - - Args: - path (str | os.PathLike): Input audio file path. Any format supported - by the local FFmpeg/PyAV build can be decoded. - sr (int | None, optional): Target sample rate. ``None`` keeps the - source stream sample rate. Defaults to None. - mono (bool, optional): Whether to downmix multi-channel audio to mono. - Defaults to False. - offset (float, optional): Start offset in seconds. Defaults to 0.0. - duration (float | None, optional): Maximum duration to return in - seconds after ``offset``. ``None`` reads to the end. Defaults to - None. - - Returns: - tuple[np.ndarray, int]: Audio samples and sample rate. The array is - channel-first for multi-channel audio and one-dimensional for mono - output. - - Example: - >>> from pymss import load_audio - >>> audio, sample_rate = load_audio("song.wav", sr=44100) - >>> sample_rate - 44100 - - Example: - >>> clip, sample_rate = load_audio( - ... "song.wav", - ... mono=True, - ... offset=30.0, - ... duration=10.0, - ... ) - >>> clip.ndim - 1""" - loaders = [ - ("PyAV", _load_audio_av), - ("librosa", _load_audio_librosa), - ("ffmpeg CLI", _load_audio_ffmpeg), - ] - - errors = [] - for name, loader in loaders: - try: - return loader(path, sr=sr, mono=mono, offset=offset, duration=duration) - except Exception as e: - errors.append(f"{name}: {e}") - continue - - raise RuntimeError(f"All audio loading methods failed: {'; '.join(errors)}") - - -def _bitrate_to_int(value): - """Implement the bitrate to int helper. - - Args: - value (Any): Value value. - - Returns: - Any: Computed result.""" - if value is None: - return None - if isinstance(value, int): - return value - value = str(value).strip().lower() - return int(float(value[:-1]) * 1000) if value.endswith("k") else int(value) - - -def _format_audio(audio): - """Format audio. - - Args: - audio (np.ndarray): Audio samples. - - Returns: - Any: Computed result.""" - audio = np.asarray(audio) - audio = np.ascontiguousarray(audio[:, None] if audio.ndim == 1 else audio) - # We can use "fltp" container for all output formats, while the final result is determined by the codec. - # Using the fltp sample format can also help avoid some clipping distortion that occurs with integer formats. - return np.ascontiguousarray(audio.astype(np.float32).T) - - -def save_audio(path, audio, sr, output_format, audio_params): - """Save a NumPy audio array to wav, flac, mp3, or m4a. - - Audio is expected as sample-major data, either ``(samples,)`` for mono or - ``(samples, channels)`` for multi-channel audio. The output codec is chosen - from ``output_format`` and ``audio_params``. - - Args: - path (str | os.PathLike): Output file path. - audio (np.ndarray): Audio samples. Mono arrays may be one-dimensional; - stereo arrays should be shaped as ``(samples, 2)``. - sr (int): Sample rate in Hz. - output_format (str): Output format. Supported values are ``wav``, - ``flac``, ``mp3``, and ``m4a``. - audio_params (dict): Encoding options. Supported keys include - ``wav_bit_depth`` (``FLOAT``, ``PCM_16``, ``PCM_24``), - ``flac_bit_depth`` (currently ``PCM_24`` uses soundfile), - ``mp3_bit_rate`` (for example ``"320k"``), ``m4a_bit_rate``, - ``m4a_codec``, and ``m4a_aac_at_quality``. - - Returns: - None: The file is written to ``path``. - - Example: - >>> from pymss import save_audio - >>> save_audio( - ... "vocals.wav", - ... vocals, - ... 44100, - ... "wav", - ... {"wav_bit_depth": "FLOAT"}, - ... ) - - Example: - >>> save_audio( - ... "instrumental.flac", - ... instrumental, - ... 44100, - ... "flac", - ... {"flac_bit_depth": "PCM_24"}, - ... )""" - output_format = output_format.lower() - audio_array = np.asarray(audio) - layout = "stereo" if audio_array.ndim > 1 and audio_array.shape[1] == 2 else "mono" - - if output_format == "mp3": - codec = "libmp3lame" - elif output_format == "m4a": - codec = audio_params.get("m4a_codec", "aac") - elif output_format == "flac": - # PyAV's FLAC encoder only exposes a single "flac" codec in the current version. - # In the current version, without access to bits_per_raw_sample in PyAV, PCM_24 may still be encoded as 16-bit. - # Use soundfile to save 24-bit FLAC - codec = "flac" - if audio_params.get("flac_bit_depth", "PCM_24") == "PCM_24": - import soundfile as sf - - return sf.write(path, audio_array, int(sr), format="FLAC", subtype="PCM_24") - else: - wav_codecs = {"PCM_16": "pcm_s16le", "PCM_24": "pcm_s24le", "FLOAT": "pcm_f32le"} - codec = wav_codecs.get(audio_params.get("wav_bit_depth", "FLOAT"), wav_codecs["FLOAT"]) - - with av.open(path, "w") as container: - stream = container.add_stream(codec, rate=int(sr)) - stream.layout = layout - if output_format == "mp3": - stream.bit_rate = _bitrate_to_int(audio_params.get("mp3_bit_rate", "320k")) - elif output_format == "m4a": - stream.bit_rate = _bitrate_to_int(audio_params.get("m4a_bit_rate", "512k")) - if codec == "aac_at": - stream.codec_context.options = {"aac_at_quality": str(audio_params.get("m4a_aac_at_quality", 2))} - - frame = av.AudioFrame.from_ndarray(_format_audio(audio_array), format="fltp", layout=layout) - frame.sample_rate = int(sr) - for packet in stream.encode(frame): - container.mux(packet) - for packet in stream.encode(): - container.mux(packet) diff --git a/tools/pymss/cli.py b/tools/pymss/cli.py deleted file mode 100644 index ab2eafdbb5ef0bf0d465ca59295c89dc22426a8b..0000000000000000000000000000000000000000 --- a/tools/pymss/cli.py +++ /dev/null @@ -1,587 +0,0 @@ -import argparse -import json -import sys -import warnings - -from .ensemble import ENSEMBLE_ALGORITHMS, save_ensemble_audio -from .logger import get_separation_logger -from .model_download import download_all, download_model -from .model_registry import create_separator, list_models, resolve_model -from .progress import _CliInferenceProgress -from .workflow import load_workflow_file, run_workflow_file, validate_workflow, write_workflow_template - -warnings.filterwarnings("ignore", category=UserWarning) - - -def _parse_key_value(values): - """Parse key value. - - Args: - values (Any): Values value. - - Returns: - Any: Parsed value.""" - result = {} - for value in values or []: - if "=" not in value: - raise argparse.ArgumentTypeError(f"Expected key=value, got {value!r}") - key, raw = value.split("=", 1) - lowered = raw.lower() - if lowered in {"true", "false"}: - result[key] = lowered == "true" - else: - try: - result[key] = int(raw) - except ValueError: - try: - result[key] = float(raw) - except ValueError: - result[key] = raw - return result - - -def cmd_list(args): - """Implement the cmd list helper. - - Args: - args (argparse.Namespace): Parsed command-line arguments. - - Returns: - Any: Computed result.""" - rows = list_models(category=args.category, supported=None if args.all else True) - if args.json: - print(json.dumps([item.__dict__ for item in rows], ensure_ascii=False, indent=2)) - return 0 - for item in rows: - status = "ok" if item.supported else item.unsupported_reason - category = item.category_path or item.primary_category - print(f"{item.name}\t{item.model_type or item.architecture}\t{category}\t{item.target_stem}\t{status}") - return 0 - - -def cmd_info(args): - """Implement the cmd info helper. - - Args: - args (argparse.Namespace): Parsed command-line arguments. - - Returns: - Any: Computed result.""" - resolved = resolve_model(args.model, model_dir=args.model_dir, require_supported=False, require_exists=False) - entry = resolved["entry"] - data = { - "name": entry.name, - "model_type": entry.model_type, - "architecture": entry.architecture, - "supported": entry.supported, - "unsupported_reason": entry.unsupported_reason, - "category": entry.category_path or entry.primary_category, - "category_cn": " / ".join(filter(None, [entry.primary_category_cn, entry.secondary_category_cn])), - "target_stem": entry.target_stem, - "model_path": resolved["model_path"], - "config_path": resolved["config_path"], - "size_bytes": entry.size_bytes, - } - print(json.dumps(data, ensure_ascii=False, indent=2)) - return 0 - - -def cmd_download(args): - """Implement the cmd download helper. - - Args: - args (argparse.Namespace): Parsed command-line arguments. - - Returns: - Any: Computed result.""" - if args.model == "all": - results = download_all( - model_dir=args.model_dir, - source=args.source, - endpoint=args.endpoint, - supported_only=args.supported_only, - force=args.force, - ) - failed = [item for item in results if item.get("error")] - print(f"Downloaded/skipped {len(results) - len(failed)} model(s), failed {len(failed)}.") - for item in failed: - print(f"ERROR {item['entry'].name}: {item['error']}", file=sys.stderr) - return 1 if failed else 0 - - result = download_model( - args.model, - model_dir=args.model_dir, - source=args.source, - endpoint=args.endpoint, - force=args.force, - ) - _print_download_result(result) - return 0 - - -def _print_download_result(result): - """Print download result. - - Args: - result (Any): Result value. - - Returns: - None: This callable completes for its side effects.""" - for path in result["skipped"]: - print(f"exists {path}") - for path in result["downloaded"]: - print(f"downloaded {path}") - - -def _ensure_model_files(args): - """Ensure model files. - - Args: - args (argparse.Namespace): Parsed command-line arguments. - - Returns: - None: This callable completes for its side effects.""" - try: - resolve_model(args.model, model_dir=args.model_dir, require_supported=True, require_exists=True) - except FileNotFoundError: - result = download_model(args.model, model_dir=args.model_dir, source=args.source, endpoint=args.endpoint) - _print_download_result(result) - else: - if args.download: - result = download_model(args.model, model_dir=args.model_dir, source=args.source, endpoint=args.endpoint) - _print_download_result(result) - - -def cmd_infer(args): - """Implement the cmd infer helper. - - Args: - args (argparse.Namespace): Parsed command-line arguments. - - Returns: - Any: Computed result.""" - _ensure_model_files(args) - logger = get_separation_logger() - inference_progress = _CliInferenceProgress() - with create_separator( - args.model, - model_dir=args.model_dir, - device=args.device, - device_ids=args.device_ids or [0], - output_format=args.output_format, - audio_params={ - "wav_bit_depth": args.wav_bit_depth, - "flac_bit_depth": args.flac_bit_depth, - "mp3_bit_rate": args.mp3_bit_rate, - "m4a_bit_rate": args.m4a_bit_rate, - "m4a_aac_at_quality": args.m4a_aac_at_quality, - }, - use_tta=args.tta, - store_dirs=args.output, - save_as_folder=args.save_as_folder, - logger=logger, - debug=args.debug, - progress_callback=inference_progress, - inference_params=_parse_key_value(args.param), - ) as separator: - try: - files = separator.process_folder(args.input) - finally: - inference_progress.close() - logger.info(f"Processed {len(files)} file(s).") - return 0 - - -def cmd_ensemble(args): - """Run the ensemble CLI command. - - Args: - args (argparse.Namespace): Parsed command-line arguments. - - Returns: - Any: Computed result.""" - logger = get_separation_logger() - output_path = save_ensemble_audio( - args.files, - args.output, - algorithm=args.algorithm, - weights=args.weights, - output_format=args.output_format, - audio_params={ - "wav_bit_depth": args.wav_bit_depth, - "flac_bit_depth": args.flac_bit_depth, - "mp3_bit_rate": args.mp3_bit_rate, - "m4a_bit_rate": args.m4a_bit_rate, - "m4a_codec": args.m4a_codec, - "m4a_aac_at_quality": args.m4a_aac_at_quality, - }, - logger=logger, - ) - logger.info(f"Saved ensemble audio to {output_path}") - return 0 - - -def cmd_workflow_init(args): - """Write a starter workflow file.""" - path = write_workflow_template(args.output, overwrite=args.force) - print(f"Wrote workflow template to {path}") - return 0 - - -def cmd_workflow_validate(args): - """Validate a workflow file without running inference.""" - workflow = load_workflow_file(args.config) - model_resolver = resolve_model if args.check_models or args.require_files else None - validate_workflow( - workflow, - model_dir=args.model_dir, - require_model_files=args.require_files, - model_resolver=model_resolver, - ) - print(f"Workflow is valid: {len(workflow.steps)} step(s).") - return 0 - - -def cmd_workflow_run(args): - """Run an audio workflow from a YAML/JSON file.""" - logger = get_separation_logger() - files = run_workflow_file( - args.config, - args.input, - args.output, - model_dir=args.model_dir, - device=args.device, - output_format=args.output_format, - download=args.download, - source=args.source, - endpoint=args.endpoint, - output_layout=args.output_layout, - audio_params={ - "wav_bit_depth": args.wav_bit_depth, - "flac_bit_depth": args.flac_bit_depth, - "mp3_bit_rate": args.mp3_bit_rate, - "m4a_bit_rate": args.m4a_bit_rate, - "m4a_codec": args.m4a_codec, - "m4a_aac_at_quality": args.m4a_aac_at_quality, - }, - logger=logger, - debug=args.debug, - ) - logger.info(f"Processed {len(files)} file(s).") - return 0 - - -def cmd_serve(args): - """Implement the cmd serve helper. - - Args: - args (argparse.Namespace): Parsed command-line arguments. - - Returns: - Any: Computed result.""" - from .server import ServerConfig, run_server - - config = ServerConfig( - model=args.model, - model_dir=args.model_dir, - source=args.source, - endpoint=args.endpoint, - device=args.device, - device_ids=args.device_ids or [0], - api_key=args.api_key, - host=args.host, - port=args.port, - debug=args.debug, - inference_params=_parse_key_value(args.param), - max_audio_seconds=args.max_audio_seconds, - max_request_bytes=args.max_request_bytes, - max_queue_size=args.max_queue_size, - request_timeout_seconds=args.request_timeout_seconds, - webui=args.webui, - ) - run_server(config) - return 0 - - -def build_parser(): - """Build the pymss command-line parser. - - Args: - None: This callable does not accept user-provided arguments. - - Returns: - argparse.ArgumentParser: Configured CLI parser.""" - parser = argparse.ArgumentParser( - prog="pymss", - description="Command-line interface for the pymss music source separation package.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - subparsers = parser.add_subparsers(dest="command", required=True) - - # ========================== - # List models - # ========================== - list_parser = subparsers.add_parser( - "list", - help="List known models.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - list_parser.add_argument("--category", help="Filter by primary or secondary category.") - list_parser.add_argument("--all", action="store_true", help="Include models that are not supported for inference yet.") - list_parser.add_argument("--json", action="store_true") - list_parser.set_defaults(func=cmd_list) - - # ========================== - # Show model info - # ========================== - info_parser = subparsers.add_parser( - "info", - help="Show model metadata.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - info_parser.add_argument("model") - info_parser.add_argument( - "--model-dir", - help="Local model cache directory. Defaults to PYMSS_MODEL_DIR, repository all_models if present, or ~/.cache/pymss/models.", - ) - info_parser.set_defaults(func=cmd_info) - - # ========================== - # Download models - # ========================== - download_parser = subparsers.add_parser( - "download", - help="Download a model by name, or use 'all'.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - download_parser.add_argument("model") - download_parser.add_argument( - "--model-dir", - help="Local model cache directory. Defaults to PYMSS_MODEL_DIR, repository all_models if present, or ~/.cache/pymss/models.", - ) - download_parser.add_argument("--source", default="modelscope", choices=["modelscope", "huggingface", "hf-mirror"]) - download_parser.add_argument("--endpoint", help="Custom resolve endpoint. It must serve files by relative path.") - download_parser.add_argument("--force", action="store_true") - download_parser.add_argument("--supported-only", action="store_true", help="Only used with model='all'.") - download_parser.set_defaults(func=cmd_download) - - # ========================== - # Inference - # ========================== - infer_parser = subparsers.add_parser( - "infer", - help="Run inference by model name.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - infer_parser.add_argument("model") - infer_parser.add_argument( - "--model-dir", - help="Local model cache directory. Defaults to PYMSS_MODEL_DIR, repository all_models if present, or ~/.cache/pymss/models.", - ) - infer_parser.add_argument( - "--download", - action="store_true", - help="Check/download the model before inference. Missing model files are downloaded automatically.", - ) - infer_parser.add_argument("--source", default="modelscope", choices=["modelscope", "huggingface", "hf-mirror"]) - infer_parser.add_argument("--endpoint", help="Custom resolve endpoint. It must serve files by relative path.") - infer_parser.add_argument("-i", "--input", required=True, help="Input audio file or folder.") - infer_parser.add_argument("-o", "--output", default="results", help="Output folder.") - infer_parser.add_argument( - "--save-as-folder", - action="store_true", - help="Save each input audio file's separated stems in a subfolder named after the audio file.", - ) - infer_parser.add_argument("--device", default="auto", choices=["auto", "cpu", "cuda", "mps", "mlx"]) - infer_parser.add_argument( - "--device-id", action="append", type=int, dest="device_ids", help="CUDA device id. Can be repeated." - ) - infer_parser.add_argument("--format", default="wav", choices=["wav", "flac", "mp3", "m4a"], dest="output_format") - infer_parser.add_argument("--wav-bit-depth", default="FLOAT", choices=["FLOAT", "PCM_16", "PCM_24"]) - infer_parser.add_argument("--flac-bit-depth", default="PCM_16", choices=["PCM_16", "PCM_24"]) - infer_parser.add_argument("--mp3-bit-rate", default="320k") - infer_parser.add_argument("--m4a-bit-rate", default="512k") - infer_parser.add_argument("--m4a-codec", default="aac") - infer_parser.add_argument("--m4a-aac-at-quality", default=2, type=int) - infer_parser.add_argument("--tta", action="store_true", help="Enable test time augmentation.") - infer_parser.add_argument("--debug", action="store_true") - infer_parser.add_argument( - "--param", action="append", default=[], help="Inference override as key=value, for example --param batch_size=2." - ) - infer_parser.set_defaults(func=cmd_infer) - - # ========================== - # Ensemble - # ========================== - ensemble_parser = subparsers.add_parser( - "ensemble", - help="Combine multiple audio files with an ensemble algorithm.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - ensemble_parser.add_argument("files", nargs="+", help="Input audio files. At least two files are required.") - ensemble_parser.add_argument( - "-a", - "--algorithm", - default="avg_wave", - choices=ENSEMBLE_ALGORITHMS, - help="Ensemble algorithm.", - ) - ensemble_parser.add_argument( - "-w", - "--weights", - nargs="+", - type=float, - help="Input weights, for example --weights 1 0.8 1.2. Defaults to all 1.", - ) - ensemble_parser.add_argument("-o", "--output", required=True, help="Output audio file.") - ensemble_parser.add_argument("--format", choices=["wav", "flac", "mp3", "m4a"], dest="output_format") - ensemble_parser.add_argument("--wav-bit-depth", default="FLOAT", choices=["FLOAT", "PCM_16", "PCM_24"]) - ensemble_parser.add_argument("--flac-bit-depth", default="PCM_16", choices=["PCM_16", "PCM_24"]) - ensemble_parser.add_argument("--mp3-bit-rate", default="320k") - ensemble_parser.add_argument("--m4a-bit-rate", default="512k") - ensemble_parser.add_argument("--m4a-codec", default="aac") - ensemble_parser.add_argument("--m4a-aac-at-quality", default=2, type=int) - ensemble_parser.set_defaults(func=cmd_ensemble) - - # ========================== - # Workflow - # ========================== - workflow_parser = subparsers.add_parser( - "workflow", - help="Create, validate, or run an automatic multi-model workflow.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - workflow_subparsers = workflow_parser.add_subparsers(dest="workflow_command", required=True) - - workflow_init_parser = workflow_subparsers.add_parser( - "init", - help="Write a starter workflow YAML file.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - workflow_init_parser.add_argument("-o", "--output", default="workflow.yaml", help="Workflow file to create.") - workflow_init_parser.add_argument("--force", action="store_true", help="Overwrite the output file if it exists.") - workflow_init_parser.set_defaults(func=cmd_workflow_init) - - workflow_validate_parser = workflow_subparsers.add_parser( - "validate", - help="Validate a workflow YAML/JSON file.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - workflow_validate_parser.add_argument("-c", "--config", required=True, help="Workflow YAML/JSON file.") - workflow_validate_parser.add_argument( - "--model-dir", - help="Local model cache directory used when --require-files is set.", - ) - workflow_validate_parser.add_argument( - "--check-models", - action="store_true", - help="Also check that every referenced model exists in the catalog.", - ) - workflow_validate_parser.add_argument( - "--require-files", - action="store_true", - help="Also require every referenced catalog model file to exist locally.", - ) - workflow_validate_parser.set_defaults(func=cmd_workflow_validate) - - workflow_run_parser = workflow_subparsers.add_parser( - "run", - help="Run inference through a workflow YAML/JSON file.", - formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=60), - ) - workflow_run_parser.add_argument("-c", "--config", required=True, help="Workflow YAML/JSON file.") - workflow_run_parser.add_argument("-i", "--input", required=True, help="Input audio file or folder.") - workflow_run_parser.add_argument("-o", "--output", default="results", help="Output folder.") - workflow_run_parser.add_argument( - "--output-layout", - default="folders", - choices=["folders", "flat"], - help=( - "Workflow output layout. 'folders' keeps each input under /