use crate::dsp::db::amplitude_to_db;
fn frame_to_sample(frame: usize, hop_length: usize) -> usize {
frame * hop_length
}
pub fn trim(y: &[f64], top_db: f64, frame_length: usize, hop_length: usize) -> (usize, usize) {
let non_silent = signal_to_frame_nonsilent(y, top_db, frame_length, hop_length);
let first = non_silent.iter().position(|&b| b);
let last = non_silent.iter().rposition(|&b| b);
match (first, last) {
(Some(f), Some(l)) => {
let start = frame_to_sample(f, hop_length);
let end = frame_to_sample(l + 1, hop_length).min(y.len());
(start, end)
}
_ => (0, 0),
}
}
pub fn split(
y: &[f64],
top_db: f64,
frame_length: usize,
hop_length: usize,
) -> Vec<(usize, usize)> {
let non_silent = signal_to_frame_nonsilent(y, top_db, frame_length, hop_length);
if non_silent.is_empty() {
return Vec::new();
}
let mut edges: Vec<usize> = Vec::new();
if non_silent[0] {
edges.push(0);
}
for i in 0..non_silent.len() - 1 {
if non_silent[i] != non_silent[i + 1] {
edges.push(i + 1);
}
}
if non_silent[non_silent.len() - 1] {
edges.push(non_silent.len());
}
let edges_samples: Vec<usize> = edges
.iter()
.map(|&e| frame_to_sample(e, hop_length).min(y.len()))
.collect();
edges_samples
.chunks(2)
.filter(|chunk| chunk.len() == 2)
.map(|chunk| (chunk[0], chunk[1]))
.collect()
}
fn signal_to_frame_nonsilent(
y: &[f64],
top_db: f64,
frame_length: usize,
hop_length: usize,
) -> Vec<bool> {
let rms = crate::spectral::rms(y, frame_length, hop_length, true);
if rms.is_empty() {
return Vec::new();
}
let ref_val = rms.iter().copied().fold(0.0_f64, f64::max);
let db = amplitude_to_db(&rms, ref_val, 1e-5, None);
db.iter().map(|&d| d > -top_db).collect()
}