janitor

janitor
git clone https://git.prime8.dev/janitor.git
Log | Files | Refs | README | LICENSE

audio.rs (1603B)


      1 use anyhow::{Context, Result};
      2 use async_walkdir::DirEntry;
      3 use fon::{chan::Ch32, Audio};
      4 use itertools::Itertools;
      5 use knf_rs::compute_fbank;
      6 use rodio::{Decoder, Source};
      7 use std::io::Cursor;
      8 
      9 pub const SAMPLE_RATE: u32 = 16000;
     10 pub const NUM_FRAMES: usize = 1024;
     11 pub const NUM_MEL_BINS: usize = 128;
     12 
     13 pub async fn is_audio_file(entry: DirEntry) -> bool {
     14     if let Some(mime) = mime_guess::from_path(entry.path()).first() {
     15         mime.type_() == "audio"
     16     } else {
     17         false
     18     }
     19 }
     20 
     21 fn extract_samples(decoder: Decoder<Cursor<Vec<u8>>>) -> Result<(Box<[f32]>, u32)> {
     22     let channels = decoder.channels() as usize;
     23     let sample_rate = decoder.sample_rate();
     24     let samples = decoder
     25         .map(|sample| sample as f32 / i16::MAX as f32)
     26         .chunks(channels)
     27         .into_iter()
     28         .map(|chunk| chunk.into_iter().sum::<f32>() / channels as f32)
     29         .collect_vec()
     30         .into_boxed_slice();
     31     Ok((samples, sample_rate))
     32 }
     33 
     34 pub fn extract_audio(buffer: Vec<u8>) -> Result<Audio<Ch32, 1>> {
     35     let decoder = Decoder::new(Cursor::new(buffer)).context("Failed to decode audio")?;
     36     let (samples, sample_rate) = extract_samples(decoder)?;
     37     Ok(Audio::with_f32_buffer(sample_rate, samples))
     38 }
     39 
     40 pub fn resample(audio: &mut Audio<Ch32, 1>, target_sample_rate: u32) {
     41     *audio = Audio::with_audio(target_sample_rate, audio);
     42 }
     43 
     44 pub fn create_fbank(audio: &mut Audio<Ch32, 1>) -> Result<Box<[[f32; NUM_MEL_BINS]]>> {
     45     let samples = audio.as_f32_slice();
     46     let mut fbank = compute_fbank(samples)?;
     47     fbank.truncate(NUM_FRAMES);
     48     Ok(fbank.into_boxed_slice())
     49 }