diff --git a/README.md b/README.md index f756065..95b267e 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,9 @@ Streaming TTS can produce clicks, pops, and artifacts at chunk boundaries. This Chunks are blended using a Hann window crossfade to eliminate boundary discontinuities: ```python -MIN_BLEND_SAMPLES = 512 # ~21ms at 24kHz - -# blend_samples is at least MIN_BLEND_SAMPLES, even if overlap_samples is smaller -blend_samples = max(overlap_samples, MIN_BLEND_SAMPLES) +# ~21ms at 24kHz, matches RMS check window +# Lower values may cause clicks, set to 0 to disable +DEFAULT_BLEND_SAMPLES = 512 # Hann crossfade fade_out = 0.5 * (1 + np.cos(np.pi * t)) @@ -161,7 +160,7 @@ for chunk, sr in model.stream_generate_voice_clone( |-----------|---------|-------------| | `emit_every_frames` | 8 | Emit audio every N frames | | `decode_window_frames` | 80 | Decoder context window | -| `overlap_samples` | 512 | Crossfade overlap between chunks | +| `overlap_samples` | 512 | Crossfade overlap between chunks (0 to disable) | | `max_frames` | 10000 | Maximum codec frames to generate | | `first_chunk_emit_every` | 0 | Phase 1 emit interval (0 = disabled) | | `first_chunk_decode_window` | 48 | Phase 1 decode window | diff --git a/qwen_tts/core/models/modeling_qwen3_tts.py b/qwen_tts/core/models/modeling_qwen3_tts.py index 895f69f..9ef898e 100644 --- a/qwen_tts/core/models/modeling_qwen3_tts.py +++ b/qwen_tts/core/models/modeling_qwen3_tts.py @@ -103,9 +103,10 @@ def _crossfade(prev_tail: np.ndarray, new_head: np.ndarray) -> np.ndarray: return prev_tail[:n] * fade_out + new_head[:n] * fade_in -# Minimum samples for boundary blending (prevents clicks even with overlap_samples=0) +# Default blend samples for boundary blending # ~21ms at 24kHz, matches RMS check window for better coverage -MIN_BLEND_SAMPLES = 512 +# Lower values may cause clicks, set to 0 to disable +DEFAULT_BLEND_SAMPLES = 512 def _add_ref_code_context( @@ -2814,7 +2815,7 @@ class Qwen3TTSForConditionalGeneration(Qwen3TTSPreTrainedModel, GenerationMixin) # Crossfade with previous chunk tail for smooth transition # Always blend boundaries to prevent clicks from sliding window re-decode artifacts - blend_samples = max(overlap_samples, MIN_BLEND_SAMPLES) + blend_samples = overlap_samples if decoded_tail is not None: ov = min(blend_samples, len(decoded_tail), len(chunk)) if ov > 0: @@ -2823,7 +2824,7 @@ class Qwen3TTSForConditionalGeneration(Qwen3TTSPreTrainedModel, GenerationMixin) # Apply Hann fade-in to very first chunk to avoid pop at audio start # Always apply fade-in on first chunk to prevent pop - blend_samples = max(overlap_samples, MIN_BLEND_SAMPLES) + blend_samples = overlap_samples if decoded_tail is None: fade_len = min(blend_samples, len(chunk)) if fade_len > 0: @@ -2867,7 +2868,7 @@ class Qwen3TTSForConditionalGeneration(Qwen3TTSPreTrainedModel, GenerationMixin) # Crossfade with previous tail # Always blend flush boundary - blend_samples = max(overlap_samples, MIN_BLEND_SAMPLES) + blend_samples = overlap_samples if decoded_tail is not None and len(wav) > 0: ov = min(blend_samples, len(decoded_tail), len(wav)) if ov > 0: