1use eyre::{bail, Context, ContextCompat, Result};
2use ndarray::Array2;
3
4pub fn compute_fbank(samples: &[f32]) -> Result<Array2<f32>> {
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 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
47pub 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)]
54mod 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<f32> {
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; let frequency = 440.0; let waveform = generate_sine_wave(sample_rate, duration, frequency);
76 let features = compute_fbank(&waveform);
77 println!("features: {:?}", features);
78 }
79}