added voice formulas for mixed text

This commit is contained in:
Juraj Borza
2025-04-28 09:19:48 +02:00
parent 572a3c7285
commit 44e555c83e
3 changed files with 60 additions and 3 deletions
+5 -1
View File
@@ -9,6 +9,7 @@ from PyQt5.QtWidgets import QCheckBox, QVBoxLayout, QDialog, QLabel, QDialogButt
import soundfile as sf import soundfile as sf
from utils import clean_text from utils import clean_text
from constants import PROGRAM_NAME, LANGUAGE_DESCRIPTIONS, SAMPLE_VOICE_TEXTS from constants import PROGRAM_NAME, LANGUAGE_DESCRIPTIONS, SAMPLE_VOICE_TEXTS
from voice_formulas import get_new_voice
def get_sample_voice_text(lang_code): def get_sample_voice_text(lang_code):
@@ -346,9 +347,12 @@ class ConversionThread(QThread):
# Set split_pattern to \n+ which will split on one or more newlines # Set split_pattern to \n+ which will split on one or more newlines
split_pattern = r"\n+" split_pattern = r"\n+"
loaded_voice = get_new_voice(tts, self.voice, self.use_gpu)
for result in tts( for result in tts(
chapter_text, chapter_text,
voice=self.voice, voice=loaded_voice,
speed=self.speed, speed=self.speed,
split_pattern=split_pattern, split_pattern=split_pattern,
): ):
+11 -1
View File
@@ -568,6 +568,13 @@ class abogen(QWidget):
) )
voice_row.addWidget(self.voice_combo) voice_row.addWidget(self.voice_combo)
# voice formula - text box for now, add a dialog later
self.voice_formula = QTextEdit(self)
self.voice_formula.setAcceptRichText(False)
self.voice_formula.setPlaceholderText("Enter voice formula here...")
self.voice_formula.setText('0.242 * am_michael + 0.758 * bf_isabella')
voice_row.addWidget(self.voice_formula)
# Play/Stop icons # Play/Stop icons
def make_icon(color, shape): def make_icon(color, shape):
pix = QPixmap(20, 20) pix = QPixmap(20, 20)
@@ -1038,11 +1045,14 @@ class abogen(QWidget):
else self.subtitle_mode else self.subtitle_mode
) )
voice_formula = self.voice_formula.toPlainText()
self.conversion_thread = ConversionThread( self.conversion_thread = ConversionThread(
self.selected_file, self.selected_file,
self.selected_lang, self.selected_lang,
speed, speed,
self.selected_voice, #self.selected_voice,
voice_formula,
self.save_option, self.save_option,
self.selected_output_folder, self.selected_output_folder,
subtitle_mode=actual_subtitle_mode, subtitle_mode=actual_subtitle_mode,
+43
View File
@@ -0,0 +1,43 @@
from constants import VOICES_INTERNAL
# Calls parsing and loads the voice to gpu or cpu
def get_new_voice(pipeline, formula, use_gpu):
try:
weighted_voice = parse_voice_formula(pipeline, formula)
device = "cuda" if use_gpu else "cpu"
return weighted_voice.to(device)
except Exception as e:
raise ValueError(f"Failed to create voice: {str(e)}")
# Parse the formula and get the combined voice tensor
def parse_voice_formula(pipeline, formula):
"""Parse the voice formula string and return the combined voice tensor."""
if not formula.strip():
raise ValueError("Empty voice formula")
# Initialize the weighted sum
weighted_sum = None
# Split the formula into terms
terms = formula.split('+')
for term in terms:
# Parse each term (format: "0.333 * voice_name")
weight, voice_name = term.strip().split('*')
weight = float(weight.strip())
voice_name = voice_name.strip()
# Get the voice tensor
# use VOICES_INTERNAL
if voice_name not in VOICES_INTERNAL:
raise ValueError(f"Unknown voice: {voice_name}")
voice_tensor = pipeline.load_single_voice(voice_name)
# Add to weighted sum
if weighted_sum is None:
weighted_sum = weight * voice_tensor
else:
weighted_sum += weight * voice_tensor
return weighted_sum