Add preview button to voice mixer

This commit is contained in:
Deniz Şafak
2025-05-04 15:10:08 +03:00
parent 15f1eb7f1e
commit 67b35d1dfb
3 changed files with 50 additions and 9 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
- Added `Insert chapter marker` button in text editor to insert chapter markers at the current cursor position.
- Added `Preview` button in voice mixer to preview the voice mix with the selected settings.
- Fixed `f-string: unmatched '['` error in Voice preview, mentioned in #14
- Fixed the content before first chapter not being included in the output (added handling for initial content).
- Fixed the issue with the content before first chapter not being included in the output.
- Fixed m4b chapter generation opens CMD window in Windows.
+6 -7
View File
@@ -290,8 +290,8 @@ class InputBox(QLabel):
)
win.selected_book_path = file_path
win.open_book_file(
file_path
) # This will handle the dialog and setting file info
file_path # This will handle the dialog and setting file info
)
event.acceptProposedAction()
else:
self.set_error("Please drop a .txt, .epub, or .pdf file.")
@@ -328,7 +328,7 @@ class TextboxDialog(QDialog):
self.setWindowFlags(
Qt.Window | Qt.WindowCloseButtonHint | Qt.WindowMaximizeButtonHint
)
self.resize(600, 400)
self.resize(700, 500)
layout = QVBoxLayout(self)
@@ -452,7 +452,7 @@ class TextboxDialog(QDialog):
def insert_chapter_marker(self):
# Insert a fixed chapter marker without prompting
cursor = self.text_edit.textCursor()
cursor.insertText("<<CHAPTER_MARKER:Chapter Title>>")
cursor.insertText("<<CHAPTER_MARKER:Title>>")
self.text_edit.setTextCursor(cursor)
self.update_char_count()
@@ -1500,14 +1500,14 @@ class abogen(QWidget):
# Build voice formula string
components = [f"{name}*{weight}" for name, weight in self.mixed_voice_state]
voice = " + ".join(filter(None, components))
# determine language: use profile setting if available, else first voice code
# determine language: use profile setting, else explicit mixer selection, else fallback to first voice code
if self.selected_profile_name:
from voice_profiles import load_profiles
entry = load_profiles().get(self.selected_profile_name, {})
lang = entry.get("language")
else:
lang = None
lang = self.selected_lang
if not lang and self.mixed_voice_state:
lang = (
self.mixed_voice_state[0][0][0]
@@ -2138,4 +2138,3 @@ class abogen(QWidget):
"Setting Saved",
f"Maximum words per subtitle set to {value}.",
)
+42 -1
View File
@@ -47,7 +47,7 @@ VOICE_MIXER_WIDTH = 100
SLIDER_WIDTH = 32
MIN_WINDOW_WIDTH = 600
MIN_WINDOW_HEIGHT = 400
INITIAL_WINDOW_WIDTH = 1000
INITIAL_WINDOW_WIDTH = 1200
INITIAL_WINDOW_HEIGHT = 500
# Language options for the language selector loaded from constants
@@ -413,6 +413,11 @@ class VoiceFormulaDialog(QDialog):
self.language_combo.setCurrentIndex(idx)
self.language_combo.currentIndexChanged.connect(self.mark_profile_modified)
header_row.addWidget(self.language_combo)
# Preview current voice mix using main window's preview
self.btn_preview_mix = QPushButton("Preview", self)
self.btn_preview_mix.setToolTip("Preview current voice mix")
self.btn_preview_mix.clicked.connect(self.preview_current_mix)
header_row.addWidget(self.btn_preview_mix)
mixer_layout.addLayout(header_row)
# Error message
@@ -708,6 +713,8 @@ class VoiceFormulaDialog(QDialog):
]
total = sum(w for _, w in selected)
# disable Preview if no voices selected
self.btn_preview_mix.setEnabled(total > 0)
if total > 0:
self.error_label.hide()
@@ -1338,3 +1345,37 @@ class VoiceFormulaDialog(QDialog):
else:
item.setBackground(QColor("white"))
self.update_profile_save_buttons()
def preview_current_mix(self):
# Disable preview until playback completes
self.btn_preview_mix.setEnabled(False)
self.btn_preview_mix.setText("Loading...")
parent = self.parent()
if parent and hasattr(parent, "preview_voice"):
# Apply mixed voices and selected language
parent.mixed_voice_state = self.get_selected_voices()
parent.selected_profile_name = None
lang = self.language_combo.currentData()
parent.selected_lang = lang
parent.subtitle_combo.setEnabled(
lang in SUPPORTED_LANGUAGES_FOR_SUBTITLE_GENERATION
)
# Reset start flag and trigger preview
self._started = False
parent.preview_voice()
# Poll preview_playing: wait for start then end
self._preview_poll_timer = QTimer(self)
self._preview_poll_timer.timeout.connect(self._check_preview_done)
self._preview_poll_timer.start(200)
def _check_preview_done(self):
parent = self.parent()
if parent and hasattr(parent, "preview_playing"):
# Mark when playback starts
if parent.preview_playing:
self._started = True
# Once started and then stopped, re-enable
elif getattr(self, "_started", False):
self.btn_preview_mix.setEnabled(True)
self.btn_preview_mix.setText("Preview")
self._preview_poll_timer.stop()