File size: 7,247 Bytes
bd4ee86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# -*- coding: utf-8 -*-
import os, sys
import tkinter as tk
from tkinter import filedialog
from pathlib import Path
import soundfile as sf

# =========================
#        CONFIG
# =========================
AUTO_MODE = True  # <<<< Set False to ask the user on launch

# Root directories (relative to this script’s folder)
RVC_DIR     = Path(__file__).resolve().parent
WEIGHTS_DIR = (RVC_DIR / "assets" / "weights").resolve()
INDEX_DIR   = (RVC_DIR / "logs").resolve()
UVR5_DIR    = (RVC_DIR / "assets" / "uvr5_weights").resolve()
HUBERT_PATH = (RVC_DIR / "assets" / "hubert" / "hubert_base.pt").resolve()

# Default params (only model/index filenames, not full paths)
AUTO_PARAMS = {
    "model_name": "Marceline EN.pth",
    "index_name": "Marceline EN.index",
    "voices_dir": r"SET YOUR VOICE PATH IN THE \"myInferFast.py\" SCRIPT FIRST <3",
    "pitch": 0,
    "f0method": "crepe",   # pm | harvest | crepe | rmvpe
    "index_rate": 0.75,
    "protect": 0.33,
}

# Build absolute paths automatically
AUTO_PARAMS["model_path"] = str((WEIGHTS_DIR / AUTO_PARAMS["model_name"]).resolve())
AUTO_PARAMS["index_path"] = str((INDEX_DIR / AUTO_PARAMS["index_name"]).resolve())

# =========================
#   RVC ENVIRONMENT SETUP
# =========================
sys.path.append(str(RVC_DIR))
os.chdir(str(RVC_DIR))

os.environ["weight_root"]      = str(WEIGHTS_DIR)
os.environ["index_root"]       = str(INDEX_DIR)
os.environ["weight_uvr5_root"] = str(UVR5_DIR)
if HUBERT_PATH.exists():
    os.environ["hubert_path"] = str(HUBERT_PATH)

print("[ENV] RVC_DIR     =", RVC_DIR)
print("[ENV] weight_root =", os.environ.get("weight_root"))
print("[ENV] index_root  =", os.environ.get("index_root"))
print("[ENV] hubert_path =", os.environ.get("hubert_path"))

# Shim for omegaconf import issue
try:
    import importlib, omegaconf
    sys.modules['_utils'] = importlib.import_module('omegaconf._utils')
except Exception:
    pass

# Imports RVC
from configs.config import Config
from infer.modules.vc.modules import VC

config = Config()
vc = VC(config)

# =========================
#   INTERACTIVE UTILITIES
# =========================
def choose_file(title, patterns):
    root = tk.Tk()
    root.withdraw()
    return filedialog.askopenfilename(title=title, filetypes=patterns)

def choose_dir(title):
    root = tk.Tk()
    root.withdraw()
    return filedialog.askdirectory(title=title)

def ask_params():
    print("=== INTERACTIVE MODE ===")
    model_path = choose_file("Choose a model (.pth)", [("RVC Model", "*.pth")])
    index_path = choose_file("Choose an index (.index)", [("RVC Index", "*.index")])
    voices_dir = choose_dir("Choose the VOICES folder")

    use_auto = (input("Load default params? (y/n) [y]: ").strip().lower() or "y") == "y"
    if use_auto:
        pitch     = AUTO_PARAMS["pitch"]
        f0method  = AUTO_PARAMS["f0method"]
        index_rate= AUTO_PARAMS["index_rate"]
        protect   = AUTO_PARAMS["protect"]
    else:
        pitch     = int(input("Pitch shift [0]: ") or "0")
        f0method  = (input("F0 method (pm/harvest/crepe/rmvpe) [crepe]: ").strip() or "crepe")
        index_rate= float(input("Index rate (0..1) [0.75]: ") or "0.75")
        protect   = float(input("Protect (0..0.5) [0.33]: ") or "0.33")

    return {
        "model_path": model_path,
        "index_path": index_path,
        "voices_dir": voices_dir,
        "pitch": pitch,
        "f0method": f0method,
        "index_rate": index_rate,
        "protect": protect,
    }

# =========================
#     FILE CONVERSION
# =========================
def convert_file(model_path, index_path, input_path, output_path, pitch, f0method, index_rate, protect):
    print(f"[+] Converting {os.path.basename(input_path)}")

    model_name = os.path.basename(model_path)
    try:
        vc.get_vc(model_name, protect, protect)
    except Exception as e:
        print(f"[!] Model load error {model_name}: {e}")
        return

    use_index = True
    if not index_path or not os.path.exists(index_path):
        print(f"[!] Index not found → disabled (index_rate=0). Expected: {index_path}")
        use_index = False

    info, (sr, wav_opt) = vc.vc_single(
        0,                                   # sid
        input_path,                          # audio source
        pitch,                               # semitones
        None,                                # f0_file
        f0method,                            # pm / harvest / crepe / rmvpe
        index_path if use_index else "",     # file_index
        None,                                # file_index2
        index_rate if use_index else 0.0,    # index_rate
        3,                                   # filter_radius
        0,                                   # resample_sr
        1.0,                                 # rms_mix_rate
        protect,                             # protect
    )

    if wav_opt is None:
        print(f"[!] Error with {input_path}:\n{info}")
        return

    try:
        sf.write(output_path, wav_opt, sr)
        print(f"[OK] Saved → {output_path}")
    except Exception as e:
        print(f"[!] Write failed {output_path}: {e}")

# =========================
#          MAIN
# =========================
def main():
    if AUTO_MODE:
        params = AUTO_PARAMS.copy()
        print("=== AUTO MODE ===")
    else:
        use_auto = (input("Load auto config? (y/n) [y]: ").strip().lower() or "y") == "y"
        if use_auto:
            params = AUTO_PARAMS.copy()
            print("=== AUTO MODE (forced) ===")
        else:
            params = ask_params()

    model_path = params["model_path"]
    index_path = params["index_path"]
    voices_dir = params["voices_dir"]
    pitch      = params["pitch"]
    f0method   = params["f0method"]
    index_rate = params["index_rate"]
    protect    = params["protect"]

    if not voices_dir or not os.path.isdir(voices_dir):
        print(f"[!] Invalid voices directory: {voices_dir}")
        input("\nPress any key to close...")
        return

    output_dir = os.path.join(voices_dir, "clone")
    os.makedirs(output_dir, exist_ok=True)

    exts = (".wav", ".mp3", ".flac", ".m4a", ".aac", ".ogg")
    files = [f for f in os.listdir(voices_dir) if f.lower().endswith(exts)]

    if not files:
        print(f"[!] No audio files found in: {voices_dir}")
        input("\nPress any key to close...")
        return

    for file in files:
        in_path = os.path.join(voices_dir, file)
        out_path = os.path.join(output_dir, Path(file).stem + "_converted.wav")
        try:
            convert_file(
                model_path,
                index_path,
                in_path,
                out_path,
                pitch,
                f0method,
                index_rate,
                protect,
            )
        except Exception as e:
            print(f"[!] Error with {file}: {e}")

    print(f"\n✅ Conversion complete → {output_dir}")
    input("Press any key to close...")

if __name__ == "__main__":
    main()