add speed parameter
This commit is contained in:
25
py/README.md
25
py/README.md
@@ -4,6 +4,8 @@ This guide provides examples for running TTS inference using `example_onnx.py`.
|
||||
|
||||
## 📰 Update News
|
||||
|
||||
**2025.11.19** - Added `--speed` parameter to control speech synthesis speed. Adjust the speed factor to make speech faster or slower while maintaining natural quality.
|
||||
|
||||
**2025.11.19** - Added automatic text chunking for long-form inference. Long texts are split into chunks and synthesized with natural pauses.
|
||||
|
||||
## Installation
|
||||
@@ -85,6 +87,28 @@ This will:
|
||||
|
||||
**Note**: When using batch mode (`--batch`), automatic text chunking is disabled. Use non-batch mode for long-form text synthesis.
|
||||
|
||||
### Example 5: Adjusting Speech Speed
|
||||
Control the speed of speech synthesis:
|
||||
```bash
|
||||
# Faster speech (speed > 1.0)
|
||||
uv run example_onnx.py \
|
||||
--voice-style assets/voice_styles/F2.json \
|
||||
--text "This text will be synthesized at a faster pace." \
|
||||
--speed 1.2
|
||||
|
||||
# Slower speech (speed < 1.0)
|
||||
uv run example_onnx.py \
|
||||
--voice-style assets/voice_styles/M2.json \
|
||||
--text "This text will be synthesized at a slower, more deliberate pace." \
|
||||
--speed 0.9
|
||||
```
|
||||
|
||||
This will:
|
||||
- Use `--speed 1.2` to generate faster speech
|
||||
- Use `--speed 0.9` to generate slower speech
|
||||
- Default speed is 1.05 if not specified
|
||||
- Recommended speed range is between 0.9 and 1.5 for natural-sounding results
|
||||
|
||||
## Available Arguments
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
@@ -92,6 +116,7 @@ This will:
|
||||
| `--use-gpu` | flag | False | Use GPU for inference (with CPU fallback) |
|
||||
| `--onnx-dir` | str | `assets/onnx` | Path to ONNX model directory |
|
||||
| `--total-step` | int | 5 | Number of denoising steps (higher = better quality, slower) |
|
||||
| `--speed` | float | 1.05 | Speech speed factor (higher = faster, lower = slower) |
|
||||
| `--n-test` | int | 4 | Number of times to generate each sample |
|
||||
| `--voice-style` | str+ | `assets/voice_styles/M1.json` | Voice style file path(s) |
|
||||
| `--text` | str+ | (long default text) | Text(s) to synthesize |
|
||||
|
||||
@@ -26,6 +26,12 @@ def parse_args():
|
||||
parser.add_argument(
|
||||
"--total-step", type=int, default=5, help="Number of denoising steps"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--speed",
|
||||
type=float,
|
||||
default=1.05,
|
||||
help="Speech speed (default: 1.05, higher = faster)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--n-test", type=int, default=4, help="Number of times to generate"
|
||||
)
|
||||
@@ -62,6 +68,7 @@ print("=== TTS Inference with ONNX Runtime (Python) ===\n")
|
||||
# --- 1. Parse arguments --- #
|
||||
args = parse_args()
|
||||
total_step = args.total_step
|
||||
speed = args.speed
|
||||
n_test = args.n_test
|
||||
save_dir = args.save_dir
|
||||
voice_style_paths = args.voice_style
|
||||
@@ -84,9 +91,9 @@ for n in range(n_test):
|
||||
print(f"\n[{n+1}/{n_test}] Starting synthesis...")
|
||||
with timer("Generating speech from text"):
|
||||
if batch:
|
||||
wav, duration = text_to_speech.batch(text_list, style, total_step)
|
||||
wav, duration = text_to_speech.batch(text_list, style, total_step, speed)
|
||||
else:
|
||||
wav, duration = text_to_speech(text_list[0], style, total_step)
|
||||
wav, duration = text_to_speech(text_list[0], style, total_step, speed)
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
for b in range(bsz):
|
||||
|
||||
16
py/helper.py
16
py/helper.py
@@ -86,7 +86,7 @@ class TextToSpeech:
|
||||
return noisy_latent, latent_mask
|
||||
|
||||
def _infer(
|
||||
self, text_list: list[str], style: Style, total_step: int
|
||||
self, text_list: list[str], style: Style, total_step: int, speed: float = 1.05
|
||||
) -> tuple[np.ndarray, np.ndarray]:
|
||||
assert (
|
||||
len(text_list) == style.ttl.shape[0]
|
||||
@@ -96,6 +96,7 @@ class TextToSpeech:
|
||||
dur_onnx, *_ = self.dp_ort.run(
|
||||
None, {"text_ids": text_ids, "style_dp": style.dp, "text_mask": text_mask}
|
||||
)
|
||||
dur_onnx = dur_onnx / speed
|
||||
text_emb_onnx, *_ = self.text_enc_ort.run(
|
||||
None,
|
||||
{"text_ids": text_ids, "style_ttl": style.ttl, "text_mask": text_mask},
|
||||
@@ -120,7 +121,12 @@ class TextToSpeech:
|
||||
return wav, dur_onnx
|
||||
|
||||
def __call__(
|
||||
self, text: str, style: Style, total_step: int, silence_duration: float = 0.3
|
||||
self,
|
||||
text: str,
|
||||
style: Style,
|
||||
total_step: int,
|
||||
speed: float = 1.05,
|
||||
silence_duration: float = 0.3,
|
||||
) -> tuple[np.ndarray, np.ndarray]:
|
||||
assert (
|
||||
style.ttl.shape[0] == 1
|
||||
@@ -129,7 +135,7 @@ class TextToSpeech:
|
||||
wav_cat = None
|
||||
dur_cat = None
|
||||
for text in text_list:
|
||||
wav, dur_onnx = self._infer([text], style, total_step)
|
||||
wav, dur_onnx = self._infer([text], style, total_step, speed)
|
||||
if wav_cat is None:
|
||||
wav_cat = wav
|
||||
dur_cat = dur_onnx
|
||||
@@ -142,9 +148,9 @@ class TextToSpeech:
|
||||
return wav_cat, dur_cat
|
||||
|
||||
def batch(
|
||||
self, text_list: list[str], style: Style, total_step: int
|
||||
self, text_list: list[str], style: Style, total_step: int, speed: float = 1.05
|
||||
) -> tuple[np.ndarray, np.ndarray]:
|
||||
return self._infer(text_list, style, total_step)
|
||||
return self._infer(text_list, style, total_step, speed)
|
||||
|
||||
|
||||
def length_to_mask(lengths: np.ndarray, max_len: Optional[int] = None) -> np.ndarray:
|
||||
|
||||
Reference in New Issue
Block a user