cli, facade: rename --ref-audio to --ref-wav, align with omnivoice convention
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ set PATH=%~dp0..\build\Release;%PATH%
|
||||
qwen-tts.exe ^
|
||||
--model ..\models\qwen-talker-1.7b-base-Q8_0.gguf ^
|
||||
--codec ..\models\qwen-tokenizer-12hz-Q8_0.gguf ^
|
||||
--ref-audio freeman.wav ^
|
||||
--ref-wav freeman.wav ^
|
||||
--ref-text freeman.txt ^
|
||||
--lang English ^
|
||||
-o clone.wav < prompt.txt
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ set -eu
|
||||
../build/qwen-tts \
|
||||
--model ../models/qwen-talker-1.7b-base-Q8_0.gguf \
|
||||
--codec ../models/qwen-tokenizer-12hz-Q8_0.gguf \
|
||||
--ref-audio freeman.wav \
|
||||
--ref-wav freeman.wav \
|
||||
--ref-text freeman.txt \
|
||||
--lang English \
|
||||
-o clone.wav < prompt.txt
|
||||
|
||||
@@ -288,8 +288,7 @@ bool pipeline_tts_synthesize(PipelineTTS * pt,
|
||||
const float * ref_spk_emb_ptr = NULL;
|
||||
if (has_ref_audio) {
|
||||
if (!pt->has_speaker_encoder) {
|
||||
fprintf(stderr,
|
||||
"[Pipeline] FATAL: --ref-audio requires a model with a loaded speaker encoder (Base only)\n");
|
||||
fprintf(stderr, "[Pipeline] FATAL: --ref-wav requires a model with a loaded speaker encoder (Base only)\n");
|
||||
return false;
|
||||
}
|
||||
if (!speaker_encoder_extract(&pt->speaker_encoder, pt->sched, params.ref_audio_24k, params.ref_n_samples,
|
||||
@@ -313,13 +312,13 @@ bool pipeline_tts_synthesize(PipelineTTS * pt,
|
||||
int ref_codes_T = 0;
|
||||
if (!ref_text.empty()) {
|
||||
if (!has_ref_audio) {
|
||||
fprintf(stderr, "[Pipeline] FATAL: --ref-text requires --ref-audio\n");
|
||||
fprintf(stderr, "[Pipeline] FATAL: --ref-text requires --ref-wav\n");
|
||||
return false;
|
||||
}
|
||||
// The codec hop is 1920 samples at 24 kHz so n_samples must be
|
||||
// a multiple of 1920. Truncate to the nearest hop boundary.
|
||||
if (params.ref_n_samples < QWEN_TOKENIZER_HOP_LENGTH) {
|
||||
fprintf(stderr, "[Pipeline] FATAL: ref_audio too short for ICL (%d samples)\n", params.ref_n_samples);
|
||||
fprintf(stderr, "[Pipeline] FATAL: ref_wav too short for ICL (%d samples)\n", params.ref_n_samples);
|
||||
return false;
|
||||
}
|
||||
int aligned_T = (params.ref_n_samples / QWEN_TOKENIZER_HOP_LENGTH) * QWEN_TOKENIZER_HOP_LENGTH;
|
||||
@@ -347,7 +346,7 @@ bool pipeline_tts_synthesize(PipelineTTS * pt,
|
||||
debug_dump_2d(&d, "trailing-text-hidden", prompt.trailing_text_hidden.data(), prompt.T_trailing, prompt.hidden);
|
||||
debug_dump_1d(&d, "tts-pad-embed", prompt.tts_pad_embed.data(), prompt.hidden);
|
||||
|
||||
// Voice clone dumps : speaker-emb fires when ref_audio is set
|
||||
// Voice clone dumps : speaker-emb fires when ref_wav is set
|
||||
// (modes A and B), ref-codes fires only when ref_text is also set
|
||||
// (mode B ICL). Both are no-ops in base / tts / customvoice modes,
|
||||
// the dump files simply do not appear in those runs.
|
||||
|
||||
@@ -215,7 +215,7 @@ bool prompt_builder_build(const PipelineTTS * pt,
|
||||
// Mode B requires ref_spk_emb so the speaker slot is also filled.
|
||||
const bool icl = !ref_text.empty() && ref_codes != NULL && ref_codes_T > 0;
|
||||
if (icl && ref_spk_emb == NULL) {
|
||||
fprintf(stderr, "[Prompt] FATAL: ICL mode requires ref_spk_emb (no --ref-audio?)\n");
|
||||
fprintf(stderr, "[Prompt] FATAL: ICL mode requires ref_spk_emb (no --ref-wav?)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -328,17 +328,17 @@ enum qwen_status qwen_synthesize(struct qwen_context * q,
|
||||
return QWEN_STATUS_MODE_INVALID;
|
||||
}
|
||||
if (params->ref_audio_24k && mt != "base") {
|
||||
qt_set_error("--ref-audio is only valid for base models (loaded: %s)", mt.c_str());
|
||||
qt_set_error("--ref-wav is only valid for base models (loaded: %s)", mt.c_str());
|
||||
qwen_audio_free(out);
|
||||
return QWEN_STATUS_MODE_INVALID;
|
||||
}
|
||||
if (params->speaker && params->ref_audio_24k) {
|
||||
qt_set_error("--speaker and --ref-audio are mutually exclusive");
|
||||
qt_set_error("--speaker and --ref-wav are mutually exclusive");
|
||||
qwen_audio_free(out);
|
||||
return QWEN_STATUS_INVALID_PARAMS;
|
||||
}
|
||||
if (params->ref_text && !params->ref_audio_24k) {
|
||||
qt_set_error("--ref-text requires --ref-audio");
|
||||
qt_set_error("--ref-text requires --ref-wav");
|
||||
qwen_audio_free(out);
|
||||
return QWEN_STATUS_INVALID_PARAMS;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ Cote Python the speaker embedding is captured directly via
|
||||
model.extract_speaker_embedding, and the reference codec frames via
|
||||
model.speech_tokenizer.encode. Both intermediates land as speaker-emb.bin
|
||||
and ref-codes.bin and are compared against the C++ side dumps emitted
|
||||
by pipeline-tts.cpp when --ref-audio and --ref-text are set.
|
||||
by pipeline-tts.cpp when --ref-wav and --ref-text are set.
|
||||
|
||||
Dumps land in cpp/clone/ (C++) and python/clone/ (Python).
|
||||
"""
|
||||
@@ -271,10 +271,10 @@ def dump_mel_mag_python(ref_wav, dump_dir):
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--prompt", default="../examples/prompt.txt")
|
||||
ap.add_argument("--ref-audio", default=DEFAULT_REF_AUDIO,
|
||||
ap.add_argument("--ref-wav", default=DEFAULT_REF_AUDIO,
|
||||
help="reference WAV path for voice cloning")
|
||||
ap.add_argument("--ref-text-file", default=DEFAULT_REF_TEXT,
|
||||
help="path to a UTF-8 file with the transcript of ref-audio")
|
||||
help="path to a UTF-8 file with the transcript of ref-wav")
|
||||
ap.add_argument("--seed", type=int, default=42)
|
||||
ap.add_argument("--lang", default="english")
|
||||
ap.add_argument("--quant", default="F32",
|
||||
@@ -300,7 +300,7 @@ def main():
|
||||
with open(args.ref_text_file, "r", encoding="utf-8") as f:
|
||||
ref_text = f.read().strip()
|
||||
print(f"[Input] Prompt: {len(text)} chars: {text[:60]}{'...' if len(text) > 60 else ''}")
|
||||
print(f"[Input] RefAudio: {args.ref_audio}")
|
||||
print(f"[Input] RefAudio: {args.ref_wav}")
|
||||
print(f"[Input] RefText: {len(ref_text)} chars: {ref_text[:60]}{'...' if len(ref_text) > 60 else ''}")
|
||||
print(f"[Input] Lang: {args.lang} Seed: {args.seed} MaxNewTokens: {args.max_new_tokens}")
|
||||
print(f"[Input] Mode: greedy ICL")
|
||||
@@ -328,7 +328,7 @@ def main():
|
||||
|
||||
# Load reference WAV. Resample to 24 kHz if needed since both the speaker
|
||||
# encoder and the codec tokenizer expect 24 kHz mono input.
|
||||
ref_wav, ref_sr = sf.read(args.ref_audio, always_2d=False)
|
||||
ref_wav, ref_sr = sf.read(args.ref_wav, always_2d=False)
|
||||
if ref_wav.ndim > 1:
|
||||
ref_wav = ref_wav[:, 0]
|
||||
ref_wav = ref_wav.astype(np.float32)
|
||||
@@ -459,7 +459,7 @@ def main():
|
||||
"--codec", model_cdc,
|
||||
"--seed", str(args.seed),
|
||||
"--text", text,
|
||||
"--ref-audio", args.ref_audio,
|
||||
"--ref-wav", args.ref_wav,
|
||||
"--ref-text", ref_text,
|
||||
"--lang", args.lang,
|
||||
"--max-new", str(args.max_new_tokens),
|
||||
@@ -467,7 +467,7 @@ def main():
|
||||
"-o", args.out_cpp,
|
||||
"--greedy",
|
||||
]
|
||||
print(f"[GGML] Cmd: {' '.join(cmd[:6])} --text [...] --ref-audio {args.ref_audio} --ref-text [...] --lang {args.lang} --max-new {args.max_new_tokens} --dump {DUMP_CPP} -o {args.out_cpp} --greedy")
|
||||
print(f"[GGML] Cmd: {' '.join(cmd[:6])} --text [...] --ref-wav {args.ref_wav} --ref-text [...] --lang {args.lang} --max-new {args.max_new_tokens} --dump {DUMP_CPP} -o {args.out_cpp} --greedy")
|
||||
r = subprocess.run(cmd)
|
||||
if r.returncode != 0:
|
||||
sys.exit(r.returncode)
|
||||
|
||||
+9
-9
@@ -24,7 +24,7 @@
|
||||
#include <string>
|
||||
|
||||
// Tokenizer sample rate for the 12 Hz Qwen3-TTS codec : 24 kHz. Used
|
||||
// by audio_read_mono to resample the optional --ref-audio file before
|
||||
// by audio_read_mono to resample the optional --ref-wav file before
|
||||
// handing it to the facade. The output sample rate is reported by
|
||||
// qwen_audio.sample_rate after a successful synthesis.
|
||||
static const int QWEN_TTS_SAMPLE_RATE = 24000;
|
||||
@@ -44,12 +44,12 @@ static void print_usage(const char * prog) {
|
||||
" --instruct <s> Style instruction. Required for VoiceDesign, optional\n"
|
||||
" for CustomVoice. Rejected for Base.\n"
|
||||
" --speaker <name> Speaker name. Only valid for CustomVoice.\n"
|
||||
" --ref-audio <wav> Reference WAV path for voice clone (Base only). Mutually\n"
|
||||
" --ref-wav <wav> Reference WAV path for voice clone (Base only). Mutually\n"
|
||||
" exclusive with --speaker. Mode A (x_vector_only) extracts\n"
|
||||
" a speaker embedding via the ECAPA-TDNN encoder.\n"
|
||||
" --ref-text <path> Path to a UTF-8 text file containing the reference\n"
|
||||
" transcript for voice clone ICL mode (Base only, requires\n"
|
||||
" --ref-audio). Switches the prompt to ICL mode B where the\n"
|
||||
" --ref-wav). Switches the prompt to ICL mode B where the\n"
|
||||
" talker conditions on the reference codec codes.\n"
|
||||
" --max-new <n> Max new audio frames (default: 2048)\n"
|
||||
" --format <fmt> WAV output format: wav16, wav24, wav32 (default: wav16)\n\n"
|
||||
@@ -75,7 +75,7 @@ struct Args {
|
||||
const char * lang;
|
||||
const char * instruct;
|
||||
const char * speaker;
|
||||
const char * ref_audio;
|
||||
const char * ref_wav;
|
||||
const char * ref_text_path;
|
||||
const char * dump_dir;
|
||||
const char * out_wav;
|
||||
@@ -165,8 +165,8 @@ static bool parse_args(int argc, char ** argv, Args & a) {
|
||||
a.instruct = argv[++i];
|
||||
} else if (std::strcmp(arg, "--speaker") == 0 && i + 1 < argc) {
|
||||
a.speaker = argv[++i];
|
||||
} else if (std::strcmp(arg, "--ref-audio") == 0 && i + 1 < argc) {
|
||||
a.ref_audio = argv[++i];
|
||||
} else if (std::strcmp(arg, "--ref-wav") == 0 && i + 1 < argc) {
|
||||
a.ref_wav = argv[++i];
|
||||
} else if (std::strcmp(arg, "--ref-text") == 0 && i + 1 < argc) {
|
||||
a.ref_text_path = argv[++i];
|
||||
} else if (std::strcmp(arg, "--format") == 0 && i + 1 < argc) {
|
||||
@@ -249,11 +249,11 @@ static int run(const Args & a) {
|
||||
std::unique_ptr<float, void (*)(void *)> raw_holder(NULL, std::free);
|
||||
const float * ref_audio_24k = NULL;
|
||||
int ref_n_samples = 0;
|
||||
if (a.ref_audio) {
|
||||
if (a.ref_wav) {
|
||||
int T_in = 0;
|
||||
float * raw = audio_read_mono(a.ref_audio, QWEN_TTS_SAMPLE_RATE, &T_in);
|
||||
float * raw = audio_read_mono(a.ref_wav, QWEN_TTS_SAMPLE_RATE, &T_in);
|
||||
if (!raw || T_in <= 0) {
|
||||
fprintf(stderr, "[CLI] ERROR: cannot read --ref-audio '%s'\n", a.ref_audio);
|
||||
fprintf(stderr, "[CLI] ERROR: cannot read --ref-wav '%s'\n", a.ref_wav);
|
||||
if (raw) {
|
||||
std::free(raw);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user