Skip to content

Commit d5bdf43

Browse files
committed
feat(py): support numpy inputs
1 parent 95640e5 commit d5bdf43

4 files changed

Lines changed: 21 additions & 4 deletions

File tree

bindings/py/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ crate-type = ["cdylib"]
1111
[dependencies]
1212
earshot = { path = "../.." }
1313
pyo3 = { version = "0.29", features = [ "extension-module", "abi3-py38" ] }
14+
numpy = "0.29"

bindings/py/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ classifiers = [
1616
"Topic :: Multimedia :: Sound/Audio :: Analysis",
1717
"Topic :: Scientific/Engineering :: Artificial Intelligence"
1818
]
19+
dependencies = ["numpy"]
1920

2021
[project.urls]
2122
Repository = "https://github.com/pykeio/earshot"

bindings/py/python/earshot/__init__.pyi

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from typing import Sequence
22

3+
import numpy
4+
35
__version__: str
46

57
class Detector:
@@ -15,7 +17,7 @@ class Detector:
1517
"""
1618
...
1719

18-
def predict_i16(self, frame: Sequence[int]) -> float:
20+
def predict_i16(self, frame: Sequence[int] | 'numpy.ndarray') -> float:
1921
"""
2022
Predicts the voice activity score of a single input frame of 16-bit PCM audio.
2123
@@ -28,7 +30,7 @@ class Detector:
2830
"""
2931
...
3032

31-
def predict_f32(self, frame: Sequence[float]) -> float:
33+
def predict_f32(self, frame: Sequence[float] | 'numpy.ndarray') -> float:
3234
"""
3335
Predicts the voice activity score of a single input frame of 32-bit floating-point PCM audio.
3436

bindings/py/src/lib.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use std::borrow::Cow;
2+
13
use earshot::{DefaultPredictor, Detector as RustDetector};
4+
use numpy::PyArrayLike1;
25
use pyo3::{exceptions::PyTypeError, prelude::*};
36

47
#[pyclass(module = "earshot._earshot")]
@@ -17,14 +20,24 @@ impl Detector {
1720
self.inner.reset();
1821
}
1922

20-
fn predict_i16(&mut self, frame: Vec<i16>) -> PyResult<f32> {
23+
fn predict_i16(&mut self, frame: PyArrayLike1<'_, i16>) -> PyResult<f32> {
24+
let frame = frame.as_array();
25+
let frame = frame
26+
.as_slice()
27+
.map(Cow::Borrowed)
28+
.unwrap_or_else(|| Cow::Owned(frame.iter().copied().collect::<Vec<_>>()));
2129
if frame.len() != 256 {
2230
return Err(PyErr::new::<PyTypeError, _>("frame must be exactly 256 samples"));
2331
}
2432
Ok(self.inner.predict_i16(&frame))
2533
}
2634

27-
fn predict_f32(&mut self, frame: Vec<f32>) -> PyResult<f32> {
35+
fn predict_f32(&mut self, frame: PyArrayLike1<'_, f32>) -> PyResult<f32> {
36+
let frame = frame.as_array();
37+
let frame = frame
38+
.as_slice()
39+
.map(Cow::Borrowed)
40+
.unwrap_or_else(|| Cow::Owned(frame.iter().copied().collect::<Vec<_>>()));
2841
if frame.len() != 256 {
2942
return Err(PyErr::new::<PyTypeError, _>("frame must be exactly 256 samples"));
3043
}

0 commit comments

Comments
 (0)