Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 228 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ add_library(engine_core OBJECT
src/framework/modules/vocoders/hift_vocoder.cpp
src/framework/modules/speech_encoders/hubert_encoder.cpp
src/framework/modules/speech_encoders/wavlm_encoder.cpp
src/framework/modules/speech_encoders/sanm.cpp
src/framework/modules/optimizations/fast_conv_modules.cpp
src/framework/modules/optimizations/fast_projection_modules.cpp
src/framework/modules/recurrent_modules.cpp
Expand Down Expand Up @@ -311,6 +312,7 @@ add_library(engine_core OBJECT
external/llama_tokenizer/unicode-data.cpp
src/framework/tokenizers/sentencepiece.cpp
src/framework/audio/fft.cpp
src/framework/audio/kaldi_fbank.cpp
src/framework/audio/activity.cpp
src/framework/audio/chunking.cpp
src/framework/audio/conversion.cpp
Expand Down Expand Up @@ -689,6 +691,23 @@ audiocpp_add_model(dramabox
engine::models::dramabox::make_dramabox_loader
)

audiocpp_add_model(fun_asr_nano
SOURCES
src/models/fun_asr_nano/assets.cpp
src/models/fun_asr_nano/frontend.cpp
src/models/fun_asr_nano/encoder.cpp
src/models/fun_asr_nano/adaptor.cpp
src/models/fun_asr_nano/tokenizer_text.cpp
src/models/fun_asr_nano/prompt.cpp
src/models/fun_asr_nano/decoder.cpp
src/models/fun_asr_nano/session.cpp
src/models/fun_asr_nano/loader.cpp
INCLUDES
engine/models/fun_asr_nano/loader.h
LOADERS
engine::models::fun_asr_nano::make_fun_asr_nano_loader
)

audiocpp_add_model(heartmula
SOURCES
src/models/heartmula/assets.cpp
Expand Down Expand Up @@ -1330,6 +1349,7 @@ if (ENGINE_BUILD_WARMBENCH)
add_engine_warmbench(citrinet_asr_warm_bench tests/citrinet_asr/citrinet_asr_warm_bench.cpp)
add_engine_warmbench(confucius4_tts_warm_bench tests/confucius4_tts/confucius4_tts_warm_bench.cpp)
add_engine_warmbench(dramabox_warm_bench tools/dramabox/dramabox_warm_bench.cpp)
add_engine_warmbench(fun_asr_nano_warm_bench tests/fun_asr_nano/fun_asr_nano_warm_bench.cpp)
add_engine_warmbench(higgs_audio_stt_warm_bench tests/higgs_audio_stt/higgs_audio_stt_warm_bench.cpp)
add_engine_warmbench(higgs_audio_tts_warm_bench tests/higgs_audio_tts/higgs_audio_tts_warm_bench.cpp)
add_engine_warmbench(hviske_asr_warm_bench tests/hviske_asr/hviske_asr_warm_bench.cpp)
Expand Down Expand Up @@ -1666,6 +1686,214 @@ if (ENGINE_BUILD_TESTS)
COMMAND model_spec_system_test
)

add_engine_unittest(fun_asr_nano_assets_test tests/unittests/test_fun_asr_nano_assets.cpp)
target_sources(fun_asr_nano_assets_test PRIVATE src/models/fun_asr_nano/assets.cpp)
target_include_directories(fun_asr_nano_assets_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/unittests)

add_test(
NAME fun_asr_nano_assets_test
COMMAND fun_asr_nano_assets_test
)

add_engine_unittest(fun_asr_nano_frontend_probe tests/fun_asr_nano/fun_asr_nano_frontend_probe.cpp)

add_test(
NAME fun_asr_nano_frontend_probe
COMMAND fun_asr_nano_frontend_probe
${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/frontend_reference.json
${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/frontend_reference.bin
${CMAKE_CURRENT_SOURCE_DIR}/assets/resources/sample_16k.wav
)

add_engine_unittest(fun_asr_nano_sanm_probe tests/fun_asr_nano/sanm_probe.cpp)

add_test(
NAME fun_asr_nano_sanm_probe
COMMAND fun_asr_nano_sanm_probe
--backend cpu
--reference ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/sanm_reference.json
--data ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/sanm_reference.bin
)

add_engine_unittest(fun_asr_nano_encoder_probe tests/fun_asr_nano/fun_asr_nano_encoder_probe.cpp)
target_sources(
fun_asr_nano_encoder_probe
PRIVATE
src/models/fun_asr_nano/assets.cpp
src/models/fun_asr_nano/frontend.cpp
src/models/fun_asr_nano/encoder.cpp
)
set(
AUDIOCPP_FUN_ASR_NANO_TEST_MODEL
""
CACHE PATH
"Optional local Fun-ASR-Nano model directory for full runtime parity tests"
)
set(
AUDIOCPP_FUN_ASR_NANO_TEST_GGUF
""
CACHE FILEPATH
"Optional standalone Fun-ASR-Nano GGUF for full CLI transcript tests"
)
if (AUDIOCPP_FUN_ASR_NANO_TEST_MODEL)
add_test(
NAME fun_asr_nano_encoder_probe_cpu
COMMAND fun_asr_nano_encoder_probe
--backend cpu
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_MODEL}
--reference ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/encoder_reference.json
--data ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/encoder_reference.bin
)
if (GGML_CUDA)
add_test(
NAME fun_asr_nano_encoder_probe_cuda
COMMAND fun_asr_nano_encoder_probe
--backend cuda
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_MODEL}
--reference ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/encoder_reference.json
--data ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/encoder_reference.bin
)
endif()

add_engine_unittest(fun_asr_nano_session_probe tests/fun_asr_nano/fun_asr_nano_session_probe.cpp)
add_test(
NAME fun_asr_nano_session_probe_cpu
COMMAND fun_asr_nano_session_probe
--backend cpu
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_MODEL}
--audio ${CMAKE_CURRENT_SOURCE_DIR}/assets/resources/sample_16k.wav
)
if (GGML_CUDA)
add_test(
NAME fun_asr_nano_session_probe_cuda
COMMAND fun_asr_nano_session_probe
--backend cuda
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_MODEL}
--audio ${CMAKE_CURRENT_SOURCE_DIR}/assets/resources/sample_16k.wav
)
endif()
endif()
if (AUDIOCPP_FUN_ASR_NANO_TEST_GGUF)
add_test(
NAME fun_asr_nano_gguf_cli_cpu
COMMAND audiocpp_cli
--task asr
--family fun_asr_nano
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_GGUF}
--backend cpu
--audio ${CMAKE_CURRENT_SOURCE_DIR}/assets/resources/sample_16k.wav
)
set_tests_properties(
fun_asr_nano_gguf_cli_cpu
PROPERTIES PASS_REGULAR_EXPRESSION
"text_output=Some call me nature, others call me mother nature"
)
if (GGML_CUDA)
add_test(
NAME fun_asr_nano_gguf_cli_cuda
COMMAND audiocpp_cli
--task asr
--family fun_asr_nano
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_GGUF}
--backend cuda
--audio ${CMAKE_CURRENT_SOURCE_DIR}/assets/resources/sample_16k.wav
)
set_tests_properties(
fun_asr_nano_gguf_cli_cuda
PROPERTIES PASS_REGULAR_EXPRESSION
"text_output=Some call me nature, others call me mother nature"
)
add_test(
NAME fun_asr_nano_gguf_cli_cuda_shared_q8
COMMAND audiocpp_cli
--task asr
--family fun_asr_nano
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_GGUF}
--backend cuda
--session-option fun_asr_nano.weight_type=q8_0
--audio ${CMAKE_CURRENT_SOURCE_DIR}/assets/resources/sample_16k.wav
)
set_tests_properties(
fun_asr_nano_gguf_cli_cuda_shared_q8
PROPERTIES PASS_REGULAR_EXPRESSION
"text_output=Some call me nature, others call me mother nature"
)
add_test(
NAME fun_asr_nano_gguf_cli_best_shared_q8
COMMAND audiocpp_cli
--task asr
--family fun_asr_nano
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_GGUF}
--backend best
--session-option fun_asr_nano.weight_type=q8_0
--audio ${CMAKE_CURRENT_SOURCE_DIR}/assets/resources/sample_16k.wav
)
set_tests_properties(
fun_asr_nano_gguf_cli_best_shared_q8
PROPERTIES PASS_REGULAR_EXPRESSION
"text_output=Some call me nature, others call me mother nature"
)
endif()
endif()

add_engine_unittest(fun_asr_nano_adaptor_probe tests/fun_asr_nano/fun_asr_nano_adaptor_probe.cpp)
target_sources(
fun_asr_nano_adaptor_probe
PRIVATE
src/models/fun_asr_nano/assets.cpp
src/models/fun_asr_nano/adaptor.cpp
)
if (AUDIOCPP_FUN_ASR_NANO_TEST_MODEL)
add_test(
NAME fun_asr_nano_adaptor_probe_cpu
COMMAND fun_asr_nano_adaptor_probe
--backend cpu
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_MODEL}
--reference ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/adaptor_reference.json
--data ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/adaptor_reference.bin
)
if (GGML_CUDA)
add_test(
NAME fun_asr_nano_adaptor_probe_cuda
COMMAND fun_asr_nano_adaptor_probe
--backend cuda
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_MODEL}
--reference ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/adaptor_reference.json
--data ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/adaptor_reference.bin
)
endif()
endif()

add_engine_unittest(fun_asr_nano_decoder_probe tests/fun_asr_nano/fun_asr_nano_decoder_probe.cpp)
target_sources(
fun_asr_nano_decoder_probe
PRIVATE
src/models/fun_asr_nano/assets.cpp
src/models/fun_asr_nano/tokenizer_text.cpp
src/models/fun_asr_nano/prompt.cpp
src/models/fun_asr_nano/decoder.cpp
)
if (AUDIOCPP_FUN_ASR_NANO_TEST_MODEL)
add_test(
NAME fun_asr_nano_decoder_probe_cpu
COMMAND fun_asr_nano_decoder_probe
--backend cpu
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_MODEL}
--reference ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/decoder_reference.json
--data ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/decoder_reference.bin
)
if (GGML_CUDA)
add_test(
NAME fun_asr_nano_decoder_probe_cuda
COMMAND fun_asr_nano_decoder_probe
--backend cuda
--model ${AUDIOCPP_FUN_ASR_NANO_TEST_MODEL}
--reference ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/decoder_reference.json
--data ${CMAKE_CURRENT_SOURCE_DIR}/tests/fun_asr_nano/decoder_reference.bin
)
endif()
endif()

add_engine_unittest(tdt_decoder_duration_loop_test tests/unittests/test_tdt_decoder_duration_loop.cpp)
target_include_directories(tdt_decoder_duration_loop_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/unittests)

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Runtime tags: safetensors is the default model loading path. `GGUF 16/Q8/Q4` mea
| **chatterbox** | TTS, Clone, VC| ar, da, de, el, en, es, fi, fr, hi, it, ko, ms, nl, no, pl, pt, sv, sw, tr | Chatterbox with 0.5B backbone | GGUF 16/Q8 |
| **citrinet_asr** | ASR | en | Citrinet-256 | GGUF Q8 |
| **fish_audio** | TTS, Clone, Ctrl | auto, en, zh | Fish Audio S2 Pro | GGUF 16/Q8 |
| **fun_asr_nano** | ASR | auto, zh, en, ja | Fun-ASR-Nano-2512 | GGUF 16/Q8 |
| **heartmula** | Music | zh, en, ja, ko, es | HeartMuLa-oss-3B with HeartCodec-oss | GGUF 16/Q8 |
| **higgs_audio_stt** | ASR | en | Higgs Audio v3 STT | GGUF 16/Q8, Stream |
| **higgs_audio_tts** | TTS, Clone, Ctrl | auto | Higgs Audio v3 TTS 4B | GGUF 16/Q8 |
Expand Down
19 changes: 19 additions & 0 deletions docs/asr.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

| Model | Family | Mode(s) | Quick Start |
|---|---|---|---|
| Fun-ASR-Nano | `fun_asr_nano` | offline | [Fun-ASR-Nano](#fun-asr-nano) |
| Qwen3 ASR | `qwen3_asr` | offline | [Qwen3 ASR](#qwen3-asr) |
| Citrinet ASR | `citrinet_asr` | offline | [Citrinet ASR](#citrinet-asr) |
| Kroko Community ASR | `kroko_asr` | offline, streaming | [Kroko Community ASR](#kroko-community-asr) |
Expand All @@ -21,6 +22,24 @@ audiocpp_cli --task asr --family <family> --model <model-dir> --backend cuda --a

When `--mode streaming` is used, the selected model provides its default streaming policy.

## Fun-ASR-Nano

Fun-ASR-Nano provides offline multilingual transcription for Chinese, English,
and Japanese with automatic language selection. The recommended package is the
standalone Q8_0 GGUF published by FunAudioLLM.

```bash
python3 tools/model_manager_v2.py install fun_asr_nano
audiocpp_cli --task asr --family fun_asr_nano \
--model models/Fun-ASR-Nano-2512-GGUF/fun-asr-nano-2512-q8_0.gguf \
--backend cuda --audio speech_16k.wav --text-out transcript.txt
```

The runtime supports fixed offline chunking and inverse text normalization.
Streaming and timestamp output are not exposed. See the
[Fun-ASR-Nano model guide](models/fun_asr_nano.md) for package, option, GGUF,
and server details.

## Qwen3 ASR

Qwen3 ASR transcribes speech and can be paired with Qwen3 Forced Aligner when timestamps are needed. See [Qwen3 models](models/qwen3.md) for the full ASR and alignment manual.
Expand Down
1 change: 1 addition & 0 deletions docs/gguf.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Status labels:
| `chatterbox` | Done | Pass | --- | Pass (ASR match, drift) | Pass (ASR match, drift) |
| `citrinet_asr` | Done | Pass | --- | --- | Pass |
| `fish_audio` | Done | Pass | --- | Pass | Pass |
| `fun_asr_nano` | Done | Pass | --- | Pass | Pass |
| `glm_tts` | Done | Pass (TTS + clone) | --- | --- | Pass (ASR match, drift) |
| `heartmula` | Done | Pass | --- | Pass (drift) | Pass (drift) |
| `higgs_audio_stt` | Done | Pass | --- | Pass | Pass |
Expand Down
3 changes: 3 additions & 0 deletions docs/model_manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ If a model has a ready-to-use GGUF package, prefer that route first.
Ready-to-use GGUF packages are published here:

- Core released models: [audio-cpp/audio.cpp-gguf](https://huggingface.co/audio-cpp/audio.cpp-gguf)
- Fun-ASR-Nano: [FunAudioLLM/Fun-ASR-Nano-2512-GGUF](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512-GGUF)
- Community OuteTTS package: [mirek190/audio.cpp](https://huggingface.co/mirek190/audio.cpp/tree/main/Text%20to%20audio%20(TTS))

For support status and tested precision coverage, see the [GGUF guide](gguf.md).
Expand Down Expand Up @@ -112,6 +113,8 @@ Packages whose loaders are not registered in the current release tree are listed
| `chatterbox` | Chatterbox | **Yes** |
| `citrinet_asr` | Citrinet ASR converted layout | No |
| `fish_audio_s2_pro` | Fish Audio S2 Pro GGUF Q8_0 | **Yes** |
| `fun_asr_nano_2512_f16` | Fun-ASR-Nano-2512 F16 GGUF | **Yes** |
| `fun_asr_nano_2512_q8_0` | Fun-ASR-Nano-2512 Q8_0 GGUF | **Yes** |
| `glm_tts` | GLM-TTS with converted Flow/HiFT/tokenizer and CAMPPlus assets | No |
| `heartmula` | HeartMuLa | No |
| `higgs_audio_stt` | Higgs Audio STT | No |
Expand Down
Loading
Loading