├── .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 | [](https://crates.io/crates/pyannote-rs/)
4 | [](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 |
--------------------------------------------------------------------------------