I have been working on speech recognition in C-Kernel-Engine for a while. Whisper can transcribe my own videos. The other direction is becoming more interesting to me now: I want my Linux workstation to read a useful response from a coding agent without making me stare at another terminal. That is why I started looking closely at Kokoro, a small text-to-speech model, and asking what it would take to run its actual graph through CKE's generated C runtime.
I do not want to call this a working CKE voice yet. The upstream Kokoro reference can produce speech, and CKE has begun to reproduce its pieces. As of the CKE tree I reviewed on September 27, 2026, CKE does not execute the complete Kokoro phoneme-to-waveform circuit. The distinction is important because an embedding kernel that matches PyTorch and a generated waveform that I can listen to are very different milestones.
What text-to-speech actually has to do
At the application level, text-to-speech starts with text and ends with samples that an audio device can play. The middle is not just a language model decoding words. The system has to decide how written text is pronounced, how long each sound lasts, where pitch rises or falls, what texture or breathiness the voice has, and how to turn those time-aligned features into a waveform. A phrase such as an acronym, a version number, or a developer's name makes the first step surprisingly important. If text normalization or pronunciation is wrong, no amount of waveform quality can repair the words.
For my first CKE gate, I am deliberately not starting with raw text. The pinned Kokoro experiment starts with prepared phoneme IDs and one selected voice row. The upstream Misaki pronunciation layer is a separate input contract. I first want a waveform that matches the pinned reference under a declared numerical contract with identical source-excitation inputs; only then does it make sense to put native text preparation and playback around it. The CKE Kokoro bring-up inventory records that boundary explicitly.
The whole graph, not just an encoder and decoder
The reference Kokoro model starts with a token sequence of length T, including boundary IDs. It sends those IDs down two paths. One passes through an ALBERT-based contextual encoder and then into duration and prosody prediction. The other passes through a convolutional/recurrent text encoder. Both paths eventually have to be expanded from tokens to audio-aligned frames, because one sound may last longer than another.
Calling everything after ALBERT a “decoder” hides useful detail. This is not an autoregressive transformer chat decoder with a KV cache. The ALBERT portion gives contextual phoneme features. A style-conditioned predictor uses recurrent and convolutional blocks to estimate durations, pitch (F0) and noise-like prosody. A separate text path supplies linguistic features to the acoustic decoder. The final ISTFTNet-style generator uses upsampling, residual convolution, a harmonic source and magnitude/phase reconstruction to make audio. Different operations, different tensor layouts, and different failure modes.
What ALBERT does here
ALBERT is a transformer encoder architecture, not Kokoro's entire speech engine. The ALBERT paper describes parameter sharing as one way to reduce model size. In Kokoro's pinned configuration, token, position and type embeddings are combined and normalized at width 128; a projection enters a 768-wide contextual stack, and the result is projected toward the predictor's 512-wide path. Twelve layer executions do not necessarily mean twelve unrelated sets of weights. I need the resolved parameter-sharing/grouping behavior of the pinned model, not a hand-drawn “12 independent blocks” approximation.
Inside an ALBERT pass, attention lets a phoneme depend on the phonemes around it: linear projections make queries, keys and values; scaled dot products and softmax mix context; an output projection, normalization and feed-forward work refine the representation. CKE already has reusable attention, GEMM and normalization concepts, but a similarly named kernel is not automatically numerically equivalent to Kokoro. Mask semantics, GELU variant, epsilon, tensor stride, weight sharing and accumulation order all matter. The CKE circuit should declare those operations and reuse the right provider contracts rather than acquiring a Kokoro-specific compiler shortcut.
In the familiar transformer shorthand, one head computes softmax(QK^T / sqrt(d) + mask) V. On a CPU, that shorthand becomes specific matrix multiplies, rowwise reductions, exponentials, divisions, layout changes and residual additions. The exact provider and its numerical contract matter more than whether we can find a kernel with “attention” in its name. ALBERT also reuses parameter groups across layer executions, so the circuit needs to represent both the repeated schedule and the shared weight identity. That is the transformer part of Kokoro. The remaining audio model leans much more heavily on recurrent scans and convolutions.
The first generated-C Kokoro boundary is now a real one-operation embedding circuit. PR #583 supplied the checked three-table embedding and LayerNorm provider, with a pinned PyTorch reference. PR #586 brought five fixture-derived BUMP weight payloads into a normal v8 circuit, lowered it, generated native C and compared the compiler-declared embedding checkpoint with that reference. The optional full exported-model bundle test was skipped in my default run. For the pinned [36,128] capture, the runbook records a worst absolute difference of 2.384185791015625e-7. The tests also exercise repeated IDs, invalid-ID output preservation and arena rejection. That is meaningful progress. It certifies the embedding boundary under that test, not the remaining ALBERT layers, complete model loading or spoken output.
The time axis is where a circuit becomes difficult
The duration predictor takes contextual features, the latter half of the selected voice style, and recurrent output. In the upstream forward path, sigmoid duration channels are summed, divided by speed, rounded and clamped to at least one frame per token. The sum of those checked durations is A, the number of aligned audio frames. The model can then repeat token features according to that duration vector. In simplified notation: A = sum(d[t]), and both the contextual/prosody stream and the parallel text stream must agree on that same alignment.
This matters to CKE's compiler. T is known when the request is validated; A is not known until the duration head runs. The model needs enough memory for a configured maximum, but each request has its own valid length. Treating A as both the loop length and the row stride can make adjacent channels overlap when buffers are padded. PR #560's checked runtime extent and subsequent generated-C fixtures address that general compiler problem, not merely a Kokoro quirk.
Recent duration work goes beyond a toy length calculation. The duration-logit provider and generated duration/two-stream fixtures exercise checked frame counts, physical padding, repeated requests and aligned feature expansion. They still use bounded, captured inputs at parts of the path, and the retained evidence records unresolved numerical-contract IDs. I would not describe them as a connected phoneme-to-audio circuit.
Prosody, voice, and the acoustic side
Kokoro's voice reference is more than a label such as “af_heart.” The pinned row is 256 floating-point values selected for the phoneme length; the upstream model uses one 128-wide slice for decoder style and the other for the duration/prosody predictor. A wrong row or swapped slice can produce a valid-looking tensor and still change the voice. CKE's weight and voice exporter records the selected row and effective weights so the circuit can bind actual data, not just compatible shapes.
The predictor has bidirectional recurrent scans, style-conditioned normalization, duration projections and separate pitch/noise branches. CKE's bidirectional LSTM scan and adaptive LayerNorm have independent, bounded primitive evidence. That does not mean every current live-oracle version or fixture is certified. The predictor checkpoints give us places to compare the connected graph when it exists. None of those individual passes means the model's actual recurrent weights, mask, state reset, branch order and style broadcasting have all been stitched.
After the text path and prosody path join, the acoustic side performs style-conditioned residual convolutions, upsampling and nonlinear transforms. The generator's harmonic source includes random phase/noise in the reference implementation. That means “same text and same voice” is not automatically a byte-identical waveform experiment. The same integer seed is insufficient if the RNG algorithm, state, draw order or execution settings differ. I can feed captured excitation tensors into a declared edge to compare a deterministic subgraph, but that would not certify native source generation. I would test that separately under an explicit RNG contract. Magnitude and phase finally go through inverse STFT and overlap-add/window normalization. CKE has an isolated inverse-STFT primitive oracle; it does not yet have the complete generated generator waveform. The pinned CKE graph inventory lists the remaining convolution, source, normalization, branch and layout contracts.
The generator is a good example of why “just stitch kernels” is both the right idea and not quite enough instruction. Its Snake activation is x + sin(alpha*x)^2 / alpha, not the SiLU used in many language models. The decoder needs grouped, dilated and transposed convolution behavior in places where a basic Conv1D provider is insufficient. iSTFT needs phase, overlap-add and window normalization; a forward spectrogram-power kernel cannot substitute for it. Those are reusable numerical operations to add or certify. Their exact shape, stride, padding and accumulation rules are the contracts that make the stitch trustworthy.
How I want CKE to stitch it
I want four declared components with explicit tensor ports: phoneme encoder (embedding, ALBERT schedule, projection); duration (style-conditioned predictor, checked frame count and expansion map); prosody (aligned features, shared recurrent path and pitch/noise branches); and waveform decoder (parallel text features, residual/upsampling stages, harmonic source, magnitude/phase and inverse STFT). The separate text encoder and selected voice row feed those components through named edges. A single generated native entry should execute the connected graph. Python should not have to secretly schedule the model around generated kernels.
The first diagram showed how Kokoro's model moves features. The next one shows how I want CKE to describe and execute those same movements. In CKE, header, body and footer are ordered sections of a circuit, not C header files or three generic TTS kernels. A circuit names operations and their producer/consumer ports; a kernel map binds each operation to an implementation with a declared calling and numerical contract. The compiler then plans buffer lifetimes and emits the calls. The v8 circuit format describes the section and stitch vocabulary; the Kokoro graph inventory applies it to this pinned model.
The header of the phoneme encoder checks IDs and runs the three-table embedding and LayerNorm; that boundary is already exercised in generated C. Its body would schedule the ALBERT attention and feed-forward work while preserving shared weight identity, and its footer would publish contextual features for the duration path. The parallel text path starts from the same phoneme IDs but produces its own [512,T] features. I show its header/body/footer grouping as a proposed circuit layout, not as an implemented Kokoro circuit file.
The duration component is where the composition stops being a fixed-length chain. After the style-conditioned recurrent stages, its footer must publish checked per-token durations, A = sum(d[t]), and one frame-to-token map. That same map separately expands the prosody-side features and the parallel text features. Prosody uses the aligned duration stream to produce pitch and noise at 2A; the waveform decoder receives the aligned text stream, those prosody outputs and the decoder half of the voice row. Its body would stitch residual convolutions, upsampling and source/generator stages; its footer would perform magnitude/phase and inverse-STFT work and publish a checked sample length. Calling these connections stitch edges makes ownership explicit: neither Python nor a hidden model-name branch should decide how to reconnect the streams.
The runbook's circuit decomposition is a design target, not evidence that the full graph lowers today. The embedding has generated-C parity evidence; checked duration and two-stream alignment have partial generated-C fixtures. A complete phoneme-to-waveform entry, the remaining provider contracts, and a listened-to waveform are still missing. That distinction is why I would first lower the pinned graph and identify its first unsupported edge before claiming CKE can already speak.
The compiler side matters as much as kernel math. Each provider map should declare its pointer, stride, valid-extent, capacity, scratch and weight-layout requirements. The circuit declares producer/consumer edges and persistent-state semantics; the compiler derives liveness and plans memory from those contracts. A failed duration check must stop downstream work before any output is presented as valid. The same generated entry must behave correctly on a second request with a different length, with no unintended recurrent-state carryover and an explicit per-request or per-session RNG policy. X-Ray can then compare compiler-declared checkpoints against the pinned PyTorch capture rather than asking whether the final audio merely sounds plausible.
My goal is to express Kokoro through CKE's existing circuits, kernel maps, memory planner and generated C, not build a separate Kokoro runtime. If new math is needed, I want a reusable kernel with its own numerical test; if an edge cannot be represented, I want a small synthetic graph that proves the missing capability before changing the compiler. Runtime-length support is the kind of model-neutral extension I have in mind. The boundaries tested so far point in that direction, but they do not prove the full graph will need only limited DSL changes. I want to find the first unsupported operation or connection by lowering the complete pinned graph, then make the smallest reusable change that lets generated C execute it. Python can prepare inputs and provide oracle evidence, not perform a missing model stage behind the compiler's back.
The first result I would trust
The decisive next demonstration is deliberately small: one pinned phoneme sequence, one pinned voice, one speed, one generated-C graph and one FP32 waveform compared to the reference at recorded checkpoints. I want the valid sample length, waveform difference, failed-boundary behavior and actual audio file retained. After that, text normalization, phonemization, PCM conversion, a playback queue and interruption control can turn the model into something useful at my desk. I can profile certified primitives during bring-up, but I will only claim end-to-end speech latency after the connected native path produces verified audio.
Kokoro is interesting to me because it forces CKE to exercise more than transformer attention. It brings shared transformer layers, two token streams, recurrent state, style conditioning, dynamic lengths, complex audio math and a real waveform target into one circuit. If CKE can express that cleanly, the value is not only one voice model. It means the engine is getting better at composing the kinds of mixed architectures I want to run locally.
Source and status: CKE Kokoro bring-up inventory reviewed against local CKE commit b5f03325c on September 27, 2026, plus the pinned upstream model, predictor/text modules and waveform generator. This post describes an implementation in progress, not released CKE TTS.