<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kasper</title>
    <description>The latest articles on DEV Community by Kasper (@nibor1896).</description>
    <link>https://dev.to/nibor1896</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4027621%2F56536702-51d5-49ed-a744-a17fcf5aa762.jpg</url>
      <title>DEV Community: Kasper</title>
      <link>https://dev.to/nibor1896</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nibor1896"/>
    <language>en</language>
    <item>
      <title>v0.2.0 - Horus.F5Tts.Onnx - MASSIVE improvements</title>
      <dc:creator>Kasper</dc:creator>
      <pubDate>Thu, 16 Jul 2026 14:26:20 +0000</pubDate>
      <link>https://dev.to/nibor1896/v020-horusf5ttsonnx-107c</link>
      <guid>https://dev.to/nibor1896/v020-horusf5ttsonnx-107c</guid>
      <description>&lt;p&gt;&lt;a href="//nibor1896.github.io/Horus.F5Tts.Onnx/"&gt;HORUS.F5TTS.ONNX&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.nuget.org/packages/Horus.F5Tts.Onnx#readme-body-tab" rel="noopener noreferrer"&gt;HORUS.F5TTS.ONNX - NuGet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;v0.2.0 ships FP16 → 10× faster on GPU.&lt;br&gt;
60 ms per denoising step, down from 617. Measured, not vibes.&lt;/p&gt;

&lt;p&gt;Plus: text of any length, real cancellation, resampling built in.&lt;/p&gt;

&lt;p&gt;MIT · 90 tests&lt;br&gt;
dotnet add package Horus.F5Tts.Onnx&lt;/p&gt;

</description>
      <category>ai</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Shipping the first .NET F5-TTS library — and the ONNX bug I had to fix first</title>
      <dc:creator>Kasper</dc:creator>
      <pubDate>Mon, 13 Jul 2026 17:24:49 +0000</pubDate>
      <link>https://dev.to/nibor1896/shipping-the-first-net-f5-tts-library-and-the-onnx-bug-i-had-to-fix-first-22dc</link>
      <guid>https://dev.to/nibor1896/shipping-the-first-net-f5-tts-library-and-the-onnx-bug-i-had-to-fix-first-22dc</guid>
      <description>&lt;p&gt;F5-TTS is one of the better open text-to-speech and voice-cloning models. There's just one catch if you live in the .NET world: &lt;strong&gt;running it means Python and PyTorch.&lt;/strong&gt; No native story, no NuGet package, nothing you can drop into a desktop app without shipping an interpreter alongside it.&lt;/p&gt;

&lt;p&gt;I wanted German (and any-language) TTS inside a native Windows app — so I set out to run F5-TTS on &lt;strong&gt;ONNX Runtime&lt;/strong&gt;, which .NET already has first-class bindings for. This is the story of the bug that stood in the way, and the library that came out of fixing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The garbled-German problem
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/DakeQQ/F5-TTS-ONNX" rel="noopener noreferrer"&gt;DakeQQ/F5-TTS-ONNX&lt;/a&gt; is an excellent project that exports F5-TTS to three ONNX graphs (preprocess → transformer → decode). It works great — for the &lt;strong&gt;default (v1)&lt;/strong&gt; base checkpoint.&lt;/p&gt;

&lt;p&gt;Point it at a non-English community fine-tune, though, and the output is &lt;em&gt;fluent-but-wrong&lt;/em&gt; speech: the right voice, the right language, complete nonsense words. A classic sign that the text conditioning is broken while the acoustic model is fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root cause: v0 vs v1
&lt;/h2&gt;

&lt;p&gt;Many non-English fine-tunes (like &lt;code&gt;hvoss-techfak/F5-TTS-German&lt;/code&gt;) are built on the older &lt;strong&gt;F5TTS_Base (v0)&lt;/strong&gt; architecture, which differs from v1 in two config flags:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;param&lt;/th&gt;
&lt;th&gt;v1 (default)&lt;/th&gt;
&lt;th&gt;v0&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pe_attn_head&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;None&lt;/code&gt; (RoPE on all heads)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;1&lt;/code&gt; (RoPE on the &lt;strong&gt;first head only&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text_mask_padding&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The exporter's model reimplementation was hard-wired for v1: it applied RoPE to every attention head and always zeroed out padded text positions. On a v0 checkpoint, both corrupt the conditioning — and you get word-salad.&lt;/p&gt;

&lt;p&gt;The fix was small and I contributed it upstream in &lt;a href="https://github.com/DakeQQ/F5-TTS-ONNX/pull/74" rel="noopener noreferrer"&gt;PR #74&lt;/a&gt; (merged): honor &lt;code&gt;pe_attn_head&lt;/code&gt; in the attention processor, and honor &lt;code&gt;mask_padding&lt;/code&gt; in the text embedding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping it in a .NET API
&lt;/h2&gt;

&lt;p&gt;With correct ONNX models in hand, the wrapper is tiny — all the heavy signal processing (STFT, the diffusion transformer, the vocoder) lives inside the graphs. The library just marshals tensors and runs the NFE loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Horus.F5Tts.Onnx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F5TtsModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"F5_Preprocess.onnx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"F5_Transformer.onnx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"F5_Decode.onnx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"vocab.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;configureSession&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendExecutionProvider_DML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// CPU / DirectML / CUDA&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WavAudio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadPcm16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"voice.wav"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 24 kHz mono&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Synthesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Transcript of the clip."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello from .NET!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAllBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"out.wav"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToWav&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design choices worth calling out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No forced runtime.&lt;/strong&gt; The package only references the ONNX Runtime &lt;em&gt;managed&lt;/em&gt; API; the consumer adds the CPU / DirectML / CUDA native package and picks the provider via a session hook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Character-level tokenizer.&lt;/strong&gt; For Latin-script languages you don't need jieba/pinyin at all — a plain char→vocab-index mapping is enough (verified end-to-end).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency-free WAV helpers&lt;/strong&gt;, so the surface stays tiny.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verifying it actually works
&lt;/h2&gt;

&lt;p&gt;Compiling isn't shipping. I ran the whole pipeline against real models and transcribed the output with &lt;code&gt;faster-whisper large-v3&lt;/code&gt;: correct language, exact transcript, confidence 1.00. (The smoke test caught a real runtime bug too — the NFE loop ran one step too many and overran the transformer's time-step table. CI + a smoke test earn their keep.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Shipping it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NuGet:&lt;/strong&gt; &lt;code&gt;dotnet add package Horus.F5Tts.Onnx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/nibor1896/Horus.F5Tts.Onnx" rel="noopener noreferrer"&gt;nibor1896/Horus.F5Tts.Onnx&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; &lt;a href="https://huggingface.co/nibor1896/F5-TTS-German-ONNX" rel="noopener noreferrer"&gt;nibor1896/F5-TTS-German-ONNX&lt;/a&gt; (CC-BY-NC-4.0)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Site:&lt;/strong&gt; &lt;a href="https://nibor1896.github.io/Horus.F5Tts.Onnx/" rel="noopener noreferrer"&gt;nibor1896.github.io/Horus.F5Tts.Onnx&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As far as I can tell, it's the first library that runs F5-TTS natively from .NET. If you're building something that needs local, offline, natural-sounding TTS on Windows/.NET, give it a spin — and open an issue if you hit anything.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
