Skip to content

Irodori-TTS support #6

Closed
Closed

Description

@nazodane

Irodori-TTS is a Japanese TTS model based on EchoTTS, but it uses Facebook Research's DAC-VAE instead of Fish-Speech S1-DAC autoencoder.
https://github.com/Aratako/Irodori-TTS

Activity

  1. 0xShug0 commented on Jun 27, 2026

    @0xShug0
    Owner

    Sure! I’m a big fan of Aratako's work. MioTTS and MioCodex are amazing, and they’re already included in audio.cpp.

    Update: In case anyone is interested in performance compared with other cpp implementations:
    check #6 (comment).

  2. 0xShug0 commented on Jul 1, 2026

    @0xShug0
    Owner

    @nazodane Irodori-TTS Done. Stay tuned for release!

    case python ms cpp ms speedup wav similarity
    short_emoji 574.658 532.456 1.079x 0.999994
    style_sound 654.716 589.598 1.110x 0.999999
    clone_reference 831.026 628.639 1.322x 1.000000
    voice_design_caption 684.987 612.264 1.119x 0.999999
    voice_design_ref_caption_emoji 985.461 837.141 1.177x 0.999997
  3. 0xShug0 commented on Jul 10, 2026

    @0xShug0
    Owner

    @nazodane @bakamomi You can try a preview version in the dev branch.

  4. bakamomi commented on Jul 10, 2026

    @bakamomi

    How do you know that I'm interested in Irodori? I don't recall saying it in this repo. lol

    Anyway, Vulkan backend simply crashes.

    ggml_vulkan: 0 = AMD Radeon 780M Graphics (RADV PHOENIX) (radv) | uma: 1 | fp16: 1 | bf16: 0 | warp size: 64 | shared memory: 65536 | int dot: 1 | matrix cores: KHR_coopmat
    /mnt/vfs/audio.cpp/external/ggml/src/ggml.c:4651: GGML_ASSERT(p0 == 0) failed
    ./audiocpp_cli(+0xb9dd56) [0x6446e98b2d56]
    ./audiocpp_cli(+0xb9e4dd) [0x6446e98b34dd]
    ./audiocpp_cli(+0xb9e6c0) [0x6446e98b36c0]
    ./audiocpp_cli(+0xba6d2b) [0x6446e98bbd2b]
    ./audiocpp_cli(+0x3f396e) [0x6446e910896e]
    ./audiocpp_cli(+0x5d42a6) [0x6446e92e92a6]
    ./audiocpp_cli(+0x5d93e6) [0x6446e92ee3e6]
    ./audiocpp_cli(+0x5d5001) [0x6446e92ea001]
    ./audiocpp_cli(+0x3291ca) [0x6446e903e1ca]
    ./audiocpp_cli(+0x1dee6f) [0x6446e8ef3e6f]
    /usr/lib64/libc.so.6(+0x2743b) [0x77146eb7243b]
    /usr/lib64/libc.so.6(__libc_start_main+0x8b) [0x77146eb724eb]
    ./audiocpp_cli(+0x1d5a85) [0x6446e8eeaa85]
    

    I also tried voice reference with Vulkan and it crashed on encoding with:

    radv/amdgpu: The CS has been cancelled because the context is lost. This context is innocent.
    audiocpp_cli failed: vk::Queue::submit: ErrorDeviceLost
    

    As far as I know, this means that it ran out of memory.

    Cuda backend lacks any memory management. A line of 41 characters needs 12 GB of VRAM (when running with voice reference). "本日はお越しいただき、誠にありがとうございます。どうぞごゆっくりお過ごしください。" Generating longer lines on 16 GB VRAM is impossible.

    Edit: for comparison, CrispASR needs only 2 GB of VRAM for the same line and same voice reference. Also, Crisp is twice as fast... though it might be attributed to ref voice caching.

    audio.cpp - real 0m3.037s
    crispasr - real 0m1.644s

  5. 0xShug0 commented on Jul 10, 2026

    @0xShug0
    Owner

    @bakamomi Based on your last issue, I thought Japanese TTS might interest you. Models on the dev branch are previews and still under testing, but some Reddit users wanted to try them, so I put them all on dev. I'm testing memory now, and you can check the latest commit (5e91ece).

    Would you be willing to test long text in server mode, or multiple CLI requests after warm-up, rather than one-shot runs? audio.cpp caches many graphs and also speaker embedding for reuse. Input length has very little impact on VRAM usage. Short requests and 6,000 characters use almost the same amount of VRAM. Check the table below.
    (weights: FP32 safetensor)

    Model Peak VRAM Resident VRAM Server wall Audio RTF
    Irodori TTS 500M 5 req 11222 MiB 3570 MiB 3276 ms 95.4s 0.0343418
    Irodori TTS 500M 6000-char 11588 MiB 3609 MiB 27828 ms 777.92s 0.0357724

    Vulkan issue is fixed. Tested on Vulkan and the resulting wavs

    {
    "requests": [
    {
    "id": "short_emoji",
    "text": "今日は短い確認です。😊やさしく、聞き取りやすい声でお願いします。",
    "language": "ja",
    "seed": 1234,
    "num_inference_steps": 40,
    "options": {
    "no_ref": true
    }
    },
    {
    "id": "style_sound",
    "text": "📞お電話ありがとうございます。少しお待ちください。⏸️ただいま担当者へおつなぎします。",
    "language": "ja",
    "seed": 1234,
    "num_inference_steps": 40,
    "options": {
    "no_ref": true
    }
    },
    {
    "id": "clone_reference",
    "text": "この声の雰囲気を保ったまま、落ち着いて自然に読み上げます。",
    "language": "ja",
    "voice_ref": "resources/sample.wav",
    "seed": 1234,
    "num_inference_steps": 40,
    "options": {
    "no_ref": false
    }
    }
    ]
    }

    {
    "requests": [
    {
    "id": "voice_design_caption",
    "text": "本日はお越しいただき、誠にありがとうございます。どうぞごゆっくりお過ごしください。",
    "language": "ja",
    "seed": 1234,
    "num_inference_steps": 40,
    "options": {
    "caption": "落ち着いた大人の男性。フォーマルな場で、深く響く声で丁寧かつ歓迎の意を込めて話している。",
    "no_ref": true
    }
    },
    {
    "id": "voice_design_ref_caption_emoji",
    "text": "あははっ🤭、それ本当に言ってるの?…😮‍💨まぁ、君らしいけどね。",
    "language": "ja",
    "voice_ref": "resources/clone_ref2.wav",
    "seed": 1234,
    "num_inference_steps": 40,
    "options": {
    "caption": "余裕のある大人の男性。親しい相手に対して、くだけた雰囲気で呆れながらも楽しそうに話している。",
    "no_ref": false
    }
    }
    ]
    }
    Ref wavs:
    clone_ref2.wav
    sample.wav

    clone_reference.wav
    short_emoji.wav
    style_sound.wav
    voice_design_caption.wav
    voice_design_ref_caption_emoji.wav

  6. 0xShug0 commented on Jul 10, 2026

    @0xShug0
    Owner

    @bakamomi Process wall time can be misleading:

    CrispASR: Q8 GGUF, audio.cpp: FP32 Safetensor. 40 steps

    本日はお越しいただき、誠にありがとうございます。どうぞごゆっくりお過ごしください。

    bucket audio.cpp CrispASR
    process wall (real) 1.98 s 1.15 s
    load/init 1450.88 ms 140.50 ms
    inference/session 330.47 ms 545.69 ms
    output write 3.64 ms included in other
    other (e.g., process/CLI/shutdown) ~194.82 ms ~463.81 ms

    inference breakdown

    component audio.cpp CrispASR
    tokenize 0.25 ms 0.50 ms
    condition / text+duration 87.48 ms 89.20 ms
    RF sample 200.20 ms 366.64 ms
    codec decode 41.62 ms 89.34 ms
    synth/session total 330.47 ms 545.69 ms

    Long-text or multi-request tests also amortize the model-loading and warm-up costs.

    Longer: 朝の港町には、まだ薄い霧が残っていた。駅前の時計台が七時を告げるころ、商店街のシャッターが一つずつ上がり、パン屋の窓からは焼きたての香りが通りへ流れ出した。古い図書館では、司書の美咲が返却箱に積まれた本を丁寧に分けながら、週末に開く朗読会の準備を進めていた。朗読会のテーマは「遠くへ出かけなくても見つかる冒険」で、子どもから年配の人まで楽しめるように、海辺の伝説、山里の手紙、町工場で働く職人の記録など、さまざまな物語を選んでいた。そこへ、漁師の健太が濡れた帽子を片手にやって来た。彼は沖で見つけた小さな木箱を図書館に預けたいと言い、中には百年前の日付が書かれた航海日誌と、色あせた写真が入っていた。写真には、現在は倉庫になっている赤レンガの建物の前で、若い女性が笑って立っている。美咲はその建物が、昔は旅人のための音楽ホールだったことを思い出し、日誌の文字を追いながら、町の記憶が静かにほどけていくのを感じた。午後になると、学校帰りの子どもたちが図書館に集まり、木箱の話を聞いて目を輝かせた。ある子は写真の女性が有名な歌手だったのではないかと言い、別の子は日誌に残された地図が宝探しの暗号だと主張した。美咲は笑いながら、まずは資料を調べ、古い新聞を読み、町の人たちに話を聞くことが大切だと説明した。その言葉を聞いた健太は、祖母が赤レンガの建物について何か知っているかもしれないと言い、夕方までに話を聞いて戻ると約束した。日が傾くころ、図書館の窓は橙色に染まり、ページをめくる音だけが静かに響いていた。美咲は朗読会の最後に、この木箱から始まった調査の途中経過を紹介しようと決めた。完成した答えではなく、みんなで手がかりを集めていく過程そのものが、きっと一番わくわくする物語になると思ったからだ。夜になり、港の灯台がゆっくり光を回し始めると、町は昼間とは違う表情を見せた。風は少し冷たくなったが、図書館の中には小さな熱が残っていた。美咲は机の上に日誌を置き、破れやすい紙を傷つけないよう手袋をはめた。最初のページには、若い船乗りが初めてこの町に着いた日のことが書かれていた。彼は嵐で予定の航路を外れ、偶然この港に避難したらしい。ところが、そこで聴いた一夜限りの演奏会に心を奪われ、翌朝出発するはずだった船を見送り、数日だけ町に残ることにした。日誌には、演奏していた女性の声が、波の音と混ざって夜明けまで忘れられなかったと記されている。美咲は写真の女性と日誌の文章を見比べ、これが単なる拾い物ではなく、町に眠っていた小さな歴史の入口なのだと確信した。

    bucket audio.cpp CrispASR
    process wall (real) 5.83 s 8.12 s
    load/init 1375.64 ms 138.73 ms
    inference/session 4163.89 ms 6821.59 ms
    output / remaining CLI 80.45 ms included in other
    other process/wrapper ~209.81 ms ~1159.68 ms

    inference breakdown:

    component audio.cpp CrispASR
    tokenize 24.63 ms 13.17 ms
    condition / text+duration 108.06 ms 103.71 ms
    RF sample 2996.83 ms 4182.40 ms
    codec decode 1018.42 ms 2522.30 ms
    synth/session total 4163.89 ms 6821.59 ms
  7. bakamomi commented on Jul 10, 2026

    @bakamomi

    I tried the server with new updates.
    VRAM situation is better. At least things don't just crash with OOM on long lines.

    But still,

    1. Peak VRAM usage at 12 GB is a lot. It requires dedicating the entire GPU to TTS. How about doing chunked decode to reduce peak VRAM?
    2. On Vulkan backend, this line "その森には、古い言い伝えがありました。月が最も高く昇る夜、静かに耳を澄ませば、風の歌声が聞こえるというのです。私は半信半疑でしたが、その夜、確かに誰かが私を呼ぶ声を聞いたのです。" produced silent output without any obvious errors. But I suspect there was some kind of OOM on decoding step, which just got swallowed.
    3. Output audio for long text gets garbled after 20 seconds. For example:
      📖🐢衝動は、もはや抑えられなかった。二乃は淹れたての熱いコーヒーが乗ったトレイを掴むと、迷わず男のテーブルへと向かった。
      「😱きゃっ!」
      📖🐢わざとらしく足をもたつかせ、二乃は持っていたトレイを男の膝の上に「うっかり」ひっくり返した。
      「😖熱っ! あ、あつっ!」
      📖🐢安物のスラックスに染み込んでいく熱いコーヒーに、男――ヒロシは悲鳴を上げる。店内の客の視線が一斉に集まる中、二乃は勝 ち誇ったように仁王立ちになり、声を張り上げた。
      Garbled output sometimes appears earlier when using reference audio. I suppose it just goes over maximum line length. So, how about using Irodori speech length predictor to chunk text into sentences of about 15 seconds long?

    P.S. It would be nice to add gguf support. audio.cpp idles at 2.6 GB, while CrispASR with q8 takes just 1.2 GB at diffusion (more at decoding).

  8. bakamomi commented on Jul 10, 2026

    @bakamomi

    I retested speed with your long text. Chunking works for your test line, and audio.cpp is faster than CrispASR. But VRAM usage for 0.5B model is just too much. People use 0.5B because they want small footprint.

  9. 0xShug0 commented on Jul 10, 2026

    @0xShug0
    Owner

    @bakamomi Thanks for testing! This is exactly the kind of feedback I need before releasing the model. I don’t speak Japanese, so I really can’t tell whether the Japanese output sounds right.

    For (2), I couldn’t reproduce the issue. For (3), I can’t tell, but I collected the audio outputs for your examples from both audio.cpp and the Python implementation (under random seeds). Let me know if the Python output sounds correct but the audio.cpp output doesn’t.

    audio.cpp also supports long-form generation by default. There is no limit on text len. You don’t need to configure anything. It automatically chunks long text.

    Using text input for the multiline example: input.txt

    Update: I messed up the naming and shared duplicated wavs. Maybe I should let AI handle this task. Wavs re-upload.

    cuda_1.wav
    vulkan_1.wav
    python_1.wav
    cuda_2.wav
    vulkan_2.wav
    python_2.wav

  10. 0xShug0 commented on Jul 10, 2026

    @0xShug0
    Owner

    As for VRAM vs performance, there’s always a trade-off. I’ve tried layer-wise and chunking to reduce memory usage, but performance can drop by up to 50%, depending on the model. My current priority is keeping memory usage stable across requests in a long-lived session, so the current mem-saver mode is less aggressive to better balance performance and VRAM usage (of course, there may still be easier ways to reduce memory usage that I haven’t found yet).

    GGUF support will be rolled out model by model.

  11. bakamomi commented on Jul 10, 2026

    @bakamomi

    For (2), I couldn’t reproduce the issue.

    I bet it's because you're testing on a dGPU with lots of vram. I'm testing Vulkan on iGPU that has just 512 Mb dedicated VRAM (it's almost always completely filled), while working memory is allocated dynamically from RAM pool. Here is full log:

    ./audiocpp_cli --log --task tts --family irodori_tts --model ../../models/Irodori-TTS-500M-v3 --out output_audio.wav  --backend vulkan  --text "その森には、古い言い伝えがありました。月が最も高く昇る夜、静かに耳を澄ませば、風の歌声が聞こえるというのです。私は半信半疑でしたが、その夜、確かに誰かが私を呼ぶ声を聞いたのです。"
    [TRACE ts=20260710-223549] runtime.model.family irodori_tts
    [TRACE ts=20260710-223549] runtime.model.variant 500M-v3
    [TRACE ts=20260710-223549] runtime.model.root /mnt/audio.cpp/models/Irodori-TTS-500M-v3
    [TRACE ts=20260710-223549] runtime.model.discovered_config_count 1
    [TRACE ts=20260710-223549] runtime.model.discovered_weight_count 1
    [TRACE ts=20260710-223549] runtime.model.task_count 2
    [TRACE ts=20260710-223549] runtime.model.language_count 1
    [TRACE ts=20260710-223549] runtime.model.supports_speaker_reference 1
    [TRACE ts=20260710-223549] runtime.model.supports_style_condition 0
    [TRACE ts=20260710-223549] runtime.model.supports_timestamps 0
    ggml_vulkan: Found 1 Vulkan devices:
    ggml_vulkan: 0 = AMD Radeon 780M Graphics (RADV PHOENIX) (radv) | uma: 1 | fp16: 1 | bf16: 0 | warp size: 64 | shared memory: 65536 | int dot: 1 | matrix cores: KHR_coopmat
    [TRACE ts=20260710-223551] irodori_tts.model_root /mnt/audio.cpp/models/Irodori-TTS-500M-v3
    [TRACE ts=20260710-223551] irodori_tts.codec_root /mnt/audio.cpp/models/Semantic-DACVAE-Japanese-32dim
    [TRACE ts=20260710-223551] irodori_tts.config.use_speaker_condition 1
    [TRACE ts=20260710-223551] irodori_tts.config.use_caption_condition 0
    [TRACE ts=20260710-223551] irodori_tts.config.max_text_len 256
    [TRACE ts=20260710-223551] irodori_tts.config.max_caption_len 256
    [TIMING ts=20260710-223551] irodori_tts.condition.graph_rebuild 1
    [TIMING ts=20260710-223602] irodori_tts.codec_decode.graph_rebuild 1
    [TIMING ts=20260710-223605] irodori_tts.reference.used 0
    [TIMING ts=20260710-223605] irodori_tts.reference.cache_hit 0
    [TRACE ts=20260710-223605] irodori_tts.text_chunk_size 256
    [TRACE ts=20260710-223605] irodori_tts.text_chunk_count 1
    [TIMING ts=20260710-223605] irodori_tts.sample_rf.context_graph_rebuilds 1
    [TIMING ts=20260710-223605] irodori_tts.sample_rf.step_graph_rebuilds 2
    [TIMING ts=20260710-223605] irodori_tts.prepare_reference_ms 0.001122
    [TIMING ts=20260710-223605] irodori_tts.tokenize_ms 1.284102
    [TIMING ts=20260710-223605] irodori_tts.condition_ms 49.010772
    [TIMING ts=20260710-223605] irodori_tts.sample_rf_ms 10579.972932
    [TIMING ts=20260710-223605] irodori_tts.sample_rf.context_cond_ms 0
    [TIMING ts=20260710-223605] irodori_tts.sample_rf.context_cfg_ms 28.333504
    [TIMING ts=20260710-223605] irodori_tts.sample_rf.steps_cfg_ms 6706.744738999999
    [TIMING ts=20260710-223605] irodori_tts.sample_rf.steps_cond_ms 3827.0788810000004
    [TIMING ts=20260710-223605] irodori_tts.codec_decode_ms 3857.571076
    [TIMING ts=20260710-223605] session.wall_ms 14491.69658
    family=irodori_tts
    task=tts
    mode=offline
    audio_out=output_audio.wav
    

    For (3), I can’t tell, but I collected the audio outputs for your examples from both audio.cpp and the Python implementation. Let me know if the Python output sounds correct but the audio.cpp output doesn’t.

    All your examples for my test line have garbled speech in the later part (including python implementation). Some sentences are just missing. The issue is most probably the fact that there is not enough time (30s) to say all text. It needs to be chunked, but it's not chunked.

  12. 0xShug0 commented on Jul 10, 2026

    @0xShug0
    Owner

    That’s interesting. Chunking is based on text length, not audio duration. There is no minimum text length requirement. As shown in the example WAVs I shared, some outputs are only about 5 seconds long. The text you pasted is about 89 Japanese characters, while the default chunk size is 256, so it will not be chunked. From the logs, the behavior looks correct.

    I ran the exact cmd on iGPU and the wav sounds okay.

    ggml_vulkan: Found 2 Vulkan devices:
    ggml_vulkan: 0 = NVIDIA GeForce RTX 5090 (NVIDIA) | uma: 0 | fp16: 1 | bf16: 0 | warp size: 32 | shared memory: 49152 | int dot: 0 | matrix cores: KHR_coopmat
    ggml_vulkan: 1 = AMD Radeon Graphics (RADV RAPHAEL_MENDOCINO) (radv) | uma: 1 | fp16: 1 | bf16: 0 | warp size: 32 | shared memory: 65536 | int dot: 0 | matrix cores: none
    
    [TIMING ts=20260710-190438] cli.registry_ms 0.057847
    [TRACE ts=20260710-190438] runtime.model.family irodori_tts
    [TRACE ts=20260710-190438] runtime.model.variant 500M-v3
    [TRACE ts=20260710-190438] runtime.model.root /media/leo/Port/audio.cpp/models/Irodori-TTS-500M-v3
    [TRACE ts=20260710-190438] runtime.model.discovered_config_count 1
    [TRACE ts=20260710-190438] runtime.model.discovered_weight_count 1
    [TRACE ts=20260710-190438] runtime.model.task_count 2
    [TRACE ts=20260710-190438] runtime.model.language_count 1
    [TRACE ts=20260710-190438] runtime.model.supports_speaker_reference 1
    [TRACE ts=20260710-190438] runtime.model.supports_style_condition 0
    [TRACE ts=20260710-190438] runtime.model.supports_timestamps 0
    [TIMING ts=20260710-190438] runtime.model.load_ms 2.002941
    [TRACE ts=20260710-190440] irodori_tts.model_root /media/leo/Port/audio.cpp/models/Irodori-TTS-500M-v3
    [TRACE ts=20260710-190440] irodori_tts.codec_root /media/leo/Port/audio.cpp/models/Semantic-DACVAE-Japanese-32dim
    [TRACE ts=20260710-190440] irodori_tts.config.use_speaker_condition 1
    [TRACE ts=20260710-190440] irodori_tts.config.use_caption_condition 0
    [TRACE ts=20260710-190440] irodori_tts.config.max_text_len 256
    [TRACE ts=20260710-190440] irodori_tts.config.max_caption_len 256
    [TIMING ts=20260710-190440] cli.model_session_ms 1514.530332
    [TIMING ts=20260710-190440] cli.request_build_ms 0.008799
    [TIMING ts=20260710-190440] cli.prepare_ms 0.00069
    [TIMING ts=20260710-190440] irodori_tts.condition.graph_rebuild 1
    [TIMING ts=20260710-190612] irodori_tts.codec_decode.graph_rebuild 1
    [TIMING ts=20260710-190815] irodori_tts.reference.used 0
    [TIMING ts=20260710-190815] irodori_tts.reference.cache_hit 0
    [TRACE ts=20260710-190815] irodori_tts.text_chunk_size 256
    [TRACE ts=20260710-190815] irodori_tts.text_chunk_count 1
    [TIMING ts=20260710-190815] irodori_tts.sample_rf.context_graph_rebuilds 1
    [TIMING ts=20260710-190815] irodori_tts.sample_rf.step_graph_rebuilds 2
    [TIMING ts=20260710-190815] irodori_tts.prepare_reference_ms 0.00067
    [TIMING ts=20260710-190815] irodori_tts.tokenize_ms 0.997901
    [TIMING ts=20260710-190815] irodori_tts.condition_ms 303.274642
    [TIMING ts=20260710-190815] irodori_tts.sample_rf_ms 91636.71644
    [TIMING ts=20260710-190815] irodori_tts.sample_rf.context_cond_ms 0
    [TIMING ts=20260710-190815] irodori_tts.sample_rf.context_cfg_ms 193.713721
    [TIMING ts=20260710-190815] irodori_tts.sample_rf.steps_cfg_ms 61143.878842
    [TIMING ts=20260710-190815] irodori_tts.sample_rf.steps_cond_ms 30261.685848
    [TIMING ts=20260710-190815] irodori_tts.codec_decode_ms 123585.80524
    [TIMING ts=20260710-190815] session.wall_ms 215535.186862
    [TIMING ts=20260710-190815] cli.run_ms 215535.237849
    [TIMING ts=20260710-190815] cli.emit_output_ms 11.672963
    [TIMING ts=20260710-190815] cli.total_ms 217061.756925
    

    output_audio.wav

  13. bakamomi commented on Jul 11, 2026

    @bakamomi

    I was talking about this text:
    📖🐢衝動は、もはや抑えられなかった。二乃は淹れたての熱いコーヒーが乗ったトレイを掴むと、迷わず男のテーブルへと向かった。
    「😱きゃっ!」
    📖🐢わざとらしく足をもたつかせ、二乃は持っていたトレイを男の膝の上に「うっかり」ひっくり返した。
    「😖熱っ! あ、あつっ!」
    📖🐢安物のスラックスに染み込んでいく熱いコーヒーに、男――ヒロシは悲鳴を上げる。店内の客の視線が一斉に集まる中、二乃は勝 ち誇ったように仁王立ちになり、声を張り上げた。

    It's 220 characters. You posted it as
    cuda_2.wav
    vulkan_2.wav
    python_2.wav

    It's not chunked, but the 🐢 emoji tells the model to speak slowly. On top of that, it needs pauses between narrative and direct speech. Together, these things make text much longer than 30 sec. CrispASR generates 40 seconds for this text.
    Another important note, chunking by character number is very unreliable for Japanese because kanji can unpack to multiple kana characters. As far as I know, Irodori TTS has built-in length predictor (CrispASR uses it to decide how many latent frames to allocate for diffusion) specifically because it's hard to predict text length.

    I don't know what to do about Vulkan issues.

    1. The output I get for "その森には、古い言い伝えがありました。月が最も高く昇る夜、静かに耳を澄ませば、風の歌声が聞こえるというのです。私は半信半疑でしたが、その夜、確かに誰かが私を呼ぶ声を聞いたのです。" is just silence: https://litter.catbox.moe/6kjmpj.wav
    2. Reducing text by one sentence "その森には、古い言い伝えがありました。月が最も高く昇る夜、静かに耳を澄ませば、風の歌声が聞こえるというのです。" produced weird noise: https://litter.catbox.moe/l0abuk.wav
    3. Reducing text further "その森には、古い言い伝えがありました。" produces good output: https://litter.catbox.moe/v1mrkc.wav
      Is there some way to get more debug output?
  14. 0xShug0 commented on Jul 11, 2026

    @0xShug0
    Owner

    @bakamomi Yes. audio.cpp uses duration predictor.

    core::TensorValue build_irodori_duration_predictor(
    . The text chunker is kinda global input preprocessing and applied to most of the TTS models for longform text (additional layer, independent of any model inner methods).

    Does python have the same issue with the same input?

  15. 0xShug0 commented on Jul 11, 2026

    @0xShug0
    Owner

    Also I don't know if this helps, but you can try to force the duration.

    ./audiocpp_cli
    --task tts
    --family irodori_tts
    --model /path/to/Irodori-TTS-500M-v3
    --backend cuda
    --threads 8
    --text "..."
    --option duration_seconds=12.0
    --out out.wav

    duration_seconds: explicit output duration, overrides predicted duration.
    duration_scale: multiplier for the built-in predicted duration.
    min_seconds / max_seconds: clamp the predicted duration.
    

    ./audiocpp_cli --task tts --family irodori_tts --model models/Irodori-TTS-500M-v3 --backend cuda --threads 8 --text "本日はお越しいただき、誠にありがとうございます。どうぞごゆっくりお過ごしください。" --request-option [xxx]=[yyy] --out out.wav

    option output duration
    default predictor 6.520s
    duration_seconds=4.0 4.000s
    duration_scale=0.5 3.280s
    duration_scale=2.0 13.040s
    min_seconds=12.0 12.000s
    max_seconds=3.0 3.000s
  16. 0xShug0 commented on Jul 11, 2026

    @0xShug0
    Owner

    I think you can try different seeds. I tested the official Python implementation with random seeds, and some produced nonsensical output when duration_scale = 0.5. The same happens with audio.cpp.

  17. bakamomi commented on Jul 11, 2026

    @bakamomi

    I tried the duration options. None of them allow setting duration longer than 30 seconds, but that's understandable. The model probably wasn't trained on longer continuous audio. Besides, manual duration setting won't work for automatic TTS.
    The python version also fails to chunk the provided text example. You posted it here python_2.wav It's missing a chunk of text at the end because there is not enough time to say it.
    I guess your implementation follows the reference one. It's up to you if you want to make it better than the reference.

  18. 0xShug0 commented on Jul 11, 2026

    @0xShug0
    Owner

    @bakamomi did you try max seconds?

    {
    "max_seconds": 60,
    "trim_tail": false
    }

    In both audio.cpp and python, 30s is the default cap of duration predictor but can be changed.

  19. bakamomi commented on Jul 11, 2026

    @bakamomi

    Alright. max_seconds works to extend audio, but the result is gibberish. Speech breaks down even if I set max_seconds=35.

  20. 0xShug0 commented on Jul 11, 2026

    @0xShug0
    Owner

    I want to make sure I am not chasing wrong target. Could you please run the failed case with a fixed seed, and share the exact cmd you used and the wav?

  21. bakamomi commented on Jul 11, 2026

    @bakamomi
    ./audiocpp_cli  --task tts --seed 42  --model ../../models/Irodori-TTS-500M-v3 --out output_audio.wav --backend cuda --text "📖🐢衝動は、もはや抑えられなかった。二乃は淹れたての熱いコーヒーが乗ったトレイを掴むと、迷わず男のテーブルへと向かった。 
    「😱きゃっ!」
    📖🐢わざとらしく足をもたつかせ、二乃は持っていたトレイを男の膝の上に「うっかり」ひっくり返した。
    「😖熱っ! あ、あつっ!」
    📖🐢安物のスラックスに染み込んでいく熱いコーヒーに、男――ヒロシは悲鳴を上げる。店内の客の視線が一斉に集まる中、二乃は勝ち誇ったように仁王立ちになり、声を張り上げた。"
    

    Output audio: https://litter.catbox.moe/asl7ka5zb6z2rg30.wav

    Around 0:20, the speech jumps from ひっくり返した。 to 店内の客の視線が一斉に集まる中、二乃は勝ち誇ったように仁王立ちになり、声を張り上げた。 It's missing 「😖熱っ! あ、あつっ!」📖🐢安物のスラックスに染み込んでいく熱いコーヒーに、男――ヒロシは悲鳴を上げる。 The speech uses up all 30 seconds, so clearly the missing part is dropped simply because there is no time for it.

  22. 0xShug0 commented on Jul 11, 2026

    @0xShug0
    Owner

    Thanks. Could you also share (1) any correct WAV output produced by other implementations for this input, along with the command you used (2) the gibberish wav you mentioned in #6 (comment) and the cmd? I’d like to determine whether this is a limitation of the reference Python implementation, a bug in audio.cpp, or a limitation of the model itself.

  23. bakamomi commented on Jul 11, 2026

    @bakamomi
    ./crispasr --backend irodori-tts -m ../../../models/tts/irodori-tts-500m-v3-q8_0.gguf --tts "📖🐢衝動は、もはや抑えられなかった。二乃は淹れたての熱いコーヒーが乗ったトレイを掴むと、迷わず男のテーブルへと向かった。
    「😱きゃっ!」
    📖🐢わざとらしく足をもたつかせ、二乃は持っていたトレイを男の膝の上に「うっかり」ひっくり返した。
    「😖熱っ! あ、あつっ!」
    📖🐢安物のスラックスに染み込んでいく熱いコーヒーに、男――ヒロシは悲鳴を上げる。店内の客の視線が一斉に集まる中、二乃は勝 ち誇ったように仁王立ちになり、声を張り上げた。"
    

    CripsASR can do this. BUT it automatically chunks text into three parts of 11, 11, and 20 seconds (it's visible in console output).
    https://litter.catbox.moe/33mulu.wav

     ./audiocpp_cli  --task tts --seed 42 --request-option duration_seconds=40.0 --request-option max_seconds=40.0  --model ../../models/Irodori-TTS-500M-v3 --out output_audio.wav  --backend cuda  --text "📖🐢衝動 は、もはや抑えられなかった。二乃は淹れたての熱いコーヒーが乗ったトレイを掴むと、迷わず男のテーブルへと向かった。 
    「😱きゃっ!」
    📖🐢わざとらしく足をもたつかせ、二乃は持っていたトレイを男の膝の上に「うっかり」ひっくり返した。
    「😖熱っ! あ、あつっ!」
    📖🐢安物のスラックスに染み込んでいく熱いコーヒーに、男――ヒロシは悲鳴を上げる。店内の客の視線が一斉に集まる中、二乃は勝ち誇ったように仁王立ちになり、声を張り上げた。"
    

    This produced garbled output.

  24. 0xShug0 commented on Jul 11, 2026

    @0xShug0
    Owner

    @bakamomi I think I understand whats going on. Check the latest commit on the dev branch 85d4a65. You can change the default text chunk mode now. The default mode for Irodori is bin packing, and since the budget is 256, it won’t chunk the text. Also I checked CrispASR and it does NOT do duration-based chunking for Irodori. It still uses text chunk, and the 11s / 11s / 20s shown in logs are the generated audio durations after synthesis, not the rule used to split the text.

    ./audiocpp_cli --task tts --request-option text_chunk_mode=endline --model models/Irodori-TTS-500M-v3 --out [xxx] --backend cuda --threads 8 --log --text [xxxx]

    Don't set duration_second.

    TRACE ts=20260711-192114] irodori_tts.config.use_speaker_condition 1
    [TRACE ts=20260711-192114] irodori_tts.config.use_caption_condition 0
    [TRACE ts=20260711-192114] irodori_tts.config.max_text_len 256
    [TRACE ts=20260711-192114] irodori_tts.config.max_caption_len 256
    [TRACE ts=20260711-192114] irodori_tts.chunk.0.text 📖🐢衝動 は、もはや抑えられなかった。二乃は淹れたての熱いコーヒーが乗ったトレイを掴むと、迷わず男のテーブルへと向かった。
    [TRACE ts=20260711-192114] irodori_tts.chunk.0.seed 1752962020
    [TRACE ts=20260711-192114] irodori_tts.condition.graph_rebuild 1
    ggml_backend_cuda_graph_compute: CUDA graph warmup complete
    ggml_backend_cuda_graph_compute: CUDA graph warmup complete
    [TRACE ts=20260711-192114] irodori_tts.codec_decode.graph_rebuild 1
    [TRACE ts=20260711-192114] irodori_tts.chunk.1.text 「😱きゃっ!」\n📖🐢わざとらしく足をもたつかせ、二乃は持っていたトレイを男の膝の上に「うっかり」ひっくり返した。
    [TRACE ts=20260711-192114] irodori_tts.chunk.1.seed 96818758
    [TRACE ts=20260711-192114] irodori_tts.condition.graph_rebuild 1
    ggml_backend_cuda_graph_compute: CUDA graph warmup complete
    ggml_backend_cuda_graph_compute: CUDA graph warmup complete
    [TRACE ts=20260711-192114] irodori_tts.codec_decode.graph_rebuild 1
    [TRACE ts=20260711-192115] irodori_tts.chunk.2.text 「😖熱っ! あ、あつっ!」\n📖🐢安物のスラックスに染み込んでいく熱いコーヒーに、男――ヒロシは悲鳴を上げる。店内の客の視線が一斉に集まる中、二乃は勝ち誇ったように仁王立ちになり、声を張り上げた。
    [TRACE ts=20260711-192115] irodori_tts.chunk.2.seed 3566896950
    [TRACE ts=20260711-192115] irodori_tts.condition.graph_rebuild 1
    ggml_backend_cuda_graph_compute: CUDA graph warmup complete
    ggml_backend_cuda_graph_compute: CUDA graph warmup complete
    [TRACE ts=20260711-192115] irodori_tts.codec_decode.graph_rebuild 1
    [TRACE ts=20260711-192115] irodori_tts.reference.used 0
    [TRACE ts=20260711-192115] irodori_tts.reference.cache_hit 0
    [TRACE ts=20260711-192115] irodori_tts.text_chunk_size 256
    [TRACE ts=20260711-192115] irodori_tts.text_chunk_mode endline
    [TRACE ts=20260711-192115] irodori_tts.text_chunk_count 3
    [TRACE ts=20260711-192115] irodori_tts.sample_rf.context_graph_rebuilds 3
    [TRACE ts=20260711-192115] irodori_tts.sample_rf.step_graph_rebuilds 6
    [TIMING ts=20260711-192115] irodori_tts.prepare_reference_ms 0.00041
    [TIMING ts=20260711-192115] irodori_tts.tokenize_ms 2.168991
    [TIMING ts=20260711-192115] irodori_tts.condition_ms 109.393678
    [TIMING ts=20260711-192115] irodori_tts.sample_rf_ms 897.96661
    [TIMING ts=20260711-192115] irodori_tts.sample_rf.context_cond_ms 0
    [TIMING ts=20260711-192115] irodori_tts.sample_rf.context_cfg_ms 4.215303
    [TIMING ts=20260711-192115] irodori_tts.sample_rf.steps_cfg_ms 564.8458800000001
    [TIMING ts=20260711-192115] irodori_tts.sample_rf.steps_cond_ms 311.6316539999999
    [TIMING ts=20260711-192115] irodori_tts.codec_decode_ms 272.652979
    [TIMING ts=20260711-192115] session.wall_ms 1287.713395
    

    Seed matters because Irodori a stochastic diffusion/flow-matching TTS model. Check the wavs attached. The seeds 2282869626/1935717885/1849449564 (one for each chunk generated randomly) produced garbled output (based on ASR), while other random seeds work better.

    irodori_endline_seed3131938595-2382678063-2557918360.wav
    irodori_endline_seed3026951487-949633697-2041888617.wav
    irodori_endline_seed2282869626-1935717885-1849449564.wav

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    new modelRequest for new model support

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions