Commit Graph
79 Commits
Author SHA1 Message Date
Pascal c39ef15bab logs 2026-07-05 10:25:31 +02:00
Pascal 2700d4c746 codec: stateful frame by frame streaming decode on a static graph
Every causal conv carries its left context in a persistent backend
tensor and every transposed conv its overlap tail, so a T=1 frame
decode reproduces the offline full decode exactly with zero re decoded
context. The tokenizer transformer attends over a sliding window KV
ring written through set_rows. The frame graph builds and allocates
once, then every frame is input uploads, one direct backend compute,
and one readback. The quantizer conts each codebook id view so the
Vulkan get_rows path accepts the direct compute. Each generated frame
emits its samples immediately and ICL priming feeds the full reference
through the same state. The buffered path keeps the chunked decode and
both codec framing knobs now apply to it alone.
2026-07-05 10:25:21 +02:00
Pascal bcac46352e logs 2026-07-05 07:47:07 +02:00
Pascal 415ef56330 tts: static decode graphs and device resident hidden bridge
KV writes go through set_rows with the destination rows carried as data
and the code predictor steps get one arena per sub step, so every
decode graph keeps a fixed topology and fixed tensor addresses step
after step. The talker last hidden stays resident on device in a
persistent bridge tensor, written by the talker graph and concatenated
as a leaf by the predictor prefill. The hot loop uploads sixteen code
ids and one overlay row and reads back the logits alone, host hidden
readbacks survive only under the dump path. Fewer nodes, transfers and
syncs pay on every backend, and the stable topology lets the CUDA
backend replay its captured graphs without an update.
2026-07-05 07:43:09 +02:00
Pascal e2e381f4f0 codec: persistent graph arena for the streaming decode path
pipeline_codec_decode builds its graph in a persistent arena instead of
a fresh ggml context per call. Constant size streaming slices rebuild
every node at the same address with identical shapes, which trims host
side graph churn on every backend and lets the CUDA backend replay its
captured graph executable without an update. The encode path keeps its
per call context.
2026-07-05 07:42:50 +02:00
Pascal f84fc05292 logs 2026-07-04 22:47:51 +02:00
Pascal 4057d0331f tts: seed the vocoder left context with the ICL reference tail
The upstream pipeline decodes reference plus generated codes then trims,
giving the first generated frames causal context from the reference; the
generated only decode started the vocoder from an empty state and
colored the clone onset. Seed both decode paths with the last
min(ref_T, left_ctx_frames) reference frames: the streaming decoder
takes them below its emit cursor so they are never emitted, the buffered
path prepends them and strips their samples. Raising
codec_left_context_sec past the reference duration reproduces the
upstream full reference decode exactly.
2026-07-04 22:47:41 +02:00
Pascal 3e3b6c1712 tts: lazy encoder loading and in graph embedding gathers
Load the codec encoder half (seanet, enc_transformer, enc_downsample,
qenc) and the speaker encoder lazily on their first real use: synthesis
from a pre extracted reference (--ref-spk --ref-rvq) now brings up only
the talker and the codec decoder, matching the load profile of a preset
voice server. Assemble the AR inputs on device: the talker decode graph
gathers and sums the 16 frame code embeddings plus the trailing text or
pad overlay via get_rows, and the code predictor gathers c0 and each
sampled sub code from its group table in graph. Per frame host traffic
drops from 16 gguf row reads plus a CPU sum plus 15 synchronous backend
readbacks to 16 code ids and one overlay row uploaded. The next-emb
parity dump reproduces the in graph composition on host under --dump
only, staying byte comparable against the Python hook.
2026-07-04 21:35:03 +02:00
Pascal c9d9fa1c6b ggml: fork update 2026-07-04 21:19:51 +02:00
Pascal 3ee7bdd8c8 tts: persistent graph arenas and padded attention windows
Rebuild each forward into a persistent arena per graph shape class (one
for the talker, two for the code predictor prefill and step flavors that
alternate within a frame) so nodes keep stable addresses and the CUDA
graph cache replays its executable instead of reinstantiating. Pad the
talker attention window to 256 and fix the predictor window to the frame
cache size so decode shapes hold across steps, with the causal mask
carrying neg inf over the padded tail. Drop the per step ggml context
churn and the trailing sched resets: one talker step plus 15 predictor
micro steps per frame no longer pay a full build/alloc/free cycle each.
2026-07-04 14:14:59 +02:00
Pascal 46c99d5889 cmake: default GGML_CUDA_GRAPHS to ON
Standalone ggml ships CUDA graphs off. Capture/replay batches every
kernel launch of a graph into a single submission. Override with
-DGGML_CUDA_GRAPHS=OFF or at runtime with GGML_CUDA_DISABLE_GRAPHS=1
2026-07-04 13:45:08 +02:00
Pascal 0b4ef05d4c ggml: fork update 2026-07-04 10:55:26 +02:00
Pascal 3676f0dc41 doc 2026-07-04 01:54:23 +02:00
Pascal 3a3069b8fd utf8: normalize inbound text bytes to UTF-8
Same gap as omnivoice.cpp: the UTF-8 boundary covers argv, console
output, and fopen but not the bytes arriving from stdin or text files.
Windows shells and editors hand those over as UTF-16 with BOM
(PowerShell redirection, Notepad, Out-File) or the ANSI codepage (cmd
pipes), and the raw bytes reach the tokenizer as garbage.

utf8_normalize() closes the gap: UTF-8 BOM stripped on every platform,
UTF-16 BOM losslessly recoded to UTF-8, bytes failing UTF-8 validation
decoded from the ANSI codepage. Valid UTF-8 passes through untouched.
Wired into read_stdin_text (binary mode stdin so CRLF translation
cannot eat UTF-16 0x0D bytes) and read_text_file, which also moves
from raw fopen to utf8_fopen so a non-ASCII --ref-text path opens.
2026-07-04 01:14:00 +02:00
Pascal 09d3bc90ab ggml: fork update 2026-07-03 22:38:45 +02:00
Pascal 9dbe7ea26a tests: absolute paths are prohibited 2026-06-24 19:00:33 +02:00
PascalandGitHub c7fb781937 Merge pull request #5 from andimarafioti/codex/voice-ref-abi
Add voice reference extraction ABI
2026-06-24 17:33:58 +02:00
Pascal 4536dcdce2 cleaning 2026-06-21 17:30:21 +02:00
Pascal 26fcea5468 ggml: fork update 2026-06-19 16:01:29 +02:00
Pascal 0bf4a18b22 codec: add pre-encoded voice reference (--ref-spk / --ref-rvq)
qwen-codec --talker extracts the speaker embedding (.spk, raw f32)
and the ICL codes (.rvq) in one pass, encode truncated to the hop
boundary conforming to the --ref-wav path. qwen-tts loads them via
--ref-spk / --ref-rvq and skips the speaker encoder and codec encode
on every synthesis: TTFA 205 ms -> 89 ms. Extends qt_tts_params with
ABI v2 latent fields, adds qt_num_codebooks(), ships freeman.spk +
freeman.rvq and switches clone scripts to the latent path. Output is
bit-identical to the raw path at fixed seed.
2026-06-11 21:45:13 +02:00
Pascal e8e33629c1 graph: reset scheduler before remaining shared-sched graph allocs
The talker path already resets the scheduler before allocating its graph
(thanks Andi Marafioti, #4 of qwentts.cpp). The same shared scheduler is
also allocated elsewhere without a reset first.

The scheduler keeps split and tensor->backend assignments from the
previous graph. Allocating a different graph topology on a dirty
scheduler can reuse stale assignments, which is exactly the CPU
divergence Andi fixed for the talker. Resetting before alloc_graph is
the canonical GGML contract and is idempotent when the scheduler is
already clean.

Suggested-by: Andres Marafioti <andimarafioti@gmail.com>
2026-06-09 19:53:56 +02:00
PascalandGitHub f79b23a567 Merge pull request #4 from andimarafioti/reset-scheduler-before-talker-alloc
Reset scheduler before talker graph allocation
2026-06-09 12:01:12 +02:00
PascalandJeffrey van Binsbergen df66c67706 tts: add --stream-by-line, one utterance and one WAV header per line
With -o '-', stdin is read line by line and every line synthesises
immediately as its own utterance, model and speaker staying resident
across lines. Each utterance after the first opens with a fresh RIFF
header, armed at end of line and consumed lazily at the next audio,
so a client can split the stream into standalone WAV clips on the
RIFF magic. Port of the feature contributed to omnivoice.cpp in
ServeurpersoCom/omnivoice.cpp#11.

Co-authored-by: Jeffrey van Binsbergen <comgenie@comgenie.com>
2026-06-06 23:13:46 +02:00
Pascal ed8052eeb3 clang-format 2026-06-06 22:46:56 +02:00
Pascal ca0c779f49 tts: default language to auto, NULL lang selects auto, reject NULL text 2026-06-06 13:31:51 +02:00
Pascal f3cfa5cf47 server: add OpenAI compatible TTS server (chunked PCM streaming, WAV one-shot) 2026-06-06 12:47:10 +02:00
Pascal eda8b59092 docs 2026-05-31 19:20:57 +02:00
Pascal 8aba0f012a logs 2026-05-31 17:49:31 +02:00
Pascal 08b79d1209 prompt: cut TTFA by projecting text and ICL codec embeds on the backend
What we gain: lower TTFA (time to first audio), the latency before the
first frame is emitted. The win is entirely in the one shot prompt build;
per frame inference throughput (talker + code predictor) is unchanged.

How:
- Fuse projection: non ICL projects [instruct ; role] in one pass, ICL
  projects [ref_text ; utterance] in one pass. Trailing utterance keeps
  its own pass.
- ICL codec stream on the backend: the per frame per codebook host
  embed_row_to_f32 + vec_add sum becomes num_code_groups ggml_get_rows
  summed on the GPU in one graph (codebook 0 from talker.codec_embedding,
  rest from code_predictor.codec_embedding, any quant via get_rows).
- Drop the host text projection (linear_f32, silu, read_tensor_f32,
  text_projection_*, PromptTextProjection). tts_bos/eos/pad are projected
  once on the backend in prompt_cache_load, now run after backend_sched_new.

No regression: direct prompt embed outputs match the host path within 2e-6
cosine on all 32 cells, bit exact in BF16/F32. The per frame AR loop is
untouched (ms/frame flat).

TTFA gain, CUDA0 RTX PRO 6000, greedy, 64 frames (old -> new):

  mode/quant      BF16     F32       Q8_0     Q4_K_M
  base            -18%     ~flat     -27%     -37%
  clone           -36%      -7%      -26%     -41%
  customvoice     +11%      -1%      -26%     -32%
  tts             -25%     -11%      -24%      +5%
2026-05-31 17:48:43 +02:00
Pascal 199a65813a logs 2026-05-31 15:41:34 +02:00
Pascal 5442c2f84c perf: add per-stage timer instrumentation to qwentts and omnivoice
Add steady_clock Timer (backend agnostic) and emit [Perf] lines per
synthesis stage: prompt build, prefill, TTFA, talker decode, code
predictor, host compose, codec decode, total with RTF. omnivoice logs
generate, codec decode and total for the one chunk path. Spans end on a
device readback so GPU work is covered, no cudaEvent dependency.
2026-05-31 15:05:48 +02:00
Pascal 127bde4eea docs 2026-05-31 14:09:28 +02:00
Pascal 1c62494faa docs 2026-05-31 13:45:25 +02:00
Pascal 29a7fa0f97 test logs 2026-05-31 02:39:03 +02:00
Pascal a62fde62e6 prompt: drop dead host projection fallback, qt_throw on backend failure 2026-05-30 16:44:16 +02:00
Pascal cea3260b64 clang-format 2026-05-30 16:15:31 +02:00
PascalandGitHub 300bb09944 Merge pull request #3 from andimarafioti/optimize-prompt-ttfa
Optimize prompt TTFA with cached prefixes and batched projection
2026-05-30 16:13:12 +02:00
Pascal 207da32e75 nits 2026-05-30 16:10:10 +02:00
Pascal b7d601ff66 nits 2026-05-20 14:15:09 +02:00
PascalandGitHub 85ad801950 Merge pull request #1 from smashingtags/master
cmake: add Intel Arc GPU support via SYCL backend
2026-05-20 14:10:11 +02:00
Pascal 55b7234d21 cmake: scope /utf-8 to C and C++ so nvcc does not treat it as an input file 2026-05-17 14:41:39 +02:00
Pascal 8e1df7329a ggml: sync 2026-05-17 14:19:59 +02:00
Pascal 50b97b12fc ggml: address 0cc4m review for Vulkan fused snake activation
snake.comp is renamed to follow the ggml DATA_A_* / A_TYPE convention.
A_TYPE now applies to the activation tensor data_a instead of the
broadcast multiplier, and the bindings become data_a (A_TYPE), data_b
(float), data_c (float) and data_d (D_TYPE). A header at the top of
the shader maps each buffer to its role in y = x + sin(b * x)^2 * c.

On the C++ side, ggml_vk_can_fuse_snake reuses the existing snake_pattern
constant instead of duplicating the op list, sin_node is extracted as a
named local alongside the other chain nodes, and the broadcast operands
a and inv_b are now required to be GGML_TYPE_F32 to match the hardcoded
float bindings on data_b and data_c (the previous a->type == x->type
would silently reject any future BF16 or F16 chain once the supports_op
gate for SIN / SQR is lifted). ggml_vk_snake_dispatch_fused gets an
explicit GGML_TYPE_F32 case and GGML_ABORT on default in place of the
silent f32 fallback, and a stale comment about data_a[i1] / data_inv_b[i1]
is refreshed to match the new binding names.
2026-05-17 11:38:29 +02:00
Pascal 5523143942 tests 2026-05-15 00:02:37 +02:00
Pascal 4bf578ec7b qwen-tts: drop --text, align help on omnivoice style 2026-05-14 23:48:27 +02:00
Pascal f9f4a0c820 cleanup: remove dead code and DRY pre_conv release via wctx_free 2026-05-14 23:27:09 +02:00
Pascal dda50c2225 codec: add chunked decode with rolling left context 2026-05-14 22:53:28 +02:00
Pascal d99eececc8 nits 2026-05-14 22:26:28 +02:00
Pascal b1339f7cae abi: drop QT_CODEC_SAMPLE_RATE macro, hardcode 24000 like omnivoice 2026-05-14 21:55:23 +02:00
Pascal 38bf6d762a abi, pipeline, cli: conform qwentts on omnivoice convention 2026-05-14 21:42:52 +02:00
Pascal 259e7059f6 align symbol naming on omnivoice convention 2026-05-14 18:09:07 +02:00
Pascal e55ba50b75 src: fuse 3 .cpp into header-only modules to match omnivoice 2026-05-14 17:14:30 +02:00
Pascal e8f1c2a053 nits 2026-05-14 16:47:45 +02:00
Pascal b1e864cb8d cli, facade: rename --ref-audio to --ref-wav, align with omnivoice convention 2026-05-14 15:46:46 +02:00
Pascal 6ad6a7db7a facade, abi: thin CLI on top of qwen_* public ABI, lock contract with C99 probe 2026-05-14 15:31:47 +02:00
Pascal 552aa93f98 refactor: ABI 2026-05-14 15:13:45 +02:00
Pascal eb48f33f09 utf8: portable Windows UTF-8 boundary for argv, fopen and CreateFile 2026-05-14 14:10:26 +02:00
Pascal 57d12ba4e5 ggml: sync from llama.cpp 2026-05-13 10:03:56 +02:00
Pascal d5f1e20c08 pipeline: zero-init qenc_host_ready, value-init PipelineTTS
The lazy-init flag started on stack garbage. When non-zero the encode
path skipped the codebook load and silently returned empty RVQ codes.
2026-05-11 18:27:06 +02:00
Pascal 7f532f1ed0 cli, pipeline: decode --ref-audio once at the CLI, pipeline takes a mono buffer
Clone mode used to read the same WAV twice (speaker encoder then codec
encoder), which failed silently on Windows where pipeline_codec_encode
returned empty on the second pass. PipelineTTSSynthesizeParams now takes
ref_audio_24k + ref_n_samples instead of a path. The CLI calls
audio_read_mono once, holds the buffer in a unique_ptr until synthesis
returns, and feeds the same pointer to both encoders.
2026-05-11 18:14:59 +02:00
Pascal d700ffea43 cli: --ref-text takes a file path instead of inline string content 2026-05-11 17:57:40 +02:00
Pascal eefb13043e tests logs 2026-05-11 16:27:12 +02:00
Pascal 32560ea597 talker, code-predictor: fused flash attention, fix Vulkan autoregressive decode 2026-05-11 15:29:24 +02:00
Pascal 42510fff59 tests logs 2026-05-11 13:38:21 +02:00
Pascal 530eed6ac5 loader, quantize: align GGUF on llama.cpp, conv kernels widened to F16 at load
GGUF norm matches llama.cpp policy: F32 master stays F32, BF16
variant keeps source BF16, K-quants fall back to F16 when kernel
rows do not align. No conv override in pick_type.

Conv kernels widen to F16 at load through gf_load_conv (12 sites).
qwen_load_ctw_f32 accepts BF16 source.

TODO upstream GGML: ggml_conv_1d and ggml_conv_1d_dw force F16 on
their im2col output, while conv_2d picks the kernel dtype. This
crashes F32 and BF16 kernels on CPU (im2col only handles F16) and
BF16 on Vulkan (mul_mat refuses BF16 on the operand the kernel
ends up on). Aligning conv_1d on conv_2d removes the workaround.
2026-05-11 12:42:54 +02:00
Pascal 59fda26827 tests logs 2026-05-11 07:23:36 +02:00
Pascal 0a7023bd0b talker, code predictor: persistent KV cache
Adds a per-layer K/V ring (kv-cache.h) backed by a dedicated backend
buffer, sized at init for max_seq_len positions. The talker holds a
4096 position cache (896 MB f32) for the LM context, the code
predictor a 16 position cache (~80 KB) reset every frame.

talker_forward splits into prefill (resets the cache and writes T
positions in one shot) and decode (appends one position, reads the
[0, cur_len+1) window). code_predictor_step does the same with a T=2
prefill plus 14 single token decodes.

Bit identical audio output, validated by sha256 against the pre KV
cache run on a 64 frame F32 reference seed=42. Walltime drops ~10%
on a single utterance ; the win scales with sequence length and
unlocks frame by frame streaming.
2026-05-11 06:44:39 +02:00
Pascal 05ecde271a convert: drop orphan encoder.sliding_window GGUF key 2026-05-11 05:48:47 +02:00
Pascal 9264b737a9 encoder: replicate pad on downsample, drop orphan sliding_window field 2026-05-11 05:43:06 +02:00
Pascal 7e01c71c58 clang-format 2026-05-10 22:20:47 +02:00
Pascal c3bd376338 encoder-transformer: pure causal mask, drop sliding window 2026-05-10 22:20:22 +02:00
Pascal 7b9435c886 clone: mode B fix, librosa to torchaudio resample, plus SEANet bisection tooling 2026-05-10 22:11:45 +02:00
Pascal 186ee91c70 ggml: sync from llama.cpp 2026-05-10 20:56:28 +02:00
Pascal 7e89929a70 fix speaker encoder ECAPA forward cossim 0.86 -> 0.996
mel-spk and mel-mag dumps in speaker-encoder-extract.h applied an extra
ggml_transpose plus cont before write. Raw ggml ne=(C, T) already
streams as numpy [T, C], so the transpose was inverting axes vs the
python upstream. Removed it.
MelMag 0.04 -> 0.999, MelSpk 0.92 -> 0.998

spk_conv1d_same passed ggml_im2col a kernel ne=(K, 1, IC, 1) and an
input ne=(T_pad, 1, IC, 1) with IC in ne[2]. But the im2col impl reads
IC = b->ne[1] when is_2D=false, so it saw IC=1, wrote OW*K floats into
a buffer declared for OW*IC*K floats, and mul_mat consumed 99% garbage.
Moved IC into ne[1] for both kernel and input, which makes the impl
read the real IC and writes a buffer coherent with the declared ne. The
permute and the retranspose after pad become unnecessary, dropped both.
SpkFrontend 0.74 -> 0.994, SpeakerEmb 0.86 -> 0.996

Adds ECAPA bisection infrastructure : 4 stage out params in
speaker_encoder_forward (frontend, block3, mfa, asp), codec encoder
intermediate dumps in pipeline-codec.cpp (seanet-out, enc-transformer
out, codec-pre-fsq), matching pytorch hooks in debug-clone-cossim.py.
2026-05-10 20:56:14 +02:00
Pascal acb75fca36 tests 2026-05-10 17:24:33 +02:00
Pascal 564b36ac90 example file for voice clone 2026-05-10 17:20:15 +02:00
Pascal 4feb286f04 tests 2026-05-10 16:43:58 +02:00
Pascal 8ca9622c70 add ggml submodule 2026-05-10 16:02:06 +02:00
Pascal add3f940a0 Initial release 2026-05-10 15:57:15 +02:00