mirror of
https://github.com/denizsafak/abogen.git
synced 2026-09-20 11:40:57 +02:00
refactor: run_tts_segment_loop also accepts SynthParams
- Reduces from 14 params to 5 unique params + SynthParams - synthesize_text now passes params through cleanly - PyQt intro/outro direct calls updated
This commit is contained in:
@@ -55,44 +55,29 @@ class SegmentInfo:
|
|||||||
def run_tts_segment_loop(
|
def run_tts_segment_loop(
|
||||||
*,
|
*,
|
||||||
text: str,
|
text: str,
|
||||||
|
params: SynthParams,
|
||||||
backend: Any,
|
backend: Any,
|
||||||
voice: Any,
|
voice: Any,
|
||||||
speed: float,
|
speed: float,
|
||||||
split_pattern: str,
|
split_pattern: str,
|
||||||
stats: SegmentStats,
|
|
||||||
check_cancel: CancelChecker,
|
|
||||||
on_progress: Callable[[int, str], None],
|
|
||||||
chapter_sink: Optional[AudioSink] = None,
|
chapter_sink: Optional[AudioSink] = None,
|
||||||
audio_sink: Optional[AudioSink] = None,
|
|
||||||
preview_callback: Optional[Callable[[str], None]] = None,
|
preview_callback: Optional[Callable[[str], None]] = None,
|
||||||
on_segment: Optional[Callable[[SegmentInfo], None]] = None,
|
on_segment: Optional[Callable[[SegmentInfo], None]] = None,
|
||||||
subtitle_mode: str = "Disabled",
|
|
||||||
max_subtitle_words: int = 50,
|
|
||||||
lang_code: str = "a",
|
|
||||||
use_spacy_segmentation: bool = False,
|
|
||||||
) -> tuple[int, list]:
|
) -> tuple[int, list]:
|
||||||
"""Run the core TTS segment iteration loop.
|
"""Run the core TTS segment iteration loop.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: Normalized text to synthesize.
|
text: Normalized text to synthesize.
|
||||||
|
params: Common synthesis parameters (stats, callbacks, sinks, etc.).
|
||||||
backend: TTS pipeline instance (Kokoro or Supertonic).
|
backend: TTS pipeline instance (Kokoro or Supertonic).
|
||||||
voice: Voice name/id for the backend.
|
voice: Voice name/id for the backend.
|
||||||
speed: Speech speed multiplier.
|
speed: Speech speed multiplier.
|
||||||
split_pattern: Regex pattern used by the TTS engine for sentence splitting.
|
split_pattern: Regex pattern used by the TTS engine for sentence splitting.
|
||||||
stats: Running character/timing stats (mutated in place).
|
|
||||||
check_cancel: Called each segment; if it returns True, iteration stops.
|
|
||||||
on_progress: Called with (percent, etr_str) after each segment.
|
|
||||||
chapter_sink: Optional audio sink for the current chapter.
|
|
||||||
audio_sink: Optional audio sink for the merged output.
|
|
||||||
preview_callback: Called with a short preview string per segment.
|
preview_callback: Called with a short preview string per segment.
|
||||||
on_segment: Called with a SegmentInfo for each segment *before*
|
on_segment: Called with a SegmentInfo for each segment *before*
|
||||||
audio is written. Useful for callers that need per-segment
|
audio is written. Useful for callers that need per-segment
|
||||||
subtitle processing (e.g. PyQt dual-writer pattern).
|
subtitle processing (e.g. PyQt dual-writer pattern).
|
||||||
When provided, the default subtitle accumulation is skipped.
|
When provided, the default subtitle accumulation is skipped.
|
||||||
subtitle_mode: Subtitle mode string (e.g. "Disabled", "Sentence").
|
|
||||||
max_subtitle_words: Max words per subtitle entry.
|
|
||||||
lang_code: Language code for subtitle processing.
|
|
||||||
use_spacy_segmentation: Whether spaCy sentence boundaries are active.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple of (segment_count, accumulated_subtitle_tokens).
|
Tuple of (segment_count, accumulated_subtitle_tokens).
|
||||||
@@ -108,26 +93,26 @@ def run_tts_segment_loop(
|
|||||||
voice=voice,
|
voice=voice,
|
||||||
speed=speed,
|
speed=speed,
|
||||||
split_pattern=split_pattern,
|
split_pattern=split_pattern,
|
||||||
current_time=stats.current_time,
|
current_time=params.stats.current_time,
|
||||||
):
|
):
|
||||||
if check_cancel():
|
if params.check_cancel():
|
||||||
break
|
break
|
||||||
|
|
||||||
local_segments += 1
|
local_segments += 1
|
||||||
stats.processed_chars += len(seg.graphemes)
|
params.stats.processed_chars += len(seg.graphemes)
|
||||||
|
|
||||||
# Progress
|
# Progress
|
||||||
if stats.total_characters:
|
if params.stats.total_characters:
|
||||||
percent = min(int(stats.processed_chars / stats.total_characters * 100), 99)
|
percent = min(int(params.stats.processed_chars / params.stats.total_characters * 100), 99)
|
||||||
else:
|
else:
|
||||||
percent = 0 if stats.processed_chars == 0 else 99
|
percent = 0 if params.stats.processed_chars == 0 else 99
|
||||||
|
|
||||||
etr_str = calc_etr_str(
|
etr_str = calc_etr_str(
|
||||||
time.time() - stats.etr_start_time,
|
time.time() - params.stats.etr_start_time,
|
||||||
stats.processed_chars,
|
params.stats.processed_chars,
|
||||||
stats.total_characters,
|
params.stats.total_characters,
|
||||||
)
|
)
|
||||||
on_progress(percent, etr_str)
|
params.on_progress(percent, etr_str)
|
||||||
|
|
||||||
# Preview / log
|
# Preview / log
|
||||||
if preview_callback:
|
if preview_callback:
|
||||||
@@ -140,23 +125,23 @@ def run_tts_segment_loop(
|
|||||||
audio=seg.audio,
|
audio=seg.audio,
|
||||||
tokens=list(seg.tokens) if seg.tokens else [],
|
tokens=list(seg.tokens) if seg.tokens else [],
|
||||||
duration=seg.duration,
|
duration=seg.duration,
|
||||||
chunk_start=getattr(seg, "chunk_start", stats.current_time),
|
chunk_start=getattr(seg, "chunk_start", params.stats.current_time),
|
||||||
)
|
)
|
||||||
on_segment(info)
|
on_segment(info)
|
||||||
|
|
||||||
# Write audio
|
# Write audio
|
||||||
if chapter_sink:
|
if chapter_sink:
|
||||||
chapter_sink.write(seg.audio)
|
chapter_sink.write(seg.audio)
|
||||||
if audio_sink:
|
if params.audio_sink:
|
||||||
audio_sink.write(seg.audio)
|
params.audio_sink.write(seg.audio)
|
||||||
|
|
||||||
# Accumulate subtitle tokens (default path; skipped if on_segment handles it)
|
# Accumulate subtitle tokens (default path; skipped if on_segment handles it)
|
||||||
if not on_segment and subtitle_mode != "Disabled" and seg.tokens:
|
if not on_segment and params.subtitle_mode != "Disabled" and seg.tokens:
|
||||||
accumulated_tokens.extend(seg.tokens)
|
accumulated_tokens.extend(seg.tokens)
|
||||||
|
|
||||||
# Update timing
|
# Update timing
|
||||||
if audio_sink:
|
if params.audio_sink:
|
||||||
stats.current_time += seg.duration
|
params.stats.current_time += seg.duration
|
||||||
|
|
||||||
return local_segments, accumulated_tokens
|
return local_segments, accumulated_tokens
|
||||||
|
|
||||||
@@ -229,19 +214,12 @@ def synthesize_text(
|
|||||||
normalized = params.tts_context.normalize(text)
|
normalized = params.tts_context.normalize(text)
|
||||||
return run_tts_segment_loop(
|
return run_tts_segment_loop(
|
||||||
text=normalized,
|
text=normalized,
|
||||||
|
params=params,
|
||||||
backend=backend,
|
backend=backend,
|
||||||
voice=voice,
|
voice=voice,
|
||||||
speed=speed,
|
speed=speed,
|
||||||
split_pattern=split_pattern_override or params.tts_context.split_pattern,
|
split_pattern=split_pattern_override or params.tts_context.split_pattern,
|
||||||
stats=params.stats,
|
|
||||||
check_cancel=params.check_cancel,
|
|
||||||
on_progress=params.on_progress,
|
|
||||||
chapter_sink=chapter_sink,
|
chapter_sink=chapter_sink,
|
||||||
audio_sink=params.audio_sink,
|
|
||||||
preview_callback=preview_callback,
|
preview_callback=preview_callback,
|
||||||
on_segment=on_segment,
|
on_segment=on_segment,
|
||||||
subtitle_mode=params.subtitle_mode,
|
|
||||||
max_subtitle_words=params.max_subtitle_words,
|
|
||||||
lang_code=params.lang_code,
|
|
||||||
use_spacy_segmentation=params.use_spacy_segmentation,
|
|
||||||
)
|
)
|
||||||
|
|||||||
+16
-10
@@ -773,17 +773,20 @@ class ConversionThread(QThread):
|
|||||||
etr_start_time=self.etr_start_time,
|
etr_start_time=self.etr_start_time,
|
||||||
total_characters=self.total_char_count,
|
total_characters=self.total_char_count,
|
||||||
)
|
)
|
||||||
|
intro_synth = SynthParams(
|
||||||
|
tts_context=self._tts_context,
|
||||||
|
stats=intro_stats,
|
||||||
|
check_cancel=lambda: self.cancel_requested,
|
||||||
|
on_progress=lambda pct, etr: self.progress_updated.emit(pct, etr),
|
||||||
|
audio_sink=merged_sink,
|
||||||
|
)
|
||||||
run_tts_segment_loop(
|
run_tts_segment_loop(
|
||||||
text=intro_spec.text,
|
text=intro_spec.text,
|
||||||
|
params=intro_synth,
|
||||||
backend=self.backend,
|
backend=self.backend,
|
||||||
voice=loaded_intro_voice,
|
voice=loaded_intro_voice,
|
||||||
speed=self.speed,
|
speed=self.speed,
|
||||||
split_pattern=self.split_pattern,
|
split_pattern=self.split_pattern,
|
||||||
stats=intro_stats,
|
|
||||||
check_cancel=lambda: self.cancel_requested,
|
|
||||||
on_progress=lambda pct, etr: self.progress_updated.emit(pct, etr),
|
|
||||||
chapter_sink=None,
|
|
||||||
audio_sink=merged_sink,
|
|
||||||
)
|
)
|
||||||
self.processed_char_count = intro_stats.processed_chars
|
self.processed_char_count = intro_stats.processed_chars
|
||||||
current_time = intro_stats.current_time
|
current_time = intro_stats.current_time
|
||||||
@@ -1106,17 +1109,20 @@ class ConversionThread(QThread):
|
|||||||
etr_start_time=self.etr_start_time,
|
etr_start_time=self.etr_start_time,
|
||||||
total_characters=self.total_char_count,
|
total_characters=self.total_char_count,
|
||||||
)
|
)
|
||||||
|
outro_synth = SynthParams(
|
||||||
|
tts_context=self._tts_context,
|
||||||
|
stats=outro_stats,
|
||||||
|
check_cancel=lambda: self.cancel_requested,
|
||||||
|
on_progress=lambda pct, etr: self.progress_updated.emit(pct, etr),
|
||||||
|
audio_sink=merged_sink,
|
||||||
|
)
|
||||||
run_tts_segment_loop(
|
run_tts_segment_loop(
|
||||||
text=outro_spec.text,
|
text=outro_spec.text,
|
||||||
|
params=outro_synth,
|
||||||
backend=self.backend,
|
backend=self.backend,
|
||||||
voice=loaded_outro_voice,
|
voice=loaded_outro_voice,
|
||||||
speed=self.speed,
|
speed=self.speed,
|
||||||
split_pattern=self.split_pattern,
|
split_pattern=self.split_pattern,
|
||||||
stats=outro_stats,
|
|
||||||
check_cancel=lambda: self.cancel_requested,
|
|
||||||
on_progress=lambda pct, etr: self.progress_updated.emit(pct, etr),
|
|
||||||
chapter_sink=None,
|
|
||||||
audio_sink=merged_sink,
|
|
||||||
)
|
)
|
||||||
self.processed_char_count = outro_stats.processed_chars
|
self.processed_char_count = outro_stats.processed_chars
|
||||||
current_time = outro_stats.current_time
|
current_time = outro_stats.current_time
|
||||||
|
|||||||
Reference in New Issue
Block a user