├── .github └── workflows │ ├── publish.yml │ └── test.yml ├── .gitignore ├── .gitmodules ├── .vscode ├── c_cpp_properties.json └── settings.json ├── BUILDING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── crates └── knf-rs │ ├── .gitignore │ ├── BUILDING.md │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── src │ └── lib.rs │ └── sys │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ ├── knfc │ ├── CMakeLists.txt │ ├── knfc.cc │ └── knfc.h │ ├── src │ └── lib.rs │ └── wrapper.hpp ├── examples ├── infinite.rs ├── max_speakers.rs └── save_segments.rs └── src ├── embedding.rs ├── identify.rs ├── lib.rs ├── segment.rs ├── session.rs └── wav.rs /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Crate 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | release: 14 | runs-on: macos-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | submodules: "true" 19 | 20 | - uses: Swatinem/rust-cache@v2 21 | 22 | - uses: actions-rs/toolchain@v1 23 | with: 24 | toolchain: stable 25 | override: true 26 | 27 | # Publish 28 | - name: Publish 29 | run: | 30 | cargo publish -p knf-rs-sys :: | 31 | cargo publish -p knf-rs :: | 32 | cargo publish -p pyannote-rs 33 | env: 34 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 35 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | build_debug: 7 | required: false 8 | default: "0" 9 | cmake_verbose: 10 | required: false 11 | default: "" 12 | cargo_args: 13 | required: false 14 | default: "" 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | test: 21 | runs-on: ${{ matrix.platform }} 22 | env: 23 | BUILD_DEBUG: ${{ github.event.inputs.build_debug }} 24 | CMAKE_VERBOSE: ${{ github.event.inputs.cmake_verbose }} 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | include: 29 | - platform: "macos-latest" # ARM 30 | options: "" 31 | 32 | - platform: "macos-latest" # Intel 33 | options: "--target x86_64-apple-darwin" 34 | 35 | - platform: "ubuntu-22.04" # Linux 36 | options: "" 37 | 38 | - platform: "windows-latest" # Windows 39 | options: "" 40 | 41 | steps: 42 | - uses: actions/checkout@v3 43 | with: 44 | submodules: "true" 45 | 46 | - name: Cache Rust 47 | uses: Swatinem/rust-cache@v2 48 | 49 | - name: Setup Rust 50 | uses: dtolnay/rust-toolchain@stable 51 | with: 52 | # Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds. 53 | targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} 54 | 55 | - name: Build 56 | run: | 57 | cargo build ${{ matrix.options }} ${{ github.event.inputs.cargo_args }} 58 | 59 | - name: Test 60 | run: | 61 | cargo test ${{ matrix.options }} ${{ github.event.inputs.cargo_args }} -- --nocapture 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | build/ 3 | *.onnx 4 | *.wav -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "crates/knf-rs/sys/knf"] 2 | path = crates/knf-rs/sys/knf 3 | url = https://github.com/csukuangfj/kaldi-native-fbank 4 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "${workspaceFolder}/crates/knf-rs//**", 7 | "${workspaceFolder}/crates/knf-rs/sys/knf/kaldi-native-fbank/csrc/**", 8 | "${workspaceFolder}/crates/knf-rs/sys/knf/kaldi-native-fbank/**" 9 | ], 10 | "defines": [], 11 | "macFrameworkPath": [ 12 | "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk/System/Library/Frameworks" 13 | ], 14 | "compilerPath": "/opt/homebrew/opt/llvm/bin/clang", 15 | "cStandard": "c17", 16 | "cppStandard": "c++17", 17 | "intelliSenseMode": "macos-clang-arm64" 18 | } 19 | ], 20 | "version": 4 21 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnPaste": true, 3 | "editor.formatOnSave": true, 4 | "rust-analyzer.check.command": "clippy", 5 | "clangd.fallbackFlags": [ 6 | "-I${workspaceFolder}/crates/knf-rs/sys/knf/kaldi-native-fbank/csrc", 7 | ] 8 | } -------------------------------------------------------------------------------- /BUILDING.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | ### Prerequisites 4 | 5 | [Cargo](https://www.rust-lang.org/tools/install) | [Clang](https://releases.llvm.org/download.html) | [Cmake](https://cmake.org/download/) 6 | 7 | _Prepare repo (or use cargo add)_ 8 | 9 | ```console 10 | git clone https://github.com/thewh1teagle/pyannote-rs --recursive 11 | ``` 12 | 13 | _Prepare models_ 14 | 15 | ```console 16 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/segmentation-3.0.onnx 17 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/wespeaker_en_voxceleb_CAM++.onnx 18 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/6_speakers.wav 19 | ``` 20 | 21 | _Build Example_ 22 | 23 | ```console 24 | cargo run --example diarize 6_speakers.wav 25 | ``` 26 | 27 | _Gotachas_ 28 | 29 | --- 30 | 31 |
32 | Static linking failed on Windows 33 | 34 | You can resolve it by creating `.cargo/config.toml` next to `Cargo.toml` with the following: 35 | 36 | ```toml 37 | [target.'cfg(windows)'] 38 | rustflags = ["-C target-feature=+crt-static"] 39 | ``` 40 | 41 | Or set the environment variable `RUSTFLAGS` to `-C target-feature=+crt-static` 42 | 43 | If it doesn't help make sure all of your dependencies also links MSVC runtime statically. 44 | You can inspect the build with the following: 45 | 46 | 1. Set `RUSTC_LOG` to `rustc_codegen_ssa::back::link=info` 47 | 2. Build with 48 | 49 | ```console 50 | cargo build -vv 51 | ``` 52 | 53 | Since there's a lot of output, it's good idea to pipe it to file and check later: 54 | 55 | ```console 56 | cargo build -vv >log.txt 2>&1 57 | ``` 58 | 59 | Look for the flags `/MD` (Meaning it links it dynamically) and `/MT` or `-MT` (Meaning it links it statically). See [MSVC_RUNTIME_LIBRARY](https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html) and [pyannote-rs/issues/1](https://github.com/thewh1teagle/pyannote-rs/issues/1) 60 | 61 |
62 | 63 | ## Release new version 64 | 65 | ```console 66 | gh release create v0.3.0-beta.0 --title "v0.3.0-beta.0" --generate-notes 67 | git pull # Fetch new tags 68 | ``` 69 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "aho-corasick" 13 | version = "1.1.3" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 16 | dependencies = [ 17 | "memchr", 18 | ] 19 | 20 | [[package]] 21 | name = "autocfg" 22 | version = "1.3.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 25 | 26 | [[package]] 27 | name = "base64" 28 | version = "0.22.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 31 | 32 | [[package]] 33 | name = "bindgen" 34 | version = "0.69.4" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" 37 | dependencies = [ 38 | "bitflags 2.6.0", 39 | "cexpr", 40 | "clang-sys", 41 | "itertools", 42 | "lazy_static", 43 | "lazycell", 44 | "log", 45 | "prettyplease", 46 | "proc-macro2", 47 | "quote", 48 | "regex", 49 | "rustc-hash", 50 | "shlex", 51 | "syn", 52 | "which", 53 | ] 54 | 55 | [[package]] 56 | name = "bitflags" 57 | version = "1.3.2" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 60 | 61 | [[package]] 62 | name = "bitflags" 63 | version = "2.6.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 66 | 67 | [[package]] 68 | name = "block-buffer" 69 | version = "0.10.4" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 72 | dependencies = [ 73 | "generic-array", 74 | ] 75 | 76 | [[package]] 77 | name = "byteorder" 78 | version = "1.5.0" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 81 | 82 | [[package]] 83 | name = "cc" 84 | version = "1.1.7" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" 87 | 88 | [[package]] 89 | name = "cexpr" 90 | version = "0.6.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 93 | dependencies = [ 94 | "nom", 95 | ] 96 | 97 | [[package]] 98 | name = "cfg-if" 99 | version = "1.0.0" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 102 | 103 | [[package]] 104 | name = "clang-sys" 105 | version = "1.8.1" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 108 | dependencies = [ 109 | "glob", 110 | "libc", 111 | "libloading", 112 | ] 113 | 114 | [[package]] 115 | name = "cmake" 116 | version = "0.1.50" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" 119 | dependencies = [ 120 | "cc", 121 | ] 122 | 123 | [[package]] 124 | name = "cpufeatures" 125 | version = "0.2.12" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 128 | dependencies = [ 129 | "libc", 130 | ] 131 | 132 | [[package]] 133 | name = "crc32fast" 134 | version = "1.4.2" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 137 | dependencies = [ 138 | "cfg-if", 139 | ] 140 | 141 | [[package]] 142 | name = "crunchy" 143 | version = "0.2.2" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 146 | 147 | [[package]] 148 | name = "crypto-common" 149 | version = "0.1.6" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 152 | dependencies = [ 153 | "generic-array", 154 | "typenum", 155 | ] 156 | 157 | [[package]] 158 | name = "digest" 159 | version = "0.10.7" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 162 | dependencies = [ 163 | "block-buffer", 164 | "crypto-common", 165 | ] 166 | 167 | [[package]] 168 | name = "either" 169 | version = "1.13.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 172 | 173 | [[package]] 174 | name = "errno" 175 | version = "0.3.9" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 178 | dependencies = [ 179 | "libc", 180 | "windows-sys", 181 | ] 182 | 183 | [[package]] 184 | name = "eyre" 185 | version = "0.6.12" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" 188 | dependencies = [ 189 | "indenter", 190 | "once_cell", 191 | ] 192 | 193 | [[package]] 194 | name = "filetime" 195 | version = "0.2.23" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" 198 | dependencies = [ 199 | "cfg-if", 200 | "libc", 201 | "redox_syscall", 202 | "windows-sys", 203 | ] 204 | 205 | [[package]] 206 | name = "flate2" 207 | version = "1.0.31" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" 210 | dependencies = [ 211 | "crc32fast", 212 | "miniz_oxide", 213 | ] 214 | 215 | [[package]] 216 | name = "form_urlencoded" 217 | version = "1.2.1" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 220 | dependencies = [ 221 | "percent-encoding", 222 | ] 223 | 224 | [[package]] 225 | name = "generic-array" 226 | version = "0.14.7" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 229 | dependencies = [ 230 | "typenum", 231 | "version_check", 232 | ] 233 | 234 | [[package]] 235 | name = "getrandom" 236 | version = "0.2.15" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 239 | dependencies = [ 240 | "cfg-if", 241 | "libc", 242 | "wasi", 243 | ] 244 | 245 | [[package]] 246 | name = "glob" 247 | version = "0.3.1" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 250 | 251 | [[package]] 252 | name = "half" 253 | version = "2.4.1" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" 256 | dependencies = [ 257 | "cfg-if", 258 | "crunchy", 259 | ] 260 | 261 | [[package]] 262 | name = "home" 263 | version = "0.5.9" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 266 | dependencies = [ 267 | "windows-sys", 268 | ] 269 | 270 | [[package]] 271 | name = "hound" 272 | version = "3.5.1" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" 275 | 276 | [[package]] 277 | name = "idna" 278 | version = "0.5.0" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 281 | dependencies = [ 282 | "unicode-bidi", 283 | "unicode-normalization", 284 | ] 285 | 286 | [[package]] 287 | name = "indenter" 288 | version = "0.3.3" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 291 | 292 | [[package]] 293 | name = "itertools" 294 | version = "0.12.1" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 297 | dependencies = [ 298 | "either", 299 | ] 300 | 301 | [[package]] 302 | name = "knf-rs" 303 | version = "0.3.0-beta.0" 304 | dependencies = [ 305 | "eyre", 306 | "knf-rs-sys", 307 | "ndarray", 308 | ] 309 | 310 | [[package]] 311 | name = "knf-rs-sys" 312 | version = "0.3.0-beta.0" 313 | dependencies = [ 314 | "bindgen", 315 | "cmake", 316 | ] 317 | 318 | [[package]] 319 | name = "lazy_static" 320 | version = "1.5.0" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 323 | 324 | [[package]] 325 | name = "lazycell" 326 | version = "1.3.0" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 329 | 330 | [[package]] 331 | name = "libc" 332 | version = "0.2.155" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 335 | 336 | [[package]] 337 | name = "libloading" 338 | version = "0.8.5" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" 341 | dependencies = [ 342 | "cfg-if", 343 | "windows-targets", 344 | ] 345 | 346 | [[package]] 347 | name = "linux-raw-sys" 348 | version = "0.4.14" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 351 | 352 | [[package]] 353 | name = "log" 354 | version = "0.4.22" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 357 | 358 | [[package]] 359 | name = "matrixmultiply" 360 | version = "0.3.9" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" 363 | dependencies = [ 364 | "autocfg", 365 | "rawpointer", 366 | ] 367 | 368 | [[package]] 369 | name = "memchr" 370 | version = "2.7.4" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 373 | 374 | [[package]] 375 | name = "minimal-lexical" 376 | version = "0.2.1" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 379 | 380 | [[package]] 381 | name = "miniz_oxide" 382 | version = "0.7.4" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 385 | dependencies = [ 386 | "adler", 387 | ] 388 | 389 | [[package]] 390 | name = "ndarray" 391 | version = "0.16.1" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" 394 | dependencies = [ 395 | "matrixmultiply", 396 | "num-complex", 397 | "num-integer", 398 | "num-traits", 399 | "portable-atomic", 400 | "portable-atomic-util", 401 | "rawpointer", 402 | ] 403 | 404 | [[package]] 405 | name = "nom" 406 | version = "7.1.3" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 409 | dependencies = [ 410 | "memchr", 411 | "minimal-lexical", 412 | ] 413 | 414 | [[package]] 415 | name = "num-complex" 416 | version = "0.4.6" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" 419 | dependencies = [ 420 | "num-traits", 421 | ] 422 | 423 | [[package]] 424 | name = "num-integer" 425 | version = "0.1.46" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 428 | dependencies = [ 429 | "num-traits", 430 | ] 431 | 432 | [[package]] 433 | name = "num-traits" 434 | version = "0.2.19" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 437 | dependencies = [ 438 | "autocfg", 439 | ] 440 | 441 | [[package]] 442 | name = "once_cell" 443 | version = "1.19.0" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 446 | 447 | [[package]] 448 | name = "ort" 449 | version = "2.0.0-rc.9" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "52afb44b6b0cffa9bf45e4d37e5a4935b0334a51570658e279e9e3e6cf324aa5" 452 | dependencies = [ 453 | "half", 454 | "libloading", 455 | "ndarray", 456 | "ort-sys", 457 | "tracing", 458 | ] 459 | 460 | [[package]] 461 | name = "ort-sys" 462 | version = "2.0.0-rc.9" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "c41d7757331aef2d04b9cb09b45583a59217628beaf91895b7e76187b6e8c088" 465 | dependencies = [ 466 | "flate2", 467 | "pkg-config", 468 | "sha2", 469 | "tar", 470 | "ureq", 471 | ] 472 | 473 | [[package]] 474 | name = "percent-encoding" 475 | version = "2.3.1" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 478 | 479 | [[package]] 480 | name = "pin-project-lite" 481 | version = "0.2.14" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 484 | 485 | [[package]] 486 | name = "pkg-config" 487 | version = "0.3.30" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 490 | 491 | [[package]] 492 | name = "portable-atomic" 493 | version = "1.7.0" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" 496 | 497 | [[package]] 498 | name = "portable-atomic-util" 499 | version = "0.2.2" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "fcdd8420072e66d54a407b3316991fe946ce3ab1083a7f575b2463866624704d" 502 | dependencies = [ 503 | "portable-atomic", 504 | ] 505 | 506 | [[package]] 507 | name = "prettyplease" 508 | version = "0.2.20" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" 511 | dependencies = [ 512 | "proc-macro2", 513 | "syn", 514 | ] 515 | 516 | [[package]] 517 | name = "proc-macro2" 518 | version = "1.0.86" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 521 | dependencies = [ 522 | "unicode-ident", 523 | ] 524 | 525 | [[package]] 526 | name = "pyannote-rs" 527 | version = "0.3.0" 528 | dependencies = [ 529 | "eyre", 530 | "hound", 531 | "knf-rs", 532 | "ndarray", 533 | "ort", 534 | ] 535 | 536 | [[package]] 537 | name = "quote" 538 | version = "1.0.36" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 541 | dependencies = [ 542 | "proc-macro2", 543 | ] 544 | 545 | [[package]] 546 | name = "rawpointer" 547 | version = "0.2.1" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" 550 | 551 | [[package]] 552 | name = "redox_syscall" 553 | version = "0.4.1" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 556 | dependencies = [ 557 | "bitflags 1.3.2", 558 | ] 559 | 560 | [[package]] 561 | name = "regex" 562 | version = "1.10.6" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" 565 | dependencies = [ 566 | "aho-corasick", 567 | "memchr", 568 | "regex-automata", 569 | "regex-syntax", 570 | ] 571 | 572 | [[package]] 573 | name = "regex-automata" 574 | version = "0.4.7" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 577 | dependencies = [ 578 | "aho-corasick", 579 | "memchr", 580 | "regex-syntax", 581 | ] 582 | 583 | [[package]] 584 | name = "regex-syntax" 585 | version = "0.8.4" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 588 | 589 | [[package]] 590 | name = "ring" 591 | version = "0.17.8" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 594 | dependencies = [ 595 | "cc", 596 | "cfg-if", 597 | "getrandom", 598 | "libc", 599 | "spin", 600 | "untrusted", 601 | "windows-sys", 602 | ] 603 | 604 | [[package]] 605 | name = "rustc-hash" 606 | version = "1.1.0" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 609 | 610 | [[package]] 611 | name = "rustix" 612 | version = "0.38.34" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 615 | dependencies = [ 616 | "bitflags 2.6.0", 617 | "errno", 618 | "libc", 619 | "linux-raw-sys", 620 | "windows-sys", 621 | ] 622 | 623 | [[package]] 624 | name = "rustls" 625 | version = "0.23.12" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" 628 | dependencies = [ 629 | "log", 630 | "once_cell", 631 | "ring", 632 | "rustls-pki-types", 633 | "rustls-webpki", 634 | "subtle", 635 | "zeroize", 636 | ] 637 | 638 | [[package]] 639 | name = "rustls-pki-types" 640 | version = "1.7.0" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" 643 | 644 | [[package]] 645 | name = "rustls-webpki" 646 | version = "0.102.6" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" 649 | dependencies = [ 650 | "ring", 651 | "rustls-pki-types", 652 | "untrusted", 653 | ] 654 | 655 | [[package]] 656 | name = "sha2" 657 | version = "0.10.8" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 660 | dependencies = [ 661 | "cfg-if", 662 | "cpufeatures", 663 | "digest", 664 | ] 665 | 666 | [[package]] 667 | name = "shlex" 668 | version = "1.3.0" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 671 | 672 | [[package]] 673 | name = "socks" 674 | version = "0.3.4" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" 677 | dependencies = [ 678 | "byteorder", 679 | "libc", 680 | "winapi", 681 | ] 682 | 683 | [[package]] 684 | name = "spin" 685 | version = "0.9.8" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 688 | 689 | [[package]] 690 | name = "subtle" 691 | version = "2.6.1" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 694 | 695 | [[package]] 696 | name = "syn" 697 | version = "2.0.72" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" 700 | dependencies = [ 701 | "proc-macro2", 702 | "quote", 703 | "unicode-ident", 704 | ] 705 | 706 | [[package]] 707 | name = "tar" 708 | version = "0.4.41" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" 711 | dependencies = [ 712 | "filetime", 713 | "libc", 714 | "xattr", 715 | ] 716 | 717 | [[package]] 718 | name = "tinyvec" 719 | version = "1.8.0" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 722 | dependencies = [ 723 | "tinyvec_macros", 724 | ] 725 | 726 | [[package]] 727 | name = "tinyvec_macros" 728 | version = "0.1.1" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 731 | 732 | [[package]] 733 | name = "tracing" 734 | version = "0.1.40" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 737 | dependencies = [ 738 | "pin-project-lite", 739 | "tracing-core", 740 | ] 741 | 742 | [[package]] 743 | name = "tracing-core" 744 | version = "0.1.32" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 747 | dependencies = [ 748 | "once_cell", 749 | ] 750 | 751 | [[package]] 752 | name = "typenum" 753 | version = "1.17.0" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 756 | 757 | [[package]] 758 | name = "unicode-bidi" 759 | version = "0.3.15" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 762 | 763 | [[package]] 764 | name = "unicode-ident" 765 | version = "1.0.12" 766 | source = "registry+https://github.com/rust-lang/crates.io-index" 767 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 768 | 769 | [[package]] 770 | name = "unicode-normalization" 771 | version = "0.1.23" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 774 | dependencies = [ 775 | "tinyvec", 776 | ] 777 | 778 | [[package]] 779 | name = "untrusted" 780 | version = "0.9.0" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 783 | 784 | [[package]] 785 | name = "ureq" 786 | version = "2.10.0" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "72139d247e5f97a3eff96229a7ae85ead5328a39efe76f8bf5a06313d505b6ea" 789 | dependencies = [ 790 | "base64", 791 | "log", 792 | "once_cell", 793 | "rustls", 794 | "rustls-pki-types", 795 | "socks", 796 | "url", 797 | "webpki-roots", 798 | ] 799 | 800 | [[package]] 801 | name = "url" 802 | version = "2.5.2" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 805 | dependencies = [ 806 | "form_urlencoded", 807 | "idna", 808 | "percent-encoding", 809 | ] 810 | 811 | [[package]] 812 | name = "version_check" 813 | version = "0.9.5" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 816 | 817 | [[package]] 818 | name = "wasi" 819 | version = "0.11.0+wasi-snapshot-preview1" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 822 | 823 | [[package]] 824 | name = "webpki-roots" 825 | version = "0.26.3" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" 828 | dependencies = [ 829 | "rustls-pki-types", 830 | ] 831 | 832 | [[package]] 833 | name = "which" 834 | version = "4.4.2" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 837 | dependencies = [ 838 | "either", 839 | "home", 840 | "once_cell", 841 | "rustix", 842 | ] 843 | 844 | [[package]] 845 | name = "winapi" 846 | version = "0.3.9" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 849 | dependencies = [ 850 | "winapi-i686-pc-windows-gnu", 851 | "winapi-x86_64-pc-windows-gnu", 852 | ] 853 | 854 | [[package]] 855 | name = "winapi-i686-pc-windows-gnu" 856 | version = "0.4.0" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 859 | 860 | [[package]] 861 | name = "winapi-x86_64-pc-windows-gnu" 862 | version = "0.4.0" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 865 | 866 | [[package]] 867 | name = "windows-sys" 868 | version = "0.52.0" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 871 | dependencies = [ 872 | "windows-targets", 873 | ] 874 | 875 | [[package]] 876 | name = "windows-targets" 877 | version = "0.52.6" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 880 | dependencies = [ 881 | "windows_aarch64_gnullvm", 882 | "windows_aarch64_msvc", 883 | "windows_i686_gnu", 884 | "windows_i686_gnullvm", 885 | "windows_i686_msvc", 886 | "windows_x86_64_gnu", 887 | "windows_x86_64_gnullvm", 888 | "windows_x86_64_msvc", 889 | ] 890 | 891 | [[package]] 892 | name = "windows_aarch64_gnullvm" 893 | version = "0.52.6" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 896 | 897 | [[package]] 898 | name = "windows_aarch64_msvc" 899 | version = "0.52.6" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 902 | 903 | [[package]] 904 | name = "windows_i686_gnu" 905 | version = "0.52.6" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 908 | 909 | [[package]] 910 | name = "windows_i686_gnullvm" 911 | version = "0.52.6" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 914 | 915 | [[package]] 916 | name = "windows_i686_msvc" 917 | version = "0.52.6" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 920 | 921 | [[package]] 922 | name = "windows_x86_64_gnu" 923 | version = "0.52.6" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 926 | 927 | [[package]] 928 | name = "windows_x86_64_gnullvm" 929 | version = "0.52.6" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 932 | 933 | [[package]] 934 | name = "windows_x86_64_msvc" 935 | version = "0.52.6" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 938 | 939 | [[package]] 940 | name = "xattr" 941 | version = "1.3.1" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" 944 | dependencies = [ 945 | "libc", 946 | "linux-raw-sys", 947 | "rustix", 948 | ] 949 | 950 | [[package]] 951 | name = "zeroize" 952 | version = "1.8.1" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 955 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["crates/knf-rs", "crates/knf-rs/sys"] 3 | 4 | [package] 5 | name = "pyannote-rs" 6 | version = "0.3.0" 7 | edition = "2021" 8 | license = "MIT" 9 | description = "Speaker diarization using pyannote in Rust" 10 | repository = "https://github.com/thewh1teagle/pyannote-rs" 11 | 12 | [dependencies] 13 | eyre = "0.6.12" 14 | hound = "3.5.1" 15 | ndarray = "0.16" 16 | ort = "2.0.0-rc.9" 17 | knf-rs = { path = "crates/knf-rs", version = "0.3.0-beta.0", features = [] } 18 | 19 | [features] 20 | default = [] 21 | coreml = ["ort/coreml"] 22 | directml = ["ort/directml"] 23 | load-dynamic = ["ort/load-dynamic"] 24 | 25 | [[example]] 26 | name = "max_speakers" 27 | 28 | [[example]] 29 | name = "infinite" 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) pyannote-rs author 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyannote-rs 2 | 3 | [![Crates](https://img.shields.io/crates/v/pyannote-rs?logo=rust)](https://crates.io/crates/pyannote-rs/) 4 | [![License](https://img.shields.io/github/license/thewh1teagle/pyannote-rs?color=00aaaa&logo=license)](https://github.com/thewh1teagle/pyannote-rs/blob/main/LICENSE) 5 | 6 | Pyannote audio diarization in Rust 7 | 8 | ## Features 9 | 10 | - Compute 1 hour of audio in less than a minute on CPU. 11 | - Faster performance with DirectML on Windows and CoreML on macOS. 12 | - Accurate timestamps with Pyannote segmentation. 13 | - Identify speakers with wespeaker embeddings. 14 | 15 | ## Install 16 | 17 | ```console 18 | cargo add pyannote-rs 19 | ``` 20 | 21 | ## Usage 22 | 23 | See [Building](BUILDING.md) 24 | 25 | ## Examples 26 | 27 | See [examples](examples) 28 | 29 |
30 | How it works 31 | 32 | pyannote-rs uses 2 models for speaker diarization: 33 | 34 | 1. **Segmentation**: [segmentation-3.0](https://huggingface.co/pyannote/segmentation-3.0) identifies when speech occurs. 35 | 2. **Speaker Identification**: [wespeaker-voxceleb-resnet34-LM](https://huggingface.co/pyannote/wespeaker-voxceleb-resnet34-LM) identifies who is speaking. 36 | 37 | Inference is powered by [onnxruntime](https://onnxruntime.ai/). 38 | 39 | - The segmentation model processes up to 10s of audio, using a sliding window approach (iterating in chunks). 40 | - The embedding model processes filter banks (audio features) extracted with [knf-rs](https://github.com/thewh1teagle/knf-rs). 41 | 42 | Speaker comparison (e.g., determining if Alice spoke again) is done using cosine similarity. 43 |
44 | 45 | ## Credits 46 | 47 | Big thanks to [pyannote-onnx](https://github.com/pengzhendong/pyannote-onnx) and [kaldi-native-fbank](https://github.com/csukuangfj/kaldi-native-fbank) 48 | -------------------------------------------------------------------------------- /crates/knf-rs/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | build/ -------------------------------------------------------------------------------- /crates/knf-rs/BUILDING.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | _Prepare knf_ 4 | 5 | ```console 6 | git clone https://github.com/thewh1teagle/knf-rs --recursive 7 | ``` 8 | 9 | _Build_ 10 | 11 | ```console 12 | cargo build 13 | ``` 14 | 15 | _Build knf_ 16 | 17 | ```console 18 | cmake -B build . -DKALDI_NATIVE_FBANK_BUILD_PYTHON=OFF -DKALDI_NATIVE_FBANK_BUILD_TESTS=OFF 19 | cmake --build build --config Release 20 | ``` 21 | -------------------------------------------------------------------------------- /crates/knf-rs/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "autocfg" 16 | version = "1.3.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 19 | 20 | [[package]] 21 | name = "bindgen" 22 | version = "0.69.4" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" 25 | dependencies = [ 26 | "bitflags", 27 | "cexpr", 28 | "clang-sys", 29 | "itertools", 30 | "lazy_static", 31 | "lazycell", 32 | "log", 33 | "prettyplease", 34 | "proc-macro2", 35 | "quote", 36 | "regex", 37 | "rustc-hash", 38 | "shlex", 39 | "syn", 40 | "which", 41 | ] 42 | 43 | [[package]] 44 | name = "bitflags" 45 | version = "2.6.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 48 | 49 | [[package]] 50 | name = "cc" 51 | version = "1.1.8" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" 54 | 55 | [[package]] 56 | name = "cexpr" 57 | version = "0.6.0" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 60 | dependencies = [ 61 | "nom", 62 | ] 63 | 64 | [[package]] 65 | name = "cfg-if" 66 | version = "1.0.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 69 | 70 | [[package]] 71 | name = "clang-sys" 72 | version = "1.8.1" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 75 | dependencies = [ 76 | "glob", 77 | "libc", 78 | "libloading", 79 | ] 80 | 81 | [[package]] 82 | name = "cmake" 83 | version = "0.1.50" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" 86 | dependencies = [ 87 | "cc", 88 | ] 89 | 90 | [[package]] 91 | name = "either" 92 | version = "1.13.0" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 95 | 96 | [[package]] 97 | name = "errno" 98 | version = "0.3.9" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 101 | dependencies = [ 102 | "libc", 103 | "windows-sys", 104 | ] 105 | 106 | [[package]] 107 | name = "eyre" 108 | version = "0.6.12" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" 111 | dependencies = [ 112 | "indenter", 113 | "once_cell", 114 | ] 115 | 116 | [[package]] 117 | name = "glob" 118 | version = "0.3.1" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 121 | 122 | [[package]] 123 | name = "home" 124 | version = "0.5.9" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 127 | dependencies = [ 128 | "windows-sys", 129 | ] 130 | 131 | [[package]] 132 | name = "indenter" 133 | version = "0.3.3" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 136 | 137 | [[package]] 138 | name = "itertools" 139 | version = "0.12.1" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 142 | dependencies = [ 143 | "either", 144 | ] 145 | 146 | [[package]] 147 | name = "knf-rs" 148 | version = "0.2.4" 149 | dependencies = [ 150 | "eyre", 151 | "knf-rs-sys", 152 | "ndarray", 153 | ] 154 | 155 | [[package]] 156 | name = "knf-rs-sys" 157 | version = "0.2.4" 158 | dependencies = [ 159 | "bindgen", 160 | "cmake", 161 | ] 162 | 163 | [[package]] 164 | name = "lazy_static" 165 | version = "1.5.0" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 168 | 169 | [[package]] 170 | name = "lazycell" 171 | version = "1.3.0" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 174 | 175 | [[package]] 176 | name = "libc" 177 | version = "0.2.155" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 180 | 181 | [[package]] 182 | name = "libloading" 183 | version = "0.8.5" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" 186 | dependencies = [ 187 | "cfg-if", 188 | "windows-targets", 189 | ] 190 | 191 | [[package]] 192 | name = "linux-raw-sys" 193 | version = "0.4.14" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 196 | 197 | [[package]] 198 | name = "log" 199 | version = "0.4.22" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 202 | 203 | [[package]] 204 | name = "matrixmultiply" 205 | version = "0.3.9" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" 208 | dependencies = [ 209 | "autocfg", 210 | "rawpointer", 211 | ] 212 | 213 | [[package]] 214 | name = "memchr" 215 | version = "2.7.4" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 218 | 219 | [[package]] 220 | name = "minimal-lexical" 221 | version = "0.2.1" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 224 | 225 | [[package]] 226 | name = "ndarray" 227 | version = "0.16.1" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" 230 | dependencies = [ 231 | "matrixmultiply", 232 | "num-complex", 233 | "num-integer", 234 | "num-traits", 235 | "portable-atomic", 236 | "portable-atomic-util", 237 | "rawpointer", 238 | ] 239 | 240 | [[package]] 241 | name = "nom" 242 | version = "7.1.3" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 245 | dependencies = [ 246 | "memchr", 247 | "minimal-lexical", 248 | ] 249 | 250 | [[package]] 251 | name = "num-complex" 252 | version = "0.4.6" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" 255 | dependencies = [ 256 | "num-traits", 257 | ] 258 | 259 | [[package]] 260 | name = "num-integer" 261 | version = "0.1.46" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 264 | dependencies = [ 265 | "num-traits", 266 | ] 267 | 268 | [[package]] 269 | name = "num-traits" 270 | version = "0.2.19" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 273 | dependencies = [ 274 | "autocfg", 275 | ] 276 | 277 | [[package]] 278 | name = "once_cell" 279 | version = "1.19.0" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 282 | 283 | [[package]] 284 | name = "portable-atomic" 285 | version = "1.7.0" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" 288 | 289 | [[package]] 290 | name = "portable-atomic-util" 291 | version = "0.2.2" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "fcdd8420072e66d54a407b3316991fe946ce3ab1083a7f575b2463866624704d" 294 | dependencies = [ 295 | "portable-atomic", 296 | ] 297 | 298 | [[package]] 299 | name = "prettyplease" 300 | version = "0.2.20" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" 303 | dependencies = [ 304 | "proc-macro2", 305 | "syn", 306 | ] 307 | 308 | [[package]] 309 | name = "proc-macro2" 310 | version = "1.0.86" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 313 | dependencies = [ 314 | "unicode-ident", 315 | ] 316 | 317 | [[package]] 318 | name = "quote" 319 | version = "1.0.36" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 322 | dependencies = [ 323 | "proc-macro2", 324 | ] 325 | 326 | [[package]] 327 | name = "rawpointer" 328 | version = "0.2.1" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" 331 | 332 | [[package]] 333 | name = "regex" 334 | version = "1.10.6" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" 337 | dependencies = [ 338 | "aho-corasick", 339 | "memchr", 340 | "regex-automata", 341 | "regex-syntax", 342 | ] 343 | 344 | [[package]] 345 | name = "regex-automata" 346 | version = "0.4.7" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 349 | dependencies = [ 350 | "aho-corasick", 351 | "memchr", 352 | "regex-syntax", 353 | ] 354 | 355 | [[package]] 356 | name = "regex-syntax" 357 | version = "0.8.4" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 360 | 361 | [[package]] 362 | name = "rustc-hash" 363 | version = "1.1.0" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 366 | 367 | [[package]] 368 | name = "rustix" 369 | version = "0.38.34" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 372 | dependencies = [ 373 | "bitflags", 374 | "errno", 375 | "libc", 376 | "linux-raw-sys", 377 | "windows-sys", 378 | ] 379 | 380 | [[package]] 381 | name = "shlex" 382 | version = "1.3.0" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 385 | 386 | [[package]] 387 | name = "syn" 388 | version = "2.0.72" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" 391 | dependencies = [ 392 | "proc-macro2", 393 | "quote", 394 | "unicode-ident", 395 | ] 396 | 397 | [[package]] 398 | name = "unicode-ident" 399 | version = "1.0.12" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 402 | 403 | [[package]] 404 | name = "which" 405 | version = "4.4.2" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 408 | dependencies = [ 409 | "either", 410 | "home", 411 | "once_cell", 412 | "rustix", 413 | ] 414 | 415 | [[package]] 416 | name = "windows-sys" 417 | version = "0.52.0" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 420 | dependencies = [ 421 | "windows-targets", 422 | ] 423 | 424 | [[package]] 425 | name = "windows-targets" 426 | version = "0.52.6" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 429 | dependencies = [ 430 | "windows_aarch64_gnullvm", 431 | "windows_aarch64_msvc", 432 | "windows_i686_gnu", 433 | "windows_i686_gnullvm", 434 | "windows_i686_msvc", 435 | "windows_x86_64_gnu", 436 | "windows_x86_64_gnullvm", 437 | "windows_x86_64_msvc", 438 | ] 439 | 440 | [[package]] 441 | name = "windows_aarch64_gnullvm" 442 | version = "0.52.6" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 445 | 446 | [[package]] 447 | name = "windows_aarch64_msvc" 448 | version = "0.52.6" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 451 | 452 | [[package]] 453 | name = "windows_i686_gnu" 454 | version = "0.52.6" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 457 | 458 | [[package]] 459 | name = "windows_i686_gnullvm" 460 | version = "0.52.6" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 463 | 464 | [[package]] 465 | name = "windows_i686_msvc" 466 | version = "0.52.6" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 469 | 470 | [[package]] 471 | name = "windows_x86_64_gnu" 472 | version = "0.52.6" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 475 | 476 | [[package]] 477 | name = "windows_x86_64_gnullvm" 478 | version = "0.52.6" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 481 | 482 | [[package]] 483 | name = "windows_x86_64_msvc" 484 | version = "0.52.6" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 487 | -------------------------------------------------------------------------------- /crates/knf-rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "knf-rs" 3 | version = "0.3.0-beta.0" 4 | edition = "2021" 5 | license = "MIT" 6 | description = "fbank features extractor without external dependencies" 7 | repository = "https://github.com/thewh1teagle/pyannote-rs" 8 | 9 | [dependencies] 10 | knf-rs-sys = { path = "sys", version = "0.3.0-beta.0", features = [] } 11 | eyre = "0.6.12" 12 | ndarray = "0.16" 13 | 14 | 15 | [features] 16 | default = [] 17 | -------------------------------------------------------------------------------- /crates/knf-rs/README.md: -------------------------------------------------------------------------------- 1 | # knf-rs 2 | 3 | _fbank features extractor without external dependencies_ 4 | 5 | Rust bindings to [kaldi-native-fbank](https://github.com/csukuangfj/kaldi-native-fbank) 6 | -------------------------------------------------------------------------------- /crates/knf-rs/src/lib.rs: -------------------------------------------------------------------------------- 1 | use eyre::{bail, Context, ContextCompat, Result}; 2 | use ndarray::Array2; 3 | 4 | pub fn compute_fbank(samples: &[f32]) -> Result> { 5 | if samples.is_empty() { 6 | bail!("The samples array is empty. No features to compute.") 7 | } 8 | 9 | let mut result = unsafe { 10 | knf_rs_sys::ComputeFbank( 11 | samples.as_ptr(), 12 | samples.len().try_into().context("samples len")?, 13 | ) 14 | }; 15 | 16 | // Extract frames 17 | let frames = unsafe { 18 | std::slice::from_raw_parts( 19 | result.frames, 20 | (result.num_frames * result.num_bins) as usize, 21 | ) 22 | .to_vec() 23 | }; 24 | 25 | let frames_array = Array2::from_shape_vec( 26 | ( 27 | result.num_frames.try_into().context("num_frames")?, 28 | result.num_bins.try_into().context("num_bins")?, 29 | ), 30 | frames, 31 | )?; 32 | 33 | unsafe { 34 | knf_rs_sys::DestroyFbankResult(&mut result as *mut _); 35 | } 36 | 37 | if frames_array.is_empty() { 38 | bail!("The frames array is empty. No features to compute.") 39 | } 40 | 41 | let mean = frames_array.mean_axis(ndarray::Axis(0)).context("mean")?; 42 | let features = frames_array - mean; 43 | 44 | Ok(features) 45 | } 46 | 47 | pub fn convert_integer_to_float_audio(samples: &[i16], output: &mut [f32]) { 48 | for (input, output) in samples.iter().zip(output.iter_mut()) { 49 | *output = *input as f32 / 32768.0; 50 | } 51 | } 52 | 53 | #[cfg(test)] 54 | mod tests { 55 | use crate::compute_fbank; 56 | use std::f32::consts::PI; 57 | 58 | fn generate_sine_wave(sample_rate: usize, duration: usize, frequency: f32) -> Vec { 59 | let waveform_size = sample_rate * duration; 60 | let mut waveform = Vec::with_capacity(waveform_size); 61 | 62 | for i in 0..waveform_size { 63 | let sample = 0.5 * (2.0 * PI * frequency * i as f32 / sample_rate as f32).sin(); 64 | waveform.push(sample); 65 | } 66 | waveform 67 | } 68 | 69 | #[test] 70 | fn it_works() { 71 | let sample_rate = 16000; 72 | let duration = 1; // 1 second 73 | let frequency = 440.0; // A4 note 74 | 75 | let waveform = generate_sine_wave(sample_rate, duration, frequency); 76 | let features = compute_fbank(&waveform); 77 | println!("features: {:?}", features); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /crates/knf-rs/sys/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "bindgen" 16 | version = "0.69.4" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" 19 | dependencies = [ 20 | "bitflags", 21 | "cexpr", 22 | "clang-sys", 23 | "itertools", 24 | "lazy_static", 25 | "lazycell", 26 | "log", 27 | "prettyplease", 28 | "proc-macro2", 29 | "quote", 30 | "regex", 31 | "rustc-hash", 32 | "shlex", 33 | "syn", 34 | "which", 35 | ] 36 | 37 | [[package]] 38 | name = "bitflags" 39 | version = "2.6.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 42 | 43 | [[package]] 44 | name = "cc" 45 | version = "1.1.7" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" 48 | 49 | [[package]] 50 | name = "cexpr" 51 | version = "0.6.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 54 | dependencies = [ 55 | "nom", 56 | ] 57 | 58 | [[package]] 59 | name = "cfg-if" 60 | version = "1.0.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 63 | 64 | [[package]] 65 | name = "clang-sys" 66 | version = "1.8.1" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 69 | dependencies = [ 70 | "glob", 71 | "libc", 72 | "libloading", 73 | ] 74 | 75 | [[package]] 76 | name = "cmake" 77 | version = "0.1.50" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" 80 | dependencies = [ 81 | "cc", 82 | ] 83 | 84 | [[package]] 85 | name = "either" 86 | version = "1.13.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 89 | 90 | [[package]] 91 | name = "errno" 92 | version = "0.3.9" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 95 | dependencies = [ 96 | "libc", 97 | "windows-sys", 98 | ] 99 | 100 | [[package]] 101 | name = "glob" 102 | version = "0.3.1" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 105 | 106 | [[package]] 107 | name = "home" 108 | version = "0.5.9" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 111 | dependencies = [ 112 | "windows-sys", 113 | ] 114 | 115 | [[package]] 116 | name = "itertools" 117 | version = "0.12.1" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 120 | dependencies = [ 121 | "either", 122 | ] 123 | 124 | [[package]] 125 | name = "knf-rs-sys" 126 | version = "0.2.2" 127 | dependencies = [ 128 | "bindgen", 129 | "cmake", 130 | ] 131 | 132 | [[package]] 133 | name = "lazy_static" 134 | version = "1.5.0" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 137 | 138 | [[package]] 139 | name = "lazycell" 140 | version = "1.3.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 143 | 144 | [[package]] 145 | name = "libc" 146 | version = "0.2.155" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 149 | 150 | [[package]] 151 | name = "libloading" 152 | version = "0.8.5" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" 155 | dependencies = [ 156 | "cfg-if", 157 | "windows-targets", 158 | ] 159 | 160 | [[package]] 161 | name = "linux-raw-sys" 162 | version = "0.4.14" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 165 | 166 | [[package]] 167 | name = "log" 168 | version = "0.4.22" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 171 | 172 | [[package]] 173 | name = "memchr" 174 | version = "2.7.4" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 177 | 178 | [[package]] 179 | name = "minimal-lexical" 180 | version = "0.2.1" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 183 | 184 | [[package]] 185 | name = "nom" 186 | version = "7.1.3" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 189 | dependencies = [ 190 | "memchr", 191 | "minimal-lexical", 192 | ] 193 | 194 | [[package]] 195 | name = "once_cell" 196 | version = "1.19.0" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 199 | 200 | [[package]] 201 | name = "prettyplease" 202 | version = "0.2.20" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" 205 | dependencies = [ 206 | "proc-macro2", 207 | "syn", 208 | ] 209 | 210 | [[package]] 211 | name = "proc-macro2" 212 | version = "1.0.86" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 215 | dependencies = [ 216 | "unicode-ident", 217 | ] 218 | 219 | [[package]] 220 | name = "quote" 221 | version = "1.0.36" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 224 | dependencies = [ 225 | "proc-macro2", 226 | ] 227 | 228 | [[package]] 229 | name = "regex" 230 | version = "1.10.6" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" 233 | dependencies = [ 234 | "aho-corasick", 235 | "memchr", 236 | "regex-automata", 237 | "regex-syntax", 238 | ] 239 | 240 | [[package]] 241 | name = "regex-automata" 242 | version = "0.4.7" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 245 | dependencies = [ 246 | "aho-corasick", 247 | "memchr", 248 | "regex-syntax", 249 | ] 250 | 251 | [[package]] 252 | name = "regex-syntax" 253 | version = "0.8.4" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 256 | 257 | [[package]] 258 | name = "rustc-hash" 259 | version = "1.1.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 262 | 263 | [[package]] 264 | name = "rustix" 265 | version = "0.38.34" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 268 | dependencies = [ 269 | "bitflags", 270 | "errno", 271 | "libc", 272 | "linux-raw-sys", 273 | "windows-sys", 274 | ] 275 | 276 | [[package]] 277 | name = "shlex" 278 | version = "1.3.0" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 281 | 282 | [[package]] 283 | name = "syn" 284 | version = "2.0.72" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" 287 | dependencies = [ 288 | "proc-macro2", 289 | "quote", 290 | "unicode-ident", 291 | ] 292 | 293 | [[package]] 294 | name = "unicode-ident" 295 | version = "1.0.12" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 298 | 299 | [[package]] 300 | name = "which" 301 | version = "4.4.2" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 304 | dependencies = [ 305 | "either", 306 | "home", 307 | "once_cell", 308 | "rustix", 309 | ] 310 | 311 | [[package]] 312 | name = "windows-sys" 313 | version = "0.52.0" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 316 | dependencies = [ 317 | "windows-targets", 318 | ] 319 | 320 | [[package]] 321 | name = "windows-targets" 322 | version = "0.52.6" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 325 | dependencies = [ 326 | "windows_aarch64_gnullvm", 327 | "windows_aarch64_msvc", 328 | "windows_i686_gnu", 329 | "windows_i686_gnullvm", 330 | "windows_i686_msvc", 331 | "windows_x86_64_gnu", 332 | "windows_x86_64_gnullvm", 333 | "windows_x86_64_msvc", 334 | ] 335 | 336 | [[package]] 337 | name = "windows_aarch64_gnullvm" 338 | version = "0.52.6" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 341 | 342 | [[package]] 343 | name = "windows_aarch64_msvc" 344 | version = "0.52.6" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 347 | 348 | [[package]] 349 | name = "windows_i686_gnu" 350 | version = "0.52.6" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 353 | 354 | [[package]] 355 | name = "windows_i686_gnullvm" 356 | version = "0.52.6" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 359 | 360 | [[package]] 361 | name = "windows_i686_msvc" 362 | version = "0.52.6" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 365 | 366 | [[package]] 367 | name = "windows_x86_64_gnu" 368 | version = "0.52.6" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 371 | 372 | [[package]] 373 | name = "windows_x86_64_gnullvm" 374 | version = "0.52.6" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 377 | 378 | [[package]] 379 | name = "windows_x86_64_msvc" 380 | version = "0.52.6" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 383 | -------------------------------------------------------------------------------- /crates/knf-rs/sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "knf-rs-sys" 3 | version = "0.3.0-beta.0" 4 | edition = "2021" 5 | license = "MIT" 6 | description = "fbank features extractor without external dependencies" 7 | repository = "https://github.com/thewh1teagle/pyannote-rs" 8 | 9 | include = [ 10 | "knfc", 11 | "knf/kaldi-native-fbank/csrc", 12 | "knf/kaldi-native-fbank/CMakeLists.txt", 13 | "knf/cmake", 14 | "knf/CMakeLists.txt", 15 | "knf/LICENSE", 16 | "src/*.rs", 17 | "build.rs", 18 | "wrapper.hpp", 19 | ] 20 | 21 | [build-dependencies] 22 | bindgen = "0.69.4" 23 | cmake = "0.1.50" 24 | 25 | [features] 26 | default = [] 27 | -------------------------------------------------------------------------------- /crates/knf-rs/sys/build.rs: -------------------------------------------------------------------------------- 1 | use cmake::Config; 2 | use std::env; 3 | use std::path::{Path, PathBuf}; 4 | 5 | macro_rules! debug_log { 6 | ($($arg:tt)*) => { 7 | if std::env::var("BUILD_DEBUG").is_ok() { 8 | println!("cargo:warning=[DEBUG] {}", format!($($arg)*)); 9 | } 10 | }; 11 | } 12 | 13 | fn copy_folder(src: &Path, dst: &Path) { 14 | std::fs::create_dir_all(dst).expect("Failed to create dst directory"); 15 | if cfg!(unix) { 16 | std::process::Command::new("cp") 17 | .arg("-rf") 18 | .arg(src) 19 | .arg(dst.parent().expect("no parent")) 20 | .status() 21 | .expect("Failed to execute cp command"); 22 | } 23 | 24 | if cfg!(windows) { 25 | std::process::Command::new("robocopy.exe") 26 | .arg("/e") 27 | .arg(src) 28 | .arg(dst) 29 | .status() 30 | .expect("Failed to execute robocopy command"); 31 | } 32 | } 33 | 34 | fn main() { 35 | let target = env::var("TARGET").expect("no target"); 36 | let out_dir = PathBuf::from(env::var("OUT_DIR").expect("no out dir")); 37 | let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("Failed to get CARGO_MANIFEST_DIR"); 38 | let knf_src = Path::new(&manifest_dir).join("knf"); 39 | let knf_dst = out_dir.join("knf"); 40 | let knfc_src = Path::new(&manifest_dir).join("knfc"); 41 | let knfc_dst = out_dir.join("knfc"); 42 | let static_crt = env::var("KNF_STATIC_CRT") 43 | .map(|v| v == "1") 44 | .unwrap_or(false); 45 | 46 | let profile = if cfg!(debug_assertions) { 47 | "Debug" 48 | } else { 49 | "Release" 50 | }; 51 | 52 | debug_log!("TARGET: {}", target); 53 | debug_log!("CARGO_MANIFEST_DIR: {}", manifest_dir); 54 | debug_log!("OUT_DIR: {}", out_dir.display()); 55 | 56 | if !knf_dst.exists() { 57 | debug_log!("Copy {} to {}", knf_src.display(), knf_dst.display()); 58 | copy_folder(&knf_src, &knf_dst); 59 | } 60 | 61 | if !knfc_dst.exists() { 62 | debug_log!("Copy {} to {}", knfc_src.display(), knfc_dst.display()); 63 | copy_folder(&knfc_src, &knfc_dst); 64 | } 65 | 66 | // Bindings 67 | let bindings = bindgen::Builder::default() 68 | .header("wrapper.hpp") 69 | .clang_arg(format!("-I{}", knfc_dst.display())) 70 | .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) 71 | .generate() 72 | .expect("Failed to generate bindings"); 73 | 74 | // Write the generated bindings to an output file 75 | let bindings_path = out_dir.join("bindings.rs"); 76 | bindings 77 | .write_to_file(bindings_path) 78 | .expect("Failed to write bindings"); 79 | 80 | println!("cargo:rerun-if-changed=./knf"); 81 | println!("cargo:rerun-if-changed=./knfc"); 82 | println!("cargo:rerun-if-changed=wrapper.hpp"); 83 | 84 | debug_log!("Bindings Created"); 85 | 86 | let mut config = Config::new(&knfc_dst); 87 | 88 | if cfg!(windows) { 89 | config.static_crt(static_crt); 90 | debug_log!("STATIC_CRT: {}", static_crt); 91 | } 92 | 93 | config 94 | .profile(profile) 95 | .very_verbose(std::env::var("CMAKE_VERBOSE").is_ok()) // Not verbose by default 96 | .always_configure(false) 97 | .build(); 98 | 99 | println!("cargo:rustc-link-search={}", out_dir.join("lib").display()); 100 | 101 | // Link 102 | if cfg!(target_os = "macos") { 103 | println!("cargo:rustc-link-lib=c++"); 104 | } 105 | 106 | if cfg!(target_os = "linux") { 107 | println!("cargo:rustc-link-lib=stdc++"); 108 | } 109 | 110 | println!("cargo:rustc-link-lib=static=knfc"); 111 | println!("cargo:rustc-link-lib=static=kaldi-native-fbank-core"); 112 | } 113 | -------------------------------------------------------------------------------- /crates/knf-rs/sys/knfc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(knfc) 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED True) 7 | 8 | option(BUILD_SHARED_LIBS "Build shared libraries" OFF) 9 | set(KALDI_NATIVE_FBANK_BUILD_PYTHON OFF CACHE BOOL "Disable Python build") 10 | set(KALDI_NATIVE_FBANK_BUILD_TESTS OFF CACHE BOOL "Disable Tests build") 11 | 12 | add_subdirectory(../knf ${CMAKE_BINARY_DIR}/knf) 13 | 14 | add_library(knfc STATIC knfc.cc) 15 | 16 | target_link_libraries(knfc PRIVATE kaldi-native-fbank-core) 17 | 18 | target_include_directories(knfc PRIVATE 19 | ${KNF_LIB_PATH}/include 20 | ../knf/kaldi-native-fbank/csrc 21 | ../knf 22 | ) 23 | 24 | install(TARGETS knfc 25 | ARCHIVE DESTINATION lib) -------------------------------------------------------------------------------- /crates/knf-rs/sys/knfc/knfc.cc: -------------------------------------------------------------------------------- 1 | #include "knfc.h" 2 | #include "kaldi-native-fbank/csrc/feature-fbank.h" 3 | #include "kaldi-native-fbank/csrc/feature-window.h" 4 | #include "kaldi-native-fbank/csrc/mel-computations.h" 5 | #include "kaldi-native-fbank/csrc/online-feature.h" 6 | #include 7 | 8 | void DestroyFbankResult(FbankResult *result) { 9 | if (result) { 10 | delete[] result->frames; 11 | result->frames = nullptr; 12 | result->num_frames = 0; 13 | result->num_bins = 0; 14 | } 15 | } 16 | 17 | FbankResult ComputeFbank(const float *waveform, int32_t waveform_size) { 18 | knf::FrameExtractionOptions frame_opts; 19 | knf::MelBanksOptions mel_opts; 20 | knf::FbankOptions fbank_opts; 21 | 22 | // Frame options 23 | frame_opts.dither = 0.0; 24 | frame_opts.samp_freq = 16000; 25 | frame_opts.snip_edges = true; 26 | 27 | // Mel options 28 | mel_opts.num_bins = 80; 29 | mel_opts.debug_mel = false; 30 | 31 | fbank_opts.mel_opts = mel_opts; 32 | fbank_opts.frame_opts = frame_opts; 33 | knf::OnlineFbank fbank(fbank_opts); 34 | fbank.AcceptWaveform(frame_opts.samp_freq, waveform, waveform_size); 35 | fbank.InputFinished(); 36 | 37 | int32_t num_frames = fbank.NumFramesReady(); 38 | int32_t num_bins = mel_opts.num_bins; 39 | 40 | // Allocate memory for the frames 41 | float *frames = new float[num_frames * num_bins]; 42 | 43 | // Fill the frames 44 | for (int32_t i = 0; i < num_frames; i++) { 45 | const float *frame = fbank.GetFrame(i); 46 | std::copy(frame, frame + num_bins, frames + i * num_bins); 47 | } 48 | 49 | FbankResult result; 50 | result.frames = frames; 51 | result.num_frames = num_frames; 52 | result.num_bins = num_bins; 53 | return result; 54 | } -------------------------------------------------------------------------------- /crates/knf-rs/sys/knfc/knfc.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | typedef struct { 8 | float *frames; 9 | int32_t num_frames; 10 | int32_t num_bins; 11 | } FbankResult; 12 | 13 | extern "C" void DestroyFbankResult(FbankResult *result); 14 | 15 | FbankResult ComputeFbank(const float *waveform, int32_t waveform_size); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif -------------------------------------------------------------------------------- /crates/knf-rs/sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | 5 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 6 | -------------------------------------------------------------------------------- /crates/knf-rs/sys/wrapper.hpp: -------------------------------------------------------------------------------- 1 | #include "knfc/knfc.h" -------------------------------------------------------------------------------- /examples/infinite.rs: -------------------------------------------------------------------------------- 1 | /* 2 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/segmentation-3.0.onnx 3 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/wespeaker_en_voxceleb_CAM++.onnx 4 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/6_speakers.wav 5 | cargo run --example infinite 6_speakers.wav 6 | */ 7 | 8 | use pyannote_rs::{EmbeddingExtractor, EmbeddingManager}; 9 | 10 | fn process_segment( 11 | segment: pyannote_rs::Segment, 12 | embedding_extractor: &mut EmbeddingExtractor, 13 | embedding_manager: &mut EmbeddingManager, 14 | search_threshold: f32, 15 | ) -> Result<(), eyre::Report> { 16 | let embedding_result: Vec = embedding_extractor 17 | .compute(&segment.samples) 18 | .unwrap() 19 | .collect(); 20 | 21 | let speaker = embedding_manager 22 | .search_speaker(embedding_result.clone(), search_threshold) 23 | .ok_or_else(|| embedding_manager.search_speaker(embedding_result, 0.0)) // Ensure always to return speaker 24 | .map(|r| r.to_string()) 25 | .unwrap_or("?".into()); 26 | 27 | println!( 28 | "start = {:.2}, end = {:.2}, speaker = {}", 29 | segment.start, segment.end, speaker 30 | ); 31 | 32 | Ok(()) 33 | } 34 | 35 | fn main() -> Result<(), eyre::Report> { 36 | let audio_path = std::env::args().nth(1).expect("Please specify audio file"); 37 | let search_threshold = 0.5; 38 | 39 | let embedding_model_path = "wespeaker_en_voxceleb_CAM++.onnx"; 40 | let segmentation_model_path = "segmentation-3.0.onnx"; 41 | 42 | let (samples, sample_rate) = pyannote_rs::read_wav(&audio_path)?; 43 | let mut embedding_extractor = EmbeddingExtractor::new(embedding_model_path)?; 44 | let mut embedding_manager = EmbeddingManager::new(usize::MAX); 45 | 46 | let segments = pyannote_rs::get_segments(&samples, sample_rate, segmentation_model_path)?; 47 | 48 | for segment in segments { 49 | if let Ok(segment) = segment { 50 | if let Err(error) = process_segment( 51 | segment, 52 | &mut embedding_extractor, 53 | &mut embedding_manager, 54 | search_threshold, 55 | ) { 56 | eprintln!("Error processing segment: {:?}", error); 57 | } 58 | } else if let Err(error) = segment { 59 | eprintln!("Failed to process segment: {:?}", error); 60 | } 61 | } 62 | 63 | Ok(()) 64 | } 65 | -------------------------------------------------------------------------------- /examples/max_speakers.rs: -------------------------------------------------------------------------------- 1 | use pyannote_rs::{EmbeddingExtractor, EmbeddingManager}; 2 | 3 | fn main() { 4 | let audio_path = std::env::args().nth(1).expect("Please specify audio file"); 5 | let (samples, sample_rate) = pyannote_rs::read_wav(&audio_path).unwrap(); 6 | let max_speakers = 6; 7 | 8 | let mut extractor = EmbeddingExtractor::new("wespeaker_en_voxceleb_CAM++.onnx").unwrap(); 9 | let mut manager = EmbeddingManager::new(6); 10 | 11 | let segments = 12 | pyannote_rs::get_segments(&samples, sample_rate, "segmentation-3.0.onnx").unwrap(); 13 | 14 | for segment in segments { 15 | match segment { 16 | Ok(segment) => { 17 | if let Ok(embedding) = extractor.compute(&segment.samples) { 18 | let speaker = if manager.get_all_speakers().len() == max_speakers { 19 | manager 20 | .get_best_speaker_match(embedding.collect()) 21 | .map(|s| s.to_string()) 22 | .unwrap_or("?".into()) 23 | } else { 24 | manager 25 | .search_speaker(embedding.collect(), 0.5) 26 | .map(|s| s.to_string()) 27 | .unwrap_or("?".into()) 28 | }; 29 | println!( 30 | "start = {:.2}, end = {:.2}, speaker = {}", 31 | segment.start, segment.end, speaker 32 | ); 33 | } else { 34 | println!( 35 | "start = {:.2}, end = {:.2}, speaker = ?", 36 | segment.start, segment.end 37 | ); 38 | } 39 | } 40 | Err(error) => eprintln!("Failed to process segment: {:?}", error), 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/save_segments.rs: -------------------------------------------------------------------------------- 1 | /* 2 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/segmentation-3.0.onnx 3 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/wespeaker_en_voxceleb_CAM++.onnx 4 | wget https://github.com/thewh1teagle/pyannote-rs/releases/download/v0.1.0/6_speakers.wav 5 | cargo run --example save_segments 6_speakers.wav 6 | */ 7 | 8 | use eyre::Result; 9 | use hound::{WavSpec, WavWriter}; 10 | use std::{fs, path::Path}; 11 | 12 | pub fn write_wav(file_path: &str, samples: &[i16], sample_rate: u32) -> Result<()> { 13 | let spec = WavSpec { 14 | channels: 1, 15 | sample_rate, 16 | bits_per_sample: 16, 17 | sample_format: hound::SampleFormat::Int, 18 | }; 19 | 20 | let mut writer = WavWriter::create(file_path, spec)?; 21 | for &sample in samples { 22 | writer.write_sample(sample)?; 23 | } 24 | 25 | Ok(()) 26 | } 27 | 28 | fn main() { 29 | let audio_path = std::env::args().nth(1).expect("Please specify audio file"); 30 | let (samples, sample_rate) = pyannote_rs::read_wav(&audio_path).unwrap(); 31 | let segments = 32 | pyannote_rs::get_segments(&samples, sample_rate, "segmentation-3.0.onnx").unwrap(); 33 | 34 | // Create a folder with the base name of the input file 35 | let output_folder = format!( 36 | "{}_segments", 37 | Path::new(&audio_path) 38 | .file_stem() 39 | .unwrap() 40 | .to_str() 41 | .unwrap() 42 | ); 43 | fs::create_dir_all(&output_folder).unwrap(); 44 | 45 | for segment in segments { 46 | match segment { 47 | Ok(segment) => { 48 | let segment_file_name = format!( 49 | "{}/start_{:.2}_end_{:.2}.wav", 50 | output_folder, segment.start, segment.end 51 | ); 52 | write_wav(&segment_file_name, &segment.samples, sample_rate).unwrap(); 53 | println!("Created {}", segment_file_name); 54 | } 55 | Err(error) => eprintln!("Failed to process segment: {:?}", error), 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/embedding.rs: -------------------------------------------------------------------------------- 1 | use crate::session; 2 | use eyre::{Context, ContextCompat, Result}; 3 | use ndarray::Array2; 4 | use ort::session::Session; 5 | use std::path::Path; 6 | 7 | #[derive(Debug)] 8 | pub struct EmbeddingExtractor { 9 | session: Session, 10 | } 11 | 12 | impl EmbeddingExtractor { 13 | pub fn new>(model_path: P) -> Result { 14 | let session = session::create_session(model_path.as_ref())?; 15 | Ok(Self { session }) 16 | } 17 | 18 | pub fn compute(&mut self, samples: &[i16]) -> Result> { 19 | // Convert to f32 precisely 20 | let mut samples_f32 = vec![0.0; samples.len()]; 21 | knf_rs::convert_integer_to_float_audio(samples, &mut samples_f32); 22 | let samples = &samples_f32; 23 | 24 | let features: Array2 = knf_rs::compute_fbank(samples)?; 25 | let features = features.insert_axis(ndarray::Axis(0)); // Add batch dimension 26 | let inputs = ort::inputs! ["feats" => features.view()]?; 27 | 28 | let ort_outs = self.session.run(inputs)?; 29 | let ort_out = ort_outs 30 | .get("embs") 31 | .context("Output tensor not found")? 32 | .try_extract_tensor::() 33 | .context("Failed to extract tensor")?; 34 | 35 | // Collect the tensor data into a Vec to own it 36 | let embeddings: Vec = ort_out.iter().copied().collect(); 37 | 38 | // Return an iterator over the Vec 39 | Ok(embeddings.into_iter()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/identify.rs: -------------------------------------------------------------------------------- 1 | use eyre::{bail, Result}; 2 | use ndarray::Array1; 3 | use std::collections::HashMap; 4 | 5 | #[derive(Debug, Clone)] 6 | pub struct EmbeddingManager { 7 | max_speakers: usize, 8 | speakers: HashMap>, 9 | next_speaker_id: usize, 10 | } 11 | 12 | impl EmbeddingManager { 13 | pub fn new(max_speakers: usize) -> Self { 14 | Self { 15 | max_speakers, 16 | speakers: HashMap::new(), 17 | next_speaker_id: 1, 18 | } 19 | } 20 | 21 | fn cosine_similarity(a: &Array1, b: &Array1) -> f32 { 22 | let dot_product = a.dot(b); 23 | let norm_a = a.dot(a).sqrt(); 24 | let norm_b = b.dot(b).sqrt(); 25 | dot_product / (norm_a * norm_b) 26 | } 27 | 28 | /// Search or create speaker 29 | pub fn search_speaker(&mut self, embedding: Vec, threshold: f32) -> Option { 30 | let embedding_array = Array1::from_vec(embedding); 31 | let mut best_speaker_id = None; 32 | let mut best_similarity = threshold; 33 | 34 | for (&speaker_id, speaker_embedding) in &self.speakers { 35 | let similarity = Self::cosine_similarity(&embedding_array, speaker_embedding); 36 | if similarity > best_similarity { 37 | best_speaker_id = Some(speaker_id); 38 | best_similarity = similarity; 39 | } 40 | } 41 | 42 | match best_speaker_id { 43 | Some(id) => Some(id), 44 | None if self.speakers.len() < self.max_speakers => { 45 | Some(self.add_speaker(embedding_array)) 46 | } 47 | None => None, 48 | } 49 | } 50 | 51 | pub fn get_best_speaker_match(&mut self, embedding: Vec) -> Result { 52 | if self.speakers.is_empty() { 53 | bail!("no speakers") 54 | } 55 | let embedding_array = Array1::from_vec(embedding); 56 | let mut best_speaker_id = 0; 57 | let mut best_similarity = f32::MIN; // Initialize to the lowest possible value 58 | 59 | for (&speaker_id, speaker_embedding) in &self.speakers { 60 | let similarity = Self::cosine_similarity(&embedding_array, speaker_embedding); 61 | if similarity > best_similarity { 62 | best_speaker_id = speaker_id; 63 | best_similarity = similarity; 64 | } 65 | } 66 | Ok(best_speaker_id) 67 | } 68 | 69 | fn add_speaker(&mut self, embedding: Array1) -> usize { 70 | let speaker_id = self.next_speaker_id; 71 | self.speakers.insert(speaker_id, embedding); 72 | self.next_speaker_id += 1; 73 | speaker_id 74 | } 75 | 76 | #[allow(unused)] 77 | pub fn get_all_speakers(&self) -> &HashMap> { 78 | &self.speakers 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod session; 2 | 3 | mod embedding; 4 | mod identify; 5 | mod segment; 6 | mod wav; 7 | 8 | pub use embedding::EmbeddingExtractor; 9 | pub use identify::EmbeddingManager; 10 | pub use knf_rs::{compute_fbank, convert_integer_to_float_audio}; 11 | pub use segment::{get_segments, Segment}; 12 | pub use wav::read_wav; 13 | -------------------------------------------------------------------------------- /src/segment.rs: -------------------------------------------------------------------------------- 1 | use crate::session; 2 | use eyre::{Context, ContextCompat, Result}; 3 | use ndarray::{ArrayBase, Axis, IxDyn, ViewRepr}; 4 | use std::{cmp::Ordering, collections::VecDeque, path::Path}; 5 | 6 | #[derive(Debug, Clone)] 7 | #[repr(C)] 8 | pub struct Segment { 9 | pub start: f64, 10 | pub end: f64, 11 | pub samples: Vec, 12 | } 13 | 14 | fn find_max_index(row: ArrayBase, IxDyn>) -> Result { 15 | let (max_index, _) = row 16 | .iter() 17 | .enumerate() 18 | .max_by(|a, b| { 19 | a.1.partial_cmp(b.1) 20 | .context("Comparison error") 21 | .unwrap_or(Ordering::Equal) 22 | }) 23 | .context("sub_row should not be empty")?; 24 | Ok(max_index) 25 | } 26 | 27 | pub fn get_segments>( 28 | samples: &[i16], 29 | sample_rate: u32, 30 | model_path: P, 31 | ) -> Result> + '_> { 32 | // Create session using the provided model path 33 | let session = session::create_session(model_path.as_ref())?; 34 | 35 | // Define frame parameters 36 | let frame_size = 270; 37 | let frame_start = 721; 38 | let window_size = (sample_rate * 10) as usize; // 10 seconds 39 | let mut is_speeching = false; 40 | let mut offset = frame_start; 41 | let mut start_offset = 0.0; 42 | 43 | // Pad end with silence for full last segment 44 | let padded_samples = { 45 | let mut padded = Vec::from(samples); 46 | padded.extend(vec![0; window_size - (samples.len() % window_size)]); 47 | padded 48 | }; 49 | 50 | let mut start_iter = (0..padded_samples.len()).step_by(window_size); 51 | 52 | let mut segments_queue = VecDeque::new(); 53 | Ok(std::iter::from_fn(move || { 54 | if let Some(start) = start_iter.next() { 55 | let end = (start + window_size).min(padded_samples.len()); 56 | let window = &padded_samples[start..end]; 57 | 58 | // Convert window to ndarray::Array1 59 | let array = ndarray::Array1::from_iter(window.iter().map(|&x| x as f32)); 60 | let array = array.view().insert_axis(Axis(0)).insert_axis(Axis(1)); 61 | 62 | // Handle potential errors during the session and input processing 63 | let inputs = match ort::inputs![array.into_dyn()] { 64 | Ok(inputs) => inputs, 65 | Err(e) => return Some(Err(eyre::eyre!("Failed to prepare inputs: {:?}", e))), 66 | }; 67 | 68 | let ort_outs = match session.run(inputs) { 69 | Ok(outputs) => outputs, 70 | Err(e) => return Some(Err(eyre::eyre!("Failed to run the session: {:?}", e))), 71 | }; 72 | 73 | let ort_out = match ort_outs.get("output").context("Output tensor not found") { 74 | Ok(output) => output, 75 | Err(e) => return Some(Err(eyre::eyre!("Output tensor error: {:?}", e))), 76 | }; 77 | 78 | let ort_out = match ort_out 79 | .try_extract_tensor::() 80 | .context("Failed to extract tensor") 81 | { 82 | Ok(tensor) => tensor, 83 | Err(e) => return Some(Err(eyre::eyre!("Tensor extraction error: {:?}", e))), 84 | }; 85 | 86 | for row in ort_out.outer_iter() { 87 | for sub_row in row.axis_iter(Axis(0)) { 88 | let max_index = match find_max_index(sub_row) { 89 | Ok(index) => index, 90 | Err(e) => return Some(Err(e)), 91 | }; 92 | 93 | if max_index != 0 { 94 | if !is_speeching { 95 | start_offset = offset as f64; 96 | is_speeching = true; 97 | } 98 | } else if is_speeching { 99 | let start = start_offset / sample_rate as f64; 100 | let end = offset as f64 / sample_rate as f64; 101 | 102 | let start_f64 = start * (sample_rate as f64); 103 | let end_f64 = end * (sample_rate as f64); 104 | 105 | // Ensure indices are within bounds 106 | let start_idx = start_f64.min((samples.len() - 1) as f64) as usize; 107 | let end_idx = end_f64.min(samples.len() as f64) as usize; 108 | 109 | let segment_samples = &padded_samples[start_idx..end_idx]; 110 | 111 | is_speeching = false; 112 | 113 | let segment = Segment { 114 | start, 115 | end, 116 | samples: segment_samples.to_vec(), 117 | }; 118 | segments_queue.push_back(segment); 119 | } 120 | offset += frame_size; 121 | } 122 | } 123 | } 124 | segments_queue.pop_front().map(Ok) 125 | })) 126 | } 127 | -------------------------------------------------------------------------------- /src/session.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | use eyre::Result; 4 | use ort::session::builder::GraphOptimizationLevel; 5 | use ort::session::Session; 6 | 7 | pub fn create_session>(path: P) -> Result { 8 | let session = Session::builder()? 9 | .with_optimization_level(GraphOptimizationLevel::Level3)? 10 | .with_intra_threads(1)? 11 | .with_inter_threads(1)? 12 | .commit_from_file(path.as_ref())?; 13 | Ok(session) 14 | } 15 | -------------------------------------------------------------------------------- /src/wav.rs: -------------------------------------------------------------------------------- 1 | use eyre::Result; 2 | use hound::WavReader; 3 | 4 | pub fn read_wav(file_path: &str) -> Result<(Vec, u32)> { 5 | let mut reader = WavReader::open(file_path)?; 6 | let spec = reader.spec(); 7 | let sample_rate = spec.sample_rate; 8 | let samples: Vec = reader.samples::().collect::, _>>()?; 9 | 10 | Ok((samples, sample_rate)) 11 | } 12 | --------------------------------------------------------------------------------