use crate::error::GigasttError;
use crate::inference::{ENCODER_SUBSAMPLING, HOP_LENGTH};
const FRAME_SAMPLES: usize = HOP_LENGTH * ENCODER_SUBSAMPLING;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct WindowSpec {
single_pass_max: usize,
window: usize,
stride: usize,
}
impl WindowSpec {
pub(crate) fn new(single_pass_max: usize, window: usize, overlap: usize) -> Self {
let stride =
(window.saturating_sub(overlap) / FRAME_SAMPLES * FRAME_SAMPLES).max(FRAME_SAMPLES);
Self {
single_pass_max,
window,
stride,
}
}
pub(crate) fn window(&self) -> usize {
self.window
}
pub(crate) fn stride(&self) -> usize {
self.stride
}
pub(crate) fn single_pass_max(&self) -> usize {
self.single_pass_max
}
pub(crate) fn overlap(&self) -> usize {
self.window.saturating_sub(self.stride)
}
pub(crate) fn is_single_pass(&self, total: usize) -> bool {
total <= self.single_pass_max
}
#[cfg(feature = "file-decode")]
pub(crate) fn flat() -> Self {
Self::new(usize::MAX, usize::MAX, 0)
}
}
#[cfg(feature = "file-decode")]
pub(crate) struct WindowCursor {
spec: WindowSpec,
next_start: usize,
first: bool,
done: bool,
}
#[cfg(feature = "file-decode")]
impl WindowCursor {
pub(crate) fn new(spec: WindowSpec) -> Self {
Self {
spec,
next_start: 0,
first: true,
done: false,
}
}
pub(crate) fn is_done(&self) -> bool {
self.done
}
pub(crate) fn next_start(&self) -> usize {
self.next_start
}
pub(crate) fn spec(&self) -> WindowSpec {
self.spec
}
pub(crate) fn fill_target(&self) -> usize {
if self.first {
self.spec
.single_pass_max()
.saturating_add(1)
.max(self.spec.window().saturating_add(1))
} else {
self.next_start + self.spec.window() + 1
}
}
pub(crate) fn take(&mut self, avail_end: usize, eof: bool) -> Option<(usize, usize)> {
if self.done {
return None;
}
let start = self.next_start;
if self.first {
self.first = false;
if eof && avail_end <= self.spec.single_pass_max() {
self.done = true;
return Some((start, avail_end));
}
}
if start >= avail_end {
self.done = true;
return None;
}
let end = (start + self.spec.window()).min(avail_end);
if eof && end == avail_end {
self.done = true;
} else {
self.next_start = start + self.spec.stride();
}
Some((start, end))
}
}
#[cfg(feature = "file-decode")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ChannelSelect {
Mono,
One(usize),
}
pub(crate) struct PcmWindow<'a> {
pub(crate) start_sample: usize,
pub(crate) samples: &'a [f32],
}
pub(crate) trait PcmWindows {
fn spec(&self) -> WindowSpec;
fn next_window(&mut self) -> Result<Option<PcmWindow<'_>>, GigasttError>;
}
pub(crate) struct SliceWindows<'a> {
samples: &'a [f32],
spec: WindowSpec,
next_start: usize,
done: bool,
}
impl<'a> SliceWindows<'a> {
pub(crate) fn new(samples: &'a [f32], spec: WindowSpec) -> Self {
Self {
samples,
spec,
next_start: 0,
done: false,
}
}
}
impl PcmWindows for SliceWindows<'_> {
fn spec(&self) -> WindowSpec {
self.spec
}
fn next_window(&mut self) -> Result<Option<PcmWindow<'_>>, GigasttError> {
let total = self.samples.len();
if self.done || self.next_start >= total {
return Ok(None);
}
let start = self.next_start;
let end = (start + self.spec.window()).min(total);
if end == total {
self.done = true;
} else {
self.next_start = start + self.spec.stride();
}
Ok(Some(PcmWindow {
start_sample: start,
samples: &self.samples[start..end],
}))
}
}
#[cfg(feature = "file-decode")]
mod file;
#[cfg(feature = "file-decode")]
pub(crate) use file::FileWindows;
#[cfg(test)]
mod tests;
#[cfg(all(test, feature = "file-decode"))]
mod file_windows_tests;