1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
extern crate libc;
use libc::c_int;
mod c;
use std::ffi::{CStr, CString};
use std::fmt::{self, Display};
use std::ptr;
#[derive(Debug)]
pub enum Status {
Success = 0,
OutOfMemory = 1,
IOError = 2,
InvalidArgument = 3,
Unknown = 4,
}
pub unsafe fn sample_rate() -> usize {
c::pv_sample_rate() as usize
}
pub unsafe fn version() -> &'static str {
CStr::from_ptr(c::pv_porcupine_version()).to_str().unwrap()
}
pub unsafe fn frame_length() -> usize {
c::pv_porcupine_frame_length() as usize
}
pub struct Object {
_object: *mut c::pv_porcupine_object_t,
}
unsafe impl Send for Object {}
impl Object {
pub unsafe fn new(
model_file_path: &str,
keyword_file_path: &str,
sensitivity: f32,
) -> Result<Self, Status> {
let mut _object: *mut c::pv_porcupine_object_t = ptr::null_mut();
let _model_file_path = CString::new(model_file_path).unwrap().into_raw();
let _keyword_file_path = CString::new(keyword_file_path).unwrap().into_raw();
let status = c::pv_porcupine_init(
_model_file_path,
_keyword_file_path,
sensitivity,
&mut _object,
);
if status != 0 {
return Err(status.into());
}
Ok(Object { _object })
}
pub unsafe fn new_multiple_keywords(
model_file_path: &str,
keyword_file_paths: &[&str],
sensitivities: &[f32],
) -> Result<Self, Status> {
let mut _object: *mut c::pv_porcupine_object_t = ptr::null_mut();
let _model_file_path = CString::new(model_file_path).unwrap().into_raw();
let _number_keywords = keyword_file_paths.len() as c_int;
let _keyword_file_paths: Vec<CString> = keyword_file_paths
.iter()
.map(|p| CString::new(*p).unwrap())
.collect();
let _keyword_file_paths: Vec<_> = _keyword_file_paths.iter().map(|p| p.as_ptr()).collect();
let status = c::pv_porcupine_multiple_keywords_init(
_model_file_path,
_number_keywords,
_keyword_file_paths.as_ptr() as *const *const i8,
sensitivities.as_ptr(),
&mut _object,
);
if status != 0 {
return Err(status.into());
}
Ok(Object { _object })
}
pub unsafe fn delete(&mut self) {
c::pv_porcupine_delete(self._object);
}
pub unsafe fn process(&self, pcm: &[i16]) -> Result<bool, Status> {
let mut detected = false;
let status = c::pv_porcupine_process(self._object, pcm.as_ptr(), &mut detected);
if status != 0 {
return Err(status.into());
}
Ok(detected)
}
pub unsafe fn process_multiple_keywords(&self, pcm: &[i16]) -> Result<isize, Status> {
let mut keyword_index: c_int = -1;
let status = c::pv_porcupine_multiple_keywords_process(
self._object,
pcm.as_ptr(),
&mut keyword_index,
);
if status != 0 {
return Err(status.into());
}
Ok(keyword_index as isize)
}
}
impl From<c::pv_status_t> for Status {
fn from(status: c::pv_status_t) -> Self {
match status {
0 => Status::Success,
1 => Status::OutOfMemory,
2 => Status::IOError,
3 => Status::InvalidArgument,
_ => Status::Unknown,
}
}
}
impl Display for Status {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Status::Success => write!(f, "Success"),
Status::OutOfMemory => write!(f, "Out Of Memory"),
Status::IOError => write!(f, "I/O Error"),
Status::InvalidArgument => write!(f, "Invalid Argument"),
_ => write!(f, "Unknown"),
}
}
}