CoolFace
Apppublic

RO-Rtechs/Rtechs_voiceClone

sourceHugging Facemitupdated 2y agoView on Hugging Face
2likes
app.py543 linesDownload Raw Back to root
1import os2import gradio as gr3import spaces4from infer_rvc_python import BaseLoader5import random6import logging7import time8import soundfile as sf9from infer_rvc_python.main import download_manager10import zipfile11import edge_tts12import asyncio13import librosa14import traceback15import numpy as np16from pedalboard import Pedalboard, Reverb, Compressor, HighpassFilter17from pedalboard.io import AudioFile18from pydub import AudioSegment19import noisereduce as nr20 21logging.getLogger("infer_rvc_python").setLevel(logging.ERROR)22 23converter = BaseLoader(only_cpu=False, hubert_path=None, rmvpe_path=None)24 25title = "<center><strong><font size='7'>WELCOME TO RVC⚡RTECHS</font></strong></center>"26description = "This RVC is provided for RTECHS MEDIA PRODUCTIONS AND SOFTWARE DEV'S LOCAL purposes only. The authors (@Robel Adugna) and contributors of this project do not endorse or encourage any misuse or unethical use of this software. Any use of this software for purposes other than those intended is solely at the user's own risk. The authors and contributors shall not be held responsible for any damages or liabilities arising from the use of this demo inappropriately."27theme = "aliabid94/new-theme"28 29PITCH_ALGO_OPT = [30    "pm",31    "harvest",32    "crepe",33    "rmvpe",34    "rmvpe+"35]36 37 38def find_files(directory):39    file_paths = []40    for filename in os.listdir(directory):41        # Check if the file has the desired extension42        if filename.endswith('.pth') or filename.endswith('.zip') or filename.endswith('.index'):43            # If yes, add the file path to the list44            file_paths.append(os.path.join(directory, filename))45 46    return file_paths47 48 49def unzip_in_folder(my_zip, my_dir):50    with zipfile.ZipFile(my_zip) as zip:51        for zip_info in zip.infolist():52            if zip_info.is_dir():53                continue54            zip_info.filename = os.path.basename(zip_info.filename)55            zip.extract(zip_info, my_dir)56 57 58def find_my_model(a_, b_):59 60    if a_ is None or a_.endswith(".pth"):61        return a_, b_62 63    txt_files = []64    for base_file in [a_, b_]:65        if base_file is not None and base_file.endswith(".txt"):66            txt_files.append(base_file)67    68    directory = os.path.dirname(a_)69    70    for txt in txt_files:71        with open(txt, 'r') as file:72            first_line = file.readline()73    74        download_manager(75            url=first_line.strip(),76            path=directory,77            extension="",78        )79    80    for f in find_files(directory):81        if f.endswith(".zip"):82            unzip_in_folder(f, directory)83    84    model = None85    index = None86    end_files = find_files(directory)87    88    for ff in end_files:89        if ff.endswith(".pth"):90            model = os.path.join(directory, ff)91            gr.Info(f"Model found: {ff}")92        if ff.endswith(".index"):93            index = os.path.join(directory, ff)94            gr.Info(f"Index found: {ff}")95 96    if not model:97        gr.Error(f"Model not found in: {end_files}")98    99    if not index:100        gr.Warning("Index not found")101    102    return model, index103 104 105def add_audio_effects(audio_list):106    print("Audio effects")107 108    result = []109    for audio_path in audio_list:110        try:111            output_path = f'{os.path.splitext(audio_path)[0]}_effects.wav'112        113            # Initialize audio effects plugins114            board = Pedalboard(115                [116                    HighpassFilter(),117                    Compressor(ratio=4, threshold_db=-15),118                    Reverb(room_size=0.10, dry_level=0.8, wet_level=0.2, damping=0.7)119                 ]120            )121        122            with AudioFile(audio_path) as f:123                with AudioFile(output_path, 'w', f.samplerate, f.num_channels) as o:124                    # Read one second of audio at a time, until the file is empty:125                    while f.tell() < f.frames:126                        chunk = f.read(int(f.samplerate))127                        effected = board(chunk, f.samplerate, reset=False)128                        o.write(effected)129            result.append(output_path)130        except Exception as e:131            traceback.print_exc()132            print(f"Error noisereduce: {str(e)}")133            result.append(audio_path)134 135    return result136 137 138def apply_noisereduce(audio_list):139    # https://github.com/saif/Audio-Denoiser140    print("Noise reduction")141 142    result = []143    for audio_path in audio_list:144        out_path = f'{os.path.splitext(audio_path)[0]}_noisereduce.wav'145 146        try:147            # Load audio file148            audio = AudioSegment.from_file(audio_path)149 150            # Convert audio to numpy array151            samples = np.array(audio.get_array_of_samples())152 153            # Reduce noise154            reduced_noise = nr.reduce_noise(samples, sr=audio.frame_rate, prop_decrease=0.6)155 156            # Convert reduced noise signal back to audio157            reduced_audio = AudioSegment(158                reduced_noise.tobytes(),159                frame_rate=audio.frame_rate,160                sample_width=audio.sample_width,161                channels=audio.channels162            )163 164            # Save reduced audio to file165            reduced_audio.export(out_path, format="wav")166            result.append(out_path)167 168        except Exception as e:169            traceback.print_exc()170            print(f"Error in noise reduction: {str(e)}")171            result.append(audio_path)172 173    return result174 175 176def split_audio_into_chunks(audio_file, chunk_length_ms=30000):177    """178    Splits an audio file into smaller chunks.179    :param audio_file: Path to the input audio file.180    :param chunk_length_ms: Length of each chunk in milliseconds (default is 30 seconds).181    :return: List of chunk file paths.182    """183    try:184        audio = AudioSegment.from_file(audio_file)185        chunks = [audio[i:i + chunk_length_ms] for i in range(0, len(audio), chunk_length_ms)]186        chunk_paths = []187 188        base_name = os.path.splitext(os.path.basename(audio_file))[0]189        output_dir = os.path.join(os.path.dirname(audio_file), f"{base_name}_chunks")190        os.makedirs(output_dir, exist_ok=True)191 192        for index, chunk in enumerate(chunks):193            chunk_path = os.path.join(output_dir, f"{base_name}_chunk_{index + 1}.wav")194            chunk.export(chunk_path, format="wav")195            chunk_paths.append(chunk_path)196 197        return chunk_paths198    except Exception as e:199        traceback.print_exc()200        print(f"Error splitting audio into chunks: {str(e)}")201        return [audio_file]202 203 204@spaces.GPU()205def convert_now(audio_files, random_tag, converter):206    return converter(207        audio_files,208        random_tag,209        overwrite=False,210        parallel_workers=8211    )212 213 214def run(215    audio_files,216    file_m,217    pitch_alg,218    pitch_lvl,219    file_index,220    index_inf,221    r_m_f,222    e_r,223    c_b_p,224    active_noise_reduce,225    audio_effects,226    chunk_length_ms=30000227):228    if not audio_files:229        raise ValueError("Please provide audio files")230 231    if isinstance(audio_files, str):232        audio_files = [audio_files]233 234    if file_m is not None and file_m.endswith(".txt"):235        file_m, file_index = find_my_model(file_m, file_index)236        print(file_m, file_index)237 238    random_tag = "USER_" + str(random.randint(10000000, 99999999))239 240    converter.apply_conf(241        tag=random_tag,242        file_model=file_m,243        pitch_algo=pitch_alg,244        pitch_lvl=pitch_lvl,245        file_index=file_index,246        index_influence=index_inf,247        respiration_median_filtering=r_m_f,248        envelope_ratio=e_r,249        consonant_breath_protection=c_b_p,250        resample_sr=44100 if audio_files[0].endswith('.mp3') else 0,251    )252    time.sleep(0.1)253 254    # Split each audio file into chunks255    chunked_audio_files = []256    for audio_file in audio_files:257        chunked_audio_files.extend(split_audio_into_chunks(audio_file, chunk_length_ms))258 259    result = convert_now(chunked_audio_files, random_tag, converter)260 261    if active_noise_reduce:262        result = apply_noisereduce(result)263 264    if audio_effects:265        result = add_audio_effects(result)266 267    return result268 269 270def audio_conf():271    return gr.File(272        label="Audio files",273        file_count="multiple",274        type="filepath",275        container=True,276    )277 278 279def model_conf():280    return gr.File(281        label="Model file",282        type="filepath",283        height=130,284    )285 286 287def pitch_algo_conf():288    return gr.Dropdown(289        PITCH_ALGO_OPT,290        value=PITCH_ALGO_OPT[4],291        label="Pitch algorithm",292        visible=True,293        interactive=True,294    )295 296 297def pitch_lvl_conf():298    return gr.Slider(299        label="Pitch level",300        minimum=-24,301        maximum=24,302        step=1,303        value=0,304        visible=True,305        interactive=True,306    )307 308 309def index_conf():310    return gr.File(311        label="Index file",312        type="filepath",313        height=130,314    )315 316 317def index_inf_conf():318    return gr.Slider(319        minimum=0,320        maximum=1,321        label="Index influence",322        value=0.75,323    )324 325 326def respiration_filter_conf():327    return gr.Slider(328        minimum=0,329        maximum=7,330        label="Respiration median filtering",331        value=3,332        step=1,333        interactive=True,334    )335 336 337def envelope_ratio_conf():338    return gr.Slider(339        minimum=0,340        maximum=1,341        label="Envelope ratio",342        value=0.25,343        interactive=True,344    )345 346 347def consonant_protec_conf():348    return gr.Slider(349        minimum=0,350        maximum=0.5,351        label="Consonant breath protection",352        value=0.5,353        interactive=True,354    )355 356 357def button_conf():358    return gr.Button(359        "Inference",360        variant="primary",361    )362 363 364def output_conf():365    return gr.File(366        label="Result",367        file_count="multiple",368        interactive=False,369    )370 371 372def active_tts_conf():373    return gr.Checkbox(374        False,375        label="TTS",376        container=False,377    )378 379 380def tts_voice_conf():381    return gr.Dropdown(382        label="TTS Voice",383        choices=[384            "en-US-EmmaMultilingualNeural-Female",385            "en-US-GuyMultilingualNeural-Male",386            "en-GB-SoniaNeural-Female",387            "fr-FR-DeniseNeural-Female"388        ],389        visible=False,390        value="en-US-EmmaMultilingualNeural-Female",391    )392 393 394def tts_text_conf():395    return gr.Textbox(396        value="",397        placeholder="Write the text here...",398        label="Text",399        visible=False,400        lines=3,401    )402 403 404def tts_button_conf():405    return gr.Button(406        "Process TTS",407        variant="secondary",408        visible=False,409    )410 411 412def tts_play_conf():413    return gr.Checkbox(414        False,415        label="Play",416        container=False,417        visible=False,418    )419 420 421def sound_gui():422    return gr.Audio(423        value=None,424        type="filepath",425        autoplay=True,426        visible=False,427    )428 429 430def denoise_conf():431    return gr.Checkbox(432        False,433        label="Denoise",434        container=False,435        visible=True,436    )437 438 439def effects_conf():440    return gr.Checkbox(441        False,442        label="Effects",443        container=False,444        visible=True,445    )446 447 448def infer_tts_audio(tts_voice, tts_text, play_tts):449    out_dir = "output"450    folder_tts = "USER_" + str(random.randint(10000, 99999))451 452    os.makedirs(out_dir, exist_ok=True)453    os.makedirs(os.path.join(out_dir, folder_tts), exist_ok=True)454    out_path = os.path.join(out_dir, folder_tts, "tts.mp3")455 456    asyncio.run(edge_tts.Communicate(tts_text, "-".join(tts_voice.split('-')[:-1])).save(out_path))457    if play_tts:458        return [out_path], out_path459    return [out_path], None460 461 462def show_components_tts(value_active):463    return gr.update(464        visible=value_active465    ), gr.update(466        visible=value_active467    ), gr.update(468        visible=value_active469    ), gr.update(470        visible=value_active471    )472 473 474def get_gui(theme):475    with gr.Blocks(theme=theme) as app:476        gr.Markdown(title)477        gr.Markdown(description)478 479        active_tts = active_tts_conf()480        with gr.Row():481            with gr.Column(scale=1):482                tts_text = tts_text_conf()483            with gr.Column(scale=2):484                with gr.Row():485                    with gr.Column():486                        with gr.Row():487                            tts_voice = tts_voice_conf()488                            tts_active_play = tts_play_conf()489 490                tts_button = tts_button_conf()491                tts_play = sound_gui()492 493        active_tts.change(494            fn=show_components_tts,495            inputs=[active_tts],496            outputs=[tts_voice, tts_text, tts_button, tts_active_play],497        )498 499        aud = audio_conf()500        gr.HTML("<hr></h2>")501 502        tts_button.click(503            fn=infer_tts_audio,504            inputs=[tts_voice, tts_text, tts_active_play],505            outputs=[aud, tts_play],506        )507 508        with gr.Column():509            with gr.Row():510                model = model_conf()511                indx = index_conf()512        algo = pitch_algo_conf()513        algo_lvl = pitch_lvl_conf()514        indx_inf = index_inf_conf()515        res_fc = respiration_filter_conf()516        envel_r = envelope_ratio_conf()517        const = consonant_protec_conf()518        denoise = denoise_conf()519        effects = effects_conf()520        inference_button = button_conf()521        output = output_conf()522 523        inference_button.click(524            fn=run,525            inputs=[526                aud,527                model,528                algo,529                algo_lvl,530                indx,531                indx_inf,532                res_fc,533                envel_r,534                const,535                denoise,536                effects,537            ],538            outputs=[output],539        )540 541        app.launch(share=True)542 543get_gui(theme=theme)