From 84312bb6b44916956b6e0c4248a9fc39da2a2edf Mon Sep 17 00:00:00 2001 From: erew123 <35898566+erew123@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:42:54 +0100 Subject: [PATCH] RVC Pitch on API adds RVC pitch to the API and generate screen. Still need to update TGWUI, SillyTavern Extensions along with documentation. --- script.py | 30 +++++++++--- tts_server.py | 123 ++++++++++++++++++-------------------------------- 2 files changed, 66 insertions(+), 87 deletions(-) diff --git a/script.py b/script.py index 2ecb3a6..3e10aa1 100644 --- a/script.py +++ b/script.py @@ -1436,7 +1436,7 @@ if gradio_enabled == True: ############################### # Sends voice2rvc request off # ############################### - def voice2rvc(audio, rvc_voice): + def voice2rvc(audio, rvc_voice, rvc_pitch, rvc_f0method): # Save the uploaded or recorded audio to a file input_tts_path = this_dir / "outputs" / "voice2rvcInput.wav" if rvc_voice == "Disabled": @@ -1464,7 +1464,9 @@ if gradio_enabled == True: response = requests.post(url, data={ "input_tts_path": str(input_tts_path), "output_rvc_path": str(output_rvc_path), - "pth_name": rvc_voice + "pth_name": rvc_voice, + "pitch": rvc_pitch, + "method": str(rvc_f0method), }) if response.status_code == 200: @@ -1615,7 +1617,7 @@ if gradio_enabled == True: save_config_data() return "RVC settings updated successfully!" - def generate_tts(gen_text, gen_char, rvcgen_char, gen_narr, rvcgen_narr, gen_narren, gen_textni, gen_repetition, gen_lang, gen_filter, gen_speed, gen_pitch, gen_autopl, gen_autoplvol, gen_filen, gen_temperature, gen_filetime, gen_stream, gen_stopcurrentgen): + def generate_tts(gen_text, gen_char, rvcgen_char, rvcgen_char_pitch, gen_narr, rvcgen_narr, rvcgen_narr_pitch, gen_narren, gen_textni, gen_repetition, gen_lang, gen_filter, gen_speed, gen_pitch, gen_autopl, gen_autoplvol, gen_filen, gen_temperature, gen_filetime, gen_stream, gen_stopcurrentgen): if running_on_google_colab: api_url = f"{tunnel_url_1}/api/tts-generate" else: @@ -1639,9 +1641,11 @@ if gradio_enabled == True: "text_filtering": gen_filter, "character_voice_gen": gen_char, "rvccharacter_voice_gen": rvcgen_char, + "rvccharacter_pitch": rvcgen_char_pitch, "narrator_enabled": str(gen_narren).lower(), "narrator_voice_gen": gen_narr, "rvcnarrator_voice_gen": rvcgen_narr, + "rvcnarrator_pitch": rvcgen_narr_pitch, "text_not_inside": gen_textni, "language": gen_lang, "output_file_name": gen_filen, @@ -1755,6 +1759,15 @@ if gradio_enabled == True: if rvcat_narrator_voice_gr not in rvcat_available_voices_gr: rvcat_narrator_voice_gr = rvcat_available_voices_gr[0] if rvcat_available_voices_gr else "" rvcgen_narr = gr.Dropdown(choices=rvcat_available_voices_gr, label="RVC Narrator Voice", value=rvcat_narrator_voice_gr, allow_custom_value=True,) + with gr.Group(): + with gr.Row(): + rvcat_default_pitch_gr = gr.Slider(minimum=-24, maximum=24, step=1, label="RVC Character Pitch", info="Corrects the Character input TTS pitch to match the desired RVC voice output pitch.", value=params["rvc_settings"].get("pitch", 0), interactive=True, visible=False) + rvcat_narrator_pitch_gr = gr.Slider(minimum=-24, maximum=24, step=1, label="RVC Narrator Pitch", info="Corrects the Narrator input TTS pitch to match the desired RVC voice output pitch.", value=params["rvc_settings"].get("pitch", 0), interactive=True, visible=False) + def update_visibility(char_voice, narr_voice): + is_visible = char_voice != "Disabled" or narr_voice != "Disabled" + return gr.update(visible=is_visible), gr.update(visible=is_visible) + rvcgen_char.change(fn=update_visibility, inputs=[rvcgen_char, rvcgen_narr], outputs=[rvcat_default_pitch_gr, rvcat_narrator_pitch_gr]) + rvcgen_narr.change(fn=update_visibility, inputs=[rvcgen_char, rvcgen_narr], outputs=[rvcat_default_pitch_gr, rvcat_narrator_pitch_gr]) with gr.Accordion("Advanced Engine/Model Settings", open=False): with gr.Row(): @@ -1816,7 +1829,7 @@ if gradio_enabled == True: }""", show_api=False) refresh_button.click(at_update_dropdowns, None, [gen_stream, gen_char, rvcgen_char, gen_narr, rvcgen_narr, gen_speed, gen_pitch, gen_temperature, gen_repetition, gen_lang, model_choices_gr, engine_choices]) stop_button.click(stop_generate_tts, inputs=[], outputs=[output_message]) - submit_button.click(generate_tts, inputs=[gen_text, gen_char, rvcgen_char, gen_narr, rvcgen_narr, gen_narren, gen_textni, gen_repetition, gen_lang, gen_filter, gen_speed, gen_pitch, gen_autopl, gen_autoplvol, gen_filen, gen_temperature, gen_filetime, gen_stream, gen_stopcurrentgen], outputs=[output_audio, output_message]) + submit_button.click(generate_tts, inputs=[gen_text, gen_char, rvcgen_char, rvcat_default_pitch_gr, gen_narr, rvcgen_narr, rvcat_narrator_pitch_gr, gen_narren, gen_textni, gen_repetition, gen_lang, gen_filter, gen_speed, gen_pitch, gen_autopl, gen_autoplvol, gen_filen, gen_temperature, gen_filetime, gen_stream, gen_stopcurrentgen], outputs=[output_audio, output_message]) with gr.Tab("Generate Help"): help_content = alltalk_generation_help() @@ -1827,11 +1840,14 @@ if gradio_enabled == True: with gr.Row(): audio_input = gr.Audio(sources=["microphone", "upload"], type="numpy", label="Record audio or Upload a spoken audio file") with gr.Row(): - rvc_voices_dropdown = gr.Dropdown(choices=at_settings["rvcvoices"], label="Select RVC Voice to generate as", value=at_settings["rvcvoices"][0]) - submit_button = gr.Button("Submit to RVC") + rvc_voices_dropdown = gr.Dropdown(choices=at_settings["rvcvoices"], label="Select RVC Voice to generate as", value=at_settings["rvcvoices"][0], scale=1) + rvc_pitch_slider = gr.Slider(minimum=-24, maximum=24, step=1, label="RVC Pitch", info="Depending on the pitch of your input audio, you will need to adjust this accordingly to change the pitch for the output voice. The higher the value, the higher the pitch.", value=0, interactive=True, scale=2) + with gr.Row(): + rvc_f0method = gr.Radio(label="Pitch Extraction Algorithm", info="Select the algorithm to be used for extracting the pitch (F0) during audio conversion. The default algorithm is rmvpe, which is generally recommended for most cases due to its balance of accuracy and performance.", choices=["crepe", "crepe-tiny", "dio", "fcpe", "harvest", "hybrid[rmvpe+fcpe]", "pm", "rmvpe"], value=params["rvc_settings"].get("f0method", "rmvpe"), interactive=True, scale=1) + submit_button = gr.Button("Submit to RVC", scale=0) audio_output = gr.Audio(label="Converted Audio") - submit_button.click(fn=voice2rvc, inputs=[audio_input, rvc_voices_dropdown], outputs=audio_output) + submit_button.click(fn=voice2rvc, inputs=[audio_input, rvc_voices_dropdown, rvc_pitch_slider, rvc_f0method], outputs=audio_output) with gr.Tab("TTS Generator"): gr.Markdown("""With the TTS Generator you can create incredibly long audio e.g. entire books. Yet to be migrated into Gradio""") diff --git a/tts_server.py b/tts_server.py index 2366b87..c32a4cf 100644 --- a/tts_server.py +++ b/tts_server.py @@ -451,7 +451,7 @@ async def deepspeed(request: Request, new_deepspeed_value: bool): # API Endpoint - /api/voice2rvc # ################################# @app.post("/api/voice2rvc") -async def voice2rvc(input_tts_path: str = Form(...), output_rvc_path: str = Form(...), pth_name: str = Form(...)): +async def voice2rvc(input_tts_path: str = Form(...), output_rvc_path: str = Form(...), pth_name: str = Form(...), pitch: str = Form(...), method: str = Form(...)): try: # Handle "Disabled" case if pth_name.lower() in ["disabled", "disable"]: @@ -468,7 +468,7 @@ async def voice2rvc(input_tts_path: str = Form(...), output_rvc_path: str = Form if not pth_path.is_file(): raise HTTPException(status_code=400, detail=f"Model file {pth_path} does not exist.") # Run the RVC conversion - result_path = run_voice2rvc(input_tts_path, output_rvc_path, pth_path) + result_path = run_voice2rvc(input_tts_path, output_rvc_path, pth_path, pitch, method) if result_path: return {"status": "success", "output_path": str(result_path)} else: @@ -478,80 +478,16 @@ async def voice2rvc(input_tts_path: str = Form(...), output_rvc_path: str = Form raise HTTPException(status_code=500, detail=str(e)) # Define the run_rvc function -def run_voice2rvc(input_tts_path, output_rvc_path, pth_path): +def run_voice2rvc(input_tts_path, output_rvc_path, pth_path, pitch, method): print(f"[{branding}GEN] \033[94mVoice2RVC Convert: Started\033[0m") generate_start_time = time.time() - f0up_key = rvc_settings["pitch"] + f0up_key = pitch filter_radius = rvc_settings["filter_radius"] index_rate = rvc_settings["index_rate"] rms_mix_rate = rvc_settings["rms_mix_rate"] protect = rvc_settings["protect"] hop_length = rvc_settings["hop_length"] - f0method = rvc_settings["f0method"] - split_audio = rvc_settings["split_audio"] - f0autotune = rvc_settings["autotune"] - embedder_model = rvc_settings["embedder_model"] - training_data_size = rvc_settings["training_data_size"] - # Convert path variables to strings - input_tts_path = str(input_tts_path) - pth_path = str(pth_path) - # Check if the model file exists - if not os.path.isfile(pth_path): - print(f"Model file {pth_path} does not exist. Exiting.") - return - # Get the directory of the model file - model_dir = os.path.dirname(pth_path) - # Find all .index files in the model directory - index_files = [file for file in os.listdir(model_dir) if file.endswith(".index")] - if len(index_files) == 1: - index_path = str(os.path.join(model_dir, index_files[0])) - else: - index_path = "" - # Call the infer_pipeline function - infer_pipeline(f0up_key, filter_radius, index_rate, rms_mix_rate, protect, hop_length, f0method, - input_tts_path, output_rvc_path, pth_path, index_path, split_audio, f0autotune, embedder_model, training_data_size, debug_rvc) - generate_end_time = time.time() - generate_elapsed_time = generate_end_time - generate_start_time - print(f"[{branding}GEN] \033[94mVoice2RVC Convert: \033[91m{generate_elapsed_time:.2f} seconds.\033[0m") - return output_rvc_path - -################################# -# API Endpoint - /api/voice2rvc # -################################# -@app.post("/api/voice2rvc") -async def voice2rvc(input_tts_path: str = Form(...), output_rvc_path: str = Form(...), pth_name: str = Form(...)): - try: - input_tts_path = Path(input_tts_path) - output_rvc_path = Path(output_rvc_path) - # Check if input file exists - if not input_tts_path.is_file(): - raise HTTPException(status_code=400, detail=f"Input file {input_tts_path} does not exist.") - # Define the model path based on the selected model name - pth_path = this_dir / "models" / "rvc_voices" / pth_name - # Check if model file exists - if not pth_path.is_file(): - raise HTTPException(status_code=400, detail=f"Model file {pth_path} does not exist.") - # Run the RVC conversion - result_path = run_voice2rvc(input_tts_path, output_rvc_path, pth_path) - if result_path: - return {"status": "success", "output_path": str(result_path)} - else: - raise HTTPException(status_code=500, detail="RVC conversion failed.") - except Exception as e: - print(f"Error during Voice2RVC conversion: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Define the run_rvc function -def run_voice2rvc(input_tts_path, output_rvc_path, pth_path): - print(f"[{branding}GEN] \033[94mVoice2RVC Convert: Started\033[0m") - generate_start_time = time.time() - f0up_key = rvc_settings["pitch"] - filter_radius = rvc_settings["filter_radius"] - index_rate = rvc_settings["index_rate"] - rms_mix_rate = rvc_settings["rms_mix_rate"] - protect = rvc_settings["protect"] - hop_length = rvc_settings["hop_length"] - f0method = rvc_settings["f0method"] + f0method = method split_audio = rvc_settings["split_audio"] f0autotune = rvc_settings["autotune"] embedder_model = rvc_settings["embedder_model"] @@ -1050,9 +986,9 @@ def combine(output_file_timestamp, output_file_name, audio_files, target_sample_ ################################## # Central RVC Generation request # ################################## -def run_rvc(input_tts_path, pth_path, infer_pipeline): +def run_rvc(input_tts_path, pth_path, pitch, infer_pipeline): generate_start_time = time.time() - f0up_key = rvc_settings["pitch"] + f0up_key = pitch filter_radius = rvc_settings["filter_radius"] index_rate = rvc_settings["index_rate"] rms_mix_rate = rvc_settings["rms_mix_rate"] @@ -1131,13 +1067,13 @@ def run_rvc(input_tts_path, pth_path, infer_pipeline): #################################################################### # /api/tts-generate Generation API Endpoint Narration RVC handling # #################################################################### -def process_rvc_narrator(part_type, voice_gen, default_model_file, output_file, infer_pipeline): +def process_rvc_narrator(part_type, voice_gen, pitch, default_model_file, output_file, infer_pipeline): if voice_gen.lower() in ["disabled", "disable"]: return else: voice_gen_path = this_dir / "models" / "rvc_voices" / voice_gen pth_path = voice_gen_path if voice_gen else default_model_file - run_rvc(output_file, pth_path, infer_pipeline) + run_rvc(output_file, pth_path, pitch, infer_pipeline) ############################################################# # /api/tts-generate Generation API Endpoint JSON validation # @@ -1147,9 +1083,11 @@ class JSONInput(BaseModel): text_filtering: str = Field(..., pattern="^(none|standard|html)$", description="text_filtering needs to be 'none', 'standard' or 'html'.") character_voice_gen: str = Field(..., pattern=r'^[\(\)a-zA-Z0-9\_\-./\s]+$', description="character_voice_gen needs to be the name of a valid voice for the loaded TTS engine.") rvccharacter_voice_gen: str = Field(..., description="rvccharacter_voice_gen needs to be the name of a valid pth file in the 'folder\\file.pth' format or the word 'Disabled'.") + rvccharacter_pitch: str = Field(..., description="RVC Character pitch needs to be a number between -24 and 24") narrator_enabled: str = Field(..., pattern="^(true|false|silent)$", description="narrator_enabled needs to be 'true', 'false' or 'silent'.") narrator_voice_gen: str = Field(..., pattern=r'^[\(\)a-zA-Z0-9\_\-./\s]+$', description="character_voice_gen needs to be the name of a valid voice for the loaded TTS engine.") - rvcnarrator_voice_gen: str = Field(..., description="rvcnarrator_voice_gen needs to be the name of a valid pth file in the 'folder\\file.pth' format or the word 'Disabled'.") + rvcnarrator_voice_gen: str = Field(..., description="rvcnarrator_voice_gen needs to be the name of a valid pth file in the 'folder\\file.pth' format or the word 'Disabled'.") + rvcnarrator_pitch: str = Field(..., description="RVC Narrator pitch needs to be a number between -24 and 24") text_not_inside: str = Field(..., pattern="^(character|narrator|silent)$", description="text_not_inside needs to be 'character', 'narrator' or 'silent'.") language: str = Field(..., pattern="^(ar|zh-cn|cs|nl|en|fr|de|hu|hi|it|ja|ko|pl|pt|ru|es|tr)$", description="language needs to be one of the following: ar, zh-cn, cs, nl, en, fr, de, hu, hi, it, ja, ko, pl, pt, ru, es, tr.") output_file_name: str = Field(..., pattern="^[a-zA-Z0-9_]+$", description="output_file_name needs to be the name without any special characters or file extension, e.g., 'filename'.") @@ -1175,13 +1113,22 @@ class JSONInput(BaseModel): raise ValueError("rvccharacter_voice_gen needs to be the name of a valid pth file in the 'folder\\file.pth' format or 'Disabled'.") return v - def validate_rvccharacter_voice_gen(cls, v): + def validate_rvnarrator_voice_gen(cls, v): if v.lower() == "disabled": return v pattern = re.compile(r'^.*\.(pth)$') if not pattern.match(v): raise ValueError("rvcnarrator_voice_gen needs to be the name of a valid pth file in the 'folder\\file.pth' format or 'Disabled'.") return v + + def validate_pitches(cls, value): + try: + num_value = float(value) + except ValueError: + raise ValueError("Pitch must be a number or a string representing a number.") + if not -24 <= num_value <= 24: + raise ValueError("Pitch needs to be a number between -24 and 24.") + return value def validate_json_input(json_input_data): try: @@ -1228,10 +1175,14 @@ def get_character_voice_gen(): return model_engine.def_character_voice def get_rvccharacter_voice_gen(): return rvc_settings["rvc_char_model_file"] +def get_rvccharacter_pitch(): + return rvc_settings["pitch"] def get_narrator_voice_gen(): return model_engine.def_narrator_voice def get_rvcnarrator_voice_gen(): return rvc_settings["rvc_narr_model_file"] +def get_rvcnarrator_pitch(): + return rvc_settings["pitch"] ############################################# # /api/tts-generate Generation API Endpoint # @@ -1242,9 +1193,11 @@ async def apifunction_generate_tts_standard( text_filtering: str = Form(None), character_voice_gen: str = Form(None), rvccharacter_voice_gen: str = Form(None), + rvccharacter_pitch: str = Form(None), narrator_enabled: str = Form(None), narrator_voice_gen: str = Form(None), rvcnarrator_voice_gen: str = Form(None), + rvcnarrator_pitch: str = Form(None), text_not_inside: str = Form(None), language: str = Form(None), output_file_name: str = Form(None), @@ -1259,9 +1212,11 @@ async def apifunction_generate_tts_standard( _text_filtering: str = Depends(get_api_text_filtering), _character_voice_gen: str = Depends(get_character_voice_gen), _rvccharacter_voice_gen: str = Depends(get_rvccharacter_voice_gen), + _rvccharacter_pitch: str = Depends(get_rvccharacter_pitch), _narrator_enabled: str = Depends(get_api_narrator_enabled), _narrator_voice_gen: str = Depends(get_narrator_voice_gen), _rvcnarrator_voice_gen: str = Depends(get_rvcnarrator_voice_gen), + _rvcnarrator_pitch: str = Depends(get_rvcnarrator_pitch), _text_not_inside: str = Depends(get_api_text_not_inside), _language: str = Depends(get_api_language), _output_file_name: str = Depends(get_api_output_file_name), @@ -1288,9 +1243,11 @@ async def apifunction_generate_tts_standard( f"[{branding}Debug] text_filtering : {text_filtering}", f"[{branding}Debug] character_voice_gen : {character_voice_gen}", f"[{branding}Debug] rvccharacter_voice_gen : {rvccharacter_voice_gen}", + f"[{branding}Debug] rvccharacter_pitch : {rvccharacter_pitch}", f"[{branding}Debug] narrator_enabled : {narrator_enabled}", f"[{branding}Debug] narrator_voice_gen : {narrator_voice_gen}", f"[{branding}Debug] rvcnarrator_voice_gen : {rvcnarrator_voice_gen}", + f"[{branding}Debug] rvcnarrator_pitch : {rvcnarrator_pitch}", f"[{branding}Debug] text_not_inside : {text_not_inside}", f"[{branding}Debug] language : {language}", f"[{branding}Debug] output_file_name : {output_file_name}", @@ -1308,9 +1265,11 @@ async def apifunction_generate_tts_standard( text_filtering = text_filtering or _text_filtering character_voice_gen = character_voice_gen or _character_voice_gen rvccharacter_voice_gen = rvccharacter_voice_gen or _rvccharacter_voice_gen + rvccharacter_pitch = rvccharacter_pitch or _rvccharacter_pitch narrator_enabled = narrator_enabled or _narrator_enabled # NEED TO COME BACK AND LOOK AT THIS!!! narrator_voice_gen = narrator_voice_gen or _narrator_voice_gen rvcnarrator_voice_gen = rvcnarrator_voice_gen or _rvcnarrator_voice_gen + rvcnarrator_pitch = rvcnarrator_pitch or _rvcnarrator_pitch text_not_inside = text_not_inside or _text_not_inside language = language or _language output_file_name = output_file_name or _output_file_name @@ -1327,9 +1286,11 @@ async def apifunction_generate_tts_standard( "text_filtering": text_filtering, "character_voice_gen": character_voice_gen, "rvccharacter_voice_gen": rvccharacter_voice_gen, + "rvccharacter_pitch": rvccharacter_pitch, "narrator_enabled": narrator_enabled, "narrator_voice_gen": narrator_voice_gen, "rvcnarrator_voice_gen": rvcnarrator_voice_gen, + "rvcnarrator_pitch": rvcnarrator_pitch, "text_not_inside": text_not_inside, "language": language, "output_file_name": output_file_name, @@ -1363,9 +1324,11 @@ async def apifunction_generate_tts_standard( f"[{branding}Debug] text_filtering : {text_filtering}", f"[{branding}Debug] character_voice_gen : {character_voice_gen}", f"[{branding}Debug] rvccharacter_voice_gen : {rvccharacter_voice_gen}", + f"[{branding}Debug] rvccharacter_pitch : {rvccharacter_pitch}", f"[{branding}Debug] narrator_enabled : {narrator_enabled}", f"[{branding}Debug] narrator_voice_gen : {narrator_voice_gen}", f"[{branding}Debug] rvcnarrator_voice_gen : {rvcnarrator_voice_gen}", + f"[{branding}Debug] rvcnarrator_pitch : {rvcnarrator_pitch}", f"[{branding}Debug] text_not_inside : {text_not_inside}", f"[{branding}Debug] language : {language}", f"[{branding}Debug] output_file_name : {output_file_name}", @@ -1425,14 +1388,14 @@ async def apifunction_generate_tts_standard( audio_path = output_file_str if rvc_settings["rvc_enabled"]: if part_type == 'character': - process_rvc_narrator(part_type, rvccharacter_voice_gen, rvc_settings["rvc_char_model_file"], output_file, infer_pipeline) + process_rvc_narrator(part_type, rvccharacter_voice_gen, rvccharacter_pitch, rvc_settings["rvc_char_model_file"], output_file, infer_pipeline) elif part_type == 'narrator': - process_rvc_narrator(part_type, rvcnarrator_voice_gen, rvc_settings["rvc_narr_model_file"], output_file, infer_pipeline) + process_rvc_narrator(part_type, rvcnarrator_voice_gen, rvcnarrator_pitch, rvc_settings["rvc_narr_model_file"], output_file, infer_pipeline) else: if text_not_inside == 'character': - process_rvc_narrator('character', rvccharacter_voice_gen, rvc_settings["rvc_char_model_file"], output_file, infer_pipeline) + process_rvc_narrator('character', rvccharacter_voice_gen, rvccharacter_pitch, rvc_settings["rvc_char_model_file"], output_file, infer_pipeline) elif text_not_inside == 'narrator': - process_rvc_narrator('narrator', rvcnarrator_voice_gen, rvc_settings["rvc_narr_model_file"], output_file, infer_pipeline) + process_rvc_narrator('narrator', rvcnarrator_voice_gen, rvcnarrator_pitch, rvc_settings["rvc_narr_model_file"], output_file, infer_pipeline) print(f"[{branding}Debug] Appending audio path to list") if debug_tts else None audio_files_all_paragraphs.append(audio_path) # Combine audio files across paragraphs @@ -1520,7 +1483,7 @@ async def apifunction_generate_tts_standard( print(f"[{branding}Debug] send to rvc") if debug_tts else None rvccharacter_voice_gen = this_dir / "models" / "rvc_voices" / rvccharacter_voice_gen pth_path = rvccharacter_voice_gen if rvccharacter_voice_gen else rvc_settings["rvc_char_model_file"] - run_rvc(output_file_path, pth_path, infer_pipeline) + run_rvc(output_file_path, pth_path, rvccharacter_pitch, infer_pipeline) # Transcode audio if necessary model_audio_format = str(model_engine.audio_format).lower() output_audio_format = str(params["transcode_audio_format"]).lower()