pub mod audio;
pub mod inference;
pub mod mel;
pub mod output;
pub mod postprocessing;
pub mod runtime;
use std::path::Path;
use anyhow::Result;
pub use audio::{load_audio, AudioData};
pub use inference::BeatInference;
pub use mel::MelProcessor;
pub use postprocessing::{BeatResult, PostProcessor};
pub use runtime::{InferenceRuntime, InferenceSession, Tensor};
const TARGET_SAMPLE_RATE: u32 = 22050;
pub struct BeatThis<S: InferenceSession> {
pub mel: MelProcessor<S>,
pub inference: BeatInference<S>,
pub post: PostProcessor,
}
impl<S: InferenceSession> BeatThis<S> {
pub fn new<R: InferenceRuntime<Session = S>>(
runtime: &R,
mel_model_path: &Path,
beat_model_path: &Path,
) -> Result<Self> {
let mel_session = runtime.load_model(mel_model_path)?;
let beat_session = runtime.load_model(beat_model_path)?;
Ok(Self {
mel: MelProcessor::new(mel_session),
inference: BeatInference::new(beat_session),
post: PostProcessor::default(),
})
}
pub fn process_file(&mut self, path: &Path) -> Result<BeatResult> {
let audio = load_audio(path, TARGET_SAMPLE_RATE)?;
self.process_audio(&audio.samples, audio.sample_rate)
}
pub fn process_audio(&mut self, samples: &[f32], sample_rate: u32) -> Result<BeatResult> {
let samples = if sample_rate != TARGET_SAMPLE_RATE {
audio::resample(samples.to_vec(), sample_rate, TARGET_SAMPLE_RATE)?
} else {
samples.to_vec()
};
let mel = self.mel.process(&samples)?;
let (beat_logits, downbeat_logits) = self.inference.process(&mel)?;
self.post.process(&beat_logits, &downbeat_logits)
}
}