Skip to content

Commit 43b5ca7

Browse files
authored
feat: Adds Python demo for ONNX using C++/C source (#61)
* Adds Python demo for ONNX using C++/C source Uses Python bindings for TEN VAD C++/C source code and ONNX Runtime. This Python extension module provides a faithful, high-quality interface to the TEN VAD C/C++ library including front-end ptch estimation. Python build and demo scripts have same functionality as existing C demo. The `is_voice` flags are identical for the same test WAV file. The tiny probability differences observed (6×10⁻⁸ mean difference) are due to floating-point representation nuances and will have zero practical impact on VAD performance. It runs 2.6x slower than existing compiled C demo. Tested on ARM64 with Ubuntu 24.04.2 LTS. * Fix architecture name for onnxruntime on x86_64 Use `x64` not `x86_64` for onnxruntime download link. Tested on Intel i5 CPU. * Add documentation for ONNX Runtime usage The build process and demo depends on external ONNX Runtime. Existing documentation needed a fix and clarification. * Renames `build-linux-python` folder Preparing for macOS build. * Separates concerns and adds macOS C++ build Refactors C++ and Python builds into separate folders for separation of concerns. Add macOS C++ build tested on arm64 and x86_64 architectures. Expands documentation in `examples_onnx/README.md` for C++ build and Python bindings build for Linux and macOS. Updates top level README. Adds headers to source files. * Fix README for Python demo usage Numpy is needed for audio data handling and available in the build generated virtual environment. Does not affect build script which activates this virtual environment.
1 parent feea265 commit 43b5ca7

File tree

12 files changed

+908
-24
lines changed

12 files changed

+908
-24
lines changed

.gitignore

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ examples/build-android/
44
examples/build-linux/
55
examples/build-windows/
66
examples/build-web/
7-
examples_onnx/build-linux
7+
examples_onnx/cpp/build-linux
8+
examples_onnx/cpp/build-macos
89
include/.DS_Store
910
lib/.DS_Store
1011
examples/.DS_Store
@@ -13,6 +14,6 @@ include/__pycache__/
1314
__pycache__/
1415
examples/out.txt
1516
.DS_Store
16-
17-
18-
17+
# Python extension module for TEN VAD C++/C and ONNX runtime.
18+
examples_onnx/python/build-linux
19+
examples_onnx/python/build-macos

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ We evaluated the RTF (Real-Time Factor) across five distinct platforms, each equ
210210
<tr>
211211
<td> iPhone8 (A11) </td>
212212
<td align="center"> 0.0050 </td>
213-
</tr>
213+
</tr>
214214
</table>
215215
<br>
216216

@@ -561,13 +561,15 @@ You have to download the **onnxruntime** packages from the [microsoft official o
561561
You can check the official **ONNX Runtime releases** from [this website](https://github.com/microsoft/onnxruntime/tags). And for example, to download version 1.17.1 (Linux x64), use [this link](https://github.com/microsoft/onnxruntime/releases/download/v1.17.1/onnxruntime-linux-x64-1.17.1.tgz). After extracting the compressed file, you'll find two important directories:`include/` - header files, `lib/` - library files
562562

563563
```
564-
1) cd examples_onnx/
564+
1) cd examples_onnx/cpp
565565
2) ./build-and-deploy-linux.sh --ort-path /absolute/path/to/your/onnxruntime/root/dir
566566
```
567567

568568
**Note 1**: If executing the onnx demo from a different directory than the one used when running build-and-deploy-linux.sh, ensure to create a symbolic link to src/onnx_model/ to prevent ONNX model file loading failures.
569569
<br>
570570
**Note 2**: The **ONNX model** locates in `src/onnx_model` directory.
571+
<br>
572+
**Note 3**: For ONNX example builds see [examples_onnx/README.md](/examples_onnx/README.md).
571573

572574
<br>
573575

examples_onnx/CMakeLists.txt

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,32 @@
44
# Licensed under the Apache License, Version 2.0, with certain conditions.
55
# Refer to the "LICENSE" file in the root directory for more information.
66
#
7-
cmake_minimum_required(VERSION 3.10)
8-
get_filename_component(ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../ ABSOLUTE)
7+
# Root CMakeLists.txt for TEN VAD ONNX examples
8+
# Supports building either C++ demo or Python bindings
99

10-
project(ten_vad)
10+
cmake_minimum_required(VERSION 3.12)
11+
project(ten_vad_examples)
1112

12-
set(CMAKE_BUILD_TYPE Release)
13-
add_compile_options(-Wno-write-strings -Wno-unused-result)
14-
include_directories(${ROOT}/src)
15-
include_directories(${ROOT}/include)
16-
include_directories(${ORT_ROOT}/include)
17-
file(GLOB LIBRARY_SOURCES "${ROOT}/src/*.cc" "${ROOT}/src/*.c")
18-
add_library(ten_vad SHARED ${LIBRARY_SOURCES})
19-
link_directories(${ORT_ROOT}/lib)
20-
target_link_libraries(ten_vad "${ORT_ROOT}/lib/libonnxruntime.so")
13+
# Build options
14+
option(BUILD_CPP_DEMO "Build C++ demo executable" ON)
15+
option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF)
2116

22-
set(EXECUTABLE_SOURCES ${ROOT}/examples/main.c)
23-
add_executable(ten_vad_demo ${EXECUTABLE_SOURCES})
24-
target_link_libraries(ten_vad_demo ten_vad)
17+
# Ensure only one target is built at a time
18+
if(BUILD_CPP_DEMO AND BUILD_PYTHON_BINDINGS)
19+
message(FATAL_ERROR "Cannot build both targets simultaneously. Choose either BUILD_CPP_DEMO or BUILD_PYTHON_BINDINGS.")
20+
endif()
21+
22+
if(NOT BUILD_CPP_DEMO AND NOT BUILD_PYTHON_BINDINGS)
23+
message(FATAL_ERROR "At least one target must be enabled. Set BUILD_CPP_DEMO=ON or BUILD_PYTHON_BINDINGS=ON.")
24+
endif()
25+
26+
# Build the selected target
27+
if(BUILD_CPP_DEMO)
28+
message(STATUS "Building C++ demo")
29+
add_subdirectory(cpp)
30+
endif()
31+
32+
if(BUILD_PYTHON_BINDINGS)
33+
message(STATUS "Building Python bindings")
34+
add_subdirectory(python)
35+
endif()

examples_onnx/README.md

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
# TEN VAD ONNX Examples
2+
3+
This directory contains examples for building and using TEN VAD with ONNX
4+
Runtime support. Follow the setup guide below to get started from scratch.
5+
6+
## 📋 Prerequisites & Setup
7+
8+
Follow these steps in order to set up your environment from nothing.
9+
10+
Test environments used for preparing this README.
11+
* ONNX Runtime 1.22.0
12+
* Python 3.12
13+
* Linux: Ubuntu 24.04 LTS on ARM64 (native) and x86_64 (VM)
14+
* macOS: Sequoia 15.6 on arm64 (native) and x86_64 (native)
15+
16+
### Step 1: Install System Dependencies
17+
18+
**Linux**
19+
```bash
20+
sudo apt update
21+
sudo apt install cmake build-essential python3-venv curl
22+
```
23+
24+
**macOS**
25+
Install brew from [brew.sh](https://brew.sh). In a new terminal session install
26+
`cmake`.
27+
```bash
28+
brew install cmake
29+
```
30+
31+
### Step 2: Download ONNX Runtime
32+
33+
Choose your platform and architecture, then download ONNX Runtime to your home
34+
directory:
35+
36+
```bash
37+
cd
38+
# Set your ONNX Runtime version
39+
ONNX_VER=1.22.0 # v1.17.1+
40+
41+
# Linux
42+
ARCH=$(uname -m) && if [ "$ARCH" = "x86_64" ]; then ARCH="x64"; fi
43+
curl -OL https://github.com/microsoft/onnxruntime/releases/download/v$ONNX_VER/onnxruntime-linux-$ARCH-$ONNX_VER.tgz
44+
tar -xzf onnxruntime-linux-$ARCH-$ONNX_VER.tgz
45+
46+
# macOS
47+
ARCH=$(uname -m) && if ! [ "$ARCH" = "x86_64" ]; then ARCH="arm64"; fi
48+
curl -OL https://github.com/microsoft/onnxruntime/releases/download/v$ONNX_VER/onnxruntime-osx-$ARCH-$ONNX_VER.tgz
49+
tar -xzf onnxruntime-osx-$ARCH-$ONNX_VER.tgz
50+
```
51+
52+
Delete the `tgz` file if needed.
53+
54+
#### ONNX Runtime v1.22.0 package folders
55+
56+
| Platform | Architecture | Package Name |
57+
|----------|----------------------------|------------------------------------|
58+
| Linux | x86_64 | `onnxruntime-linux-x64-1.22.0` |
59+
| Linux | ARM64 | `onnxruntime-linux-aarch64-1.22.0` |
60+
| macOS | Intel | `onnxruntime-osx-x86_64-1.22.0` |
61+
| macOS | Apple Silicon | `onnxruntime-osx-arm64-1.22.0` |
62+
63+
## 🚀 Build Instructions
64+
65+
First navigate into the cloned TEN VAD repo.
66+
```bash
67+
cd
68+
cd ten-vad/examples_onnx
69+
```
70+
71+
Now that dependencies are installed, choose your platform and build type.
72+
73+
### Linux
74+
75+
#### C++ Demo
76+
Build a standalone C++ executable that uses ONNX Runtime directly.
77+
78+
```bash
79+
cd cpp
80+
./build-and-deploy-linux.sh --ort-path ~/onnxruntime-linux-$ARCH-$ONNX_VER
81+
```
82+
83+
**Output**: `cpp/build-linux/ten_vad_demo`
84+
85+
#### Python Extension Module
86+
Build a Python extension module with pybind11 bindings.
87+
88+
```bash
89+
cd python
90+
./build-and-deploy-linux.sh --ort-path ~/onnxruntime-linux-$ARCH-$ONNX_VER
91+
```
92+
93+
**Output** on ARM64: `python/build-linux/lib/ten_vad_python.cpython-312-aarch64-linux-gnu.so`
94+
95+
**Output** on X86_64: `python/build-linux/lib/ten_vad_python.cpython-312-x86_64-linux-gnu.so`
96+
97+
### macOS
98+
99+
#### C++ Demo
100+
Build a standalone C++ executable that uses ONNX Runtime directly.
101+
```bash
102+
cd cpp
103+
./build-and-deploy-macos.sh --ort-path ~/onnxruntime-osx-$ARCH-$ONNX_VER
104+
```
105+
106+
**Output**: `cpp/build-macos/ten_vad_demo`
107+
108+
#### Python Extension Module
109+
110+
Build a Python extension module optimized for macOS (supports both Intel and
111+
Apple Silicon).
112+
113+
```bash
114+
cd python
115+
./build-and-deploy-macos.sh --ort-path ~/onnxruntime-osx-$ARCH-$ONNX_VER
116+
```
117+
118+
**Output**: `python/build-macos/lib/ten_vad_python.*.so`
119+
120+
## Demo Usage
121+
122+
### C++ Demo
123+
From the build directory, run the demo executable:
124+
125+
```bash
126+
# Linux
127+
cd cpp/build-linux
128+
./ten_vad_demo ../../../examples/s0724-s0730.wav out-cpp.txt
129+
130+
# macOS
131+
cd cpp/build-macos
132+
./ten_vad_demo ../../../examples/s0724-s0730.wav out-cpp.txt
133+
```
134+
135+
### Python Extension Module
136+
From the build directory, run the Python demo:
137+
138+
```bash
139+
# Linux
140+
cd python/build-linux
141+
source ./venv/bin/activate # For numpy
142+
python3 ten_vad_demo.py ../../../examples/s0724-s0730.wav out-python.txt
143+
144+
# macOS
145+
cd python/build-macos
146+
source ./venv/bin/activate # For numpy
147+
python3 ten_vad_demo.py ../../../examples/s0724-s0730.wav out-python.txt
148+
149+
# With custom threshold on either Linux or macOS.
150+
python3 ten_vad_demo.py ../../../examples/s0724-s0730.wav out-custom.txt --threshold 0.6
151+
```
152+
153+
**Note**: Both demos process the same input WAV file and output frames where
154+
voice activity is detected.
155+
156+
## 📊 Performance Comparison
157+
158+
### Output Comparison of Python Extension Module and Compiled C
159+
160+
The C++ demo and Python extension module process the same WAV file with nearly
161+
identical results:
162+
163+
**Accuracy Analysis:**
164+
1. **Voice Activity Detection**: `is_voice` flags are identical for all 476 frames
165+
2. **Probability Values**: 440 frames (92.4%) have identical probabilities; 36 frames (7.6%) differ only in the 6th decimal place
166+
167+
```console
168+
Python: [35] 0.728302, 1 vs C: [35] 0.728301, 1 (diff: 0.000001)
169+
Python: [42] 0.901945, 1 vs C: [42] 0.901944, 1 (diff: 0.000001)
170+
Python: [54] 0.585849, 1 vs C: [54] 0.585848, 1 (diff: 0.000001)
171+
```
172+
173+
3. **Precision**: Differences are in the 7th-8th decimal place (mean: 6 × 10⁻⁸, max: 5.9 × 10⁻⁷)
174+
175+
**Conclusion**: These tiny differences have no functional impact. The Python
176+
extension provides a faithful, high-quality interface to the TEN VAD C/C++
177+
library.
178+
179+
### Real-time Factor (RTF) Comparison
180+
181+
Performance test on ARM CPU (Orange Pi 5 8-core ARM64 RockChip RK3588S):
182+
183+
| Method | Time (ms) | Audio (ms) | RTF |
184+
|-------------------------|:---------:|:----------:|:--------:|
185+
| C++ Demo | 74.0 | 7631 | 0.009697 |
186+
| Python Extension Module | 192.5 | 7631 | 0.025222 |
187+
188+
The C++ demo is 2.6x faster than the Python extension module. For
189+
latency-critical applications, choose the compiled C++ version.
190+
191+
## 🐍 Python Usage
192+
193+
Example for macOS.
194+
```python
195+
import sys
196+
import numpy as np
197+
198+
# Add the built module to path
199+
sys.path.insert(0, "python/build-macos/lib") # macOS
200+
# sys.path.insert(0, "python/build-linux-python/lib") # Linux
201+
202+
import ten_vad_python
203+
204+
# Create VAD instance
205+
vad = ten_vad_python.VAD(hop_size=256, threshold=0.5)
206+
207+
# Process audio frame (must be exactly hop_size samples)
208+
audio_frame = np.array([...], dtype=np.int16) # 256 samples
209+
probability, is_voice = vad.process(audio_frame)
210+
211+
print(f"Voice probability: {probability:.6f}")
212+
print(f"Is voice: {is_voice}")
213+
```
214+
215+
## 📁 Project Structure
216+
217+
```
218+
examples_onnx/
219+
├── README.md # This file
220+
├── CMakeLists.txt # Root build configuration
221+
├── cpp/ # C++ demo (Linux + macOS)
222+
│ ├── CMakeLists.txt
223+
│ ├── build-and-deploy-linux.sh
224+
│ └── build-and-deploy-macos.sh
225+
├── python/ # Python extension (Linux + macOS)
226+
│ ├── CMakeLists.txt
227+
│ ├── build-and-deploy-linux-python.sh
228+
│ └── build-and-deploy-macos.sh
229+
├── ten_vad_demo.py # Python demo script
230+
└── ten_vad_python.cc # pybind11 wrapper
231+
```
232+
233+
## Build notes
234+
235+
### Environment Detection
236+
- **Python Version**: Automatically uses your active Python (supports pyenv)
237+
- **Architecture**: Auto-detects x86_64/ARM64 for ONNX Runtime selection
238+
- **Platform**: Automatically configures for Linux/macOS differences
239+
240+
### Troubleshooting
241+
242+
**Python Import Error**: Ensure the module is in your Python path and built for
243+
the correct Python version. Numpy is needed for WAV audio handling.
244+
245+
**ONNX Runtime Not Found**: Verify the `--ort-path` points to a valid ONNX
246+
Runtime installation with `lib/` and `include/` directories.
247+
248+
**Architecture Mismatch**: Ensure your ONNX Runtime package matches your system
249+
architecture.
250+
251+
**Permission Denied**: Make sure build scripts are executable: `chmod +x *.sh`
252+
253+
## 📖 Additional Resources
254+
255+
- [Main TEN VAD Repository](../../README.md)
256+
- [ONNX Runtime Releases](https://github.com/microsoft/onnxruntime/releases)
257+
- [TEN VAD Python Examples](ten_vad_demo.py)
258+
259+
---

examples_onnx/cpp/CMakeLists.txt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#
2+
# Copyright © 2025 Agora
3+
# This file is part of TEN Framework, an open source project.
4+
# Licensed under the Apache License, Version 2.0, with certain conditions.
5+
# Refer to the "LICENSE" file in the root directory for more information.
6+
#
7+
# CMakeList for TEN VAD C++ demo with ONNX Runtime
8+
cmake_minimum_required(VERSION 3.10)
9+
get_filename_component(ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../ ABSOLUTE)
10+
11+
project(ten_vad)
12+
13+
set(CMAKE_CXX_STANDARD 14)
14+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
15+
set(CMAKE_BUILD_TYPE Release)
16+
add_compile_options(-Wno-write-strings -Wno-unused-result)
17+
include_directories(${ROOT}/src)
18+
include_directories(${ROOT}/include)
19+
include_directories(${ORT_ROOT}/include)
20+
file(GLOB LIBRARY_SOURCES "${ROOT}/src/*.cc" "${ROOT}/src/*.c")
21+
add_library(ten_vad SHARED ${LIBRARY_SOURCES})
22+
link_directories(${ORT_ROOT}/lib)
23+
24+
# Platform-specific ONNX Runtime linking
25+
if(APPLE)
26+
target_link_libraries(ten_vad "${ORT_ROOT}/lib/libonnxruntime.dylib")
27+
# Set rpath for macOS
28+
set_target_properties(ten_vad PROPERTIES
29+
INSTALL_RPATH "${ORT_ROOT}/lib"
30+
BUILD_WITH_INSTALL_RPATH TRUE
31+
)
32+
else()
33+
target_link_libraries(ten_vad "${ORT_ROOT}/lib/libonnxruntime.so")
34+
endif()
35+
36+
set(EXECUTABLE_SOURCES ${ROOT}/examples/main.c)
37+
add_executable(ten_vad_demo ${EXECUTABLE_SOURCES})
38+
target_link_libraries(ten_vad_demo ten_vad)

0 commit comments

Comments
 (0)