//! Silence operations: insert silence at a position or remove a range of silence. use crate::error::CoreError; /// Insert silence (zeros) at the given frame position for the specified duration. /// /// Operates on interleaved sample data. Positions are in frame units. pub fn apply_insert_silence( samples: &mut Vec, channels: u16, start_frame: usize, duration_frames: usize, ) -> Result<(), CoreError> { let ch = channels as usize; if ch == 0 { return Err(CoreError::Internal("insert_silence: channels must be > 0".to_string())); } let total_frames = samples.len() / ch; if start_frame > total_frames { return Err(CoreError::Internal(format!( "insert_silence: start_frame ({start_frame}) exceeds total frames ({total_frames})" ))); } if duration_frames == 0 { return Ok(()); } let insert_at = start_frame * ch; let insert_count = duration_frames * ch; samples.splice(insert_at..insert_at, std::iter::repeat_n(0.0f32, insert_count)); Ok(()) } /// Remove a range of samples (typically silence) between two frame positions. /// /// Operates on interleaved sample data. `start_frame` inclusive, `end_frame` exclusive. pub fn apply_remove_range( samples: &mut Vec, channels: u16, start_frame: usize, end_frame: usize, ) -> Result<(), CoreError> { let ch = channels as usize; if ch == 0 { return Err(CoreError::Internal("remove_range: channels must be > 0".to_string())); } let total_frames = samples.len() / ch; if start_frame >= end_frame { return Err(CoreError::Internal( "remove_range: start_frame must be less than end_frame".to_string(), )); } if end_frame > total_frames { return Err(CoreError::Internal(format!( "remove_range: end_frame ({end_frame}) exceeds total frames ({total_frames})" ))); } let start_sample = start_frame * ch; let end_sample = end_frame * ch; samples.drain(start_sample..end_sample); Ok(()) } #[cfg(test)] mod tests { use super::*; #[test] fn insert_silence_mono_middle() { let mut samples = vec![1.0, 2.0, 3.0]; apply_insert_silence(&mut samples, 1, 1, 2).unwrap(); assert_eq!(samples, vec![1.0, 0.0, 0.0, 2.0, 3.0]); } #[test] fn insert_silence_stereo_start() { let mut samples = vec![1.0, 2.0, 3.0, 4.0]; // 2 frames stereo apply_insert_silence(&mut samples, 2, 0, 1).unwrap(); assert_eq!(samples, vec![0.0, 0.0, 1.0, 2.0, 3.0, 4.0]); } #[test] fn insert_silence_at_end() { let mut samples = vec![1.0, 2.0, 3.0]; apply_insert_silence(&mut samples, 1, 3, 2).unwrap(); assert_eq!(samples, vec![1.0, 2.0, 3.0, 0.0, 0.0]); } #[test] fn insert_silence_zero_duration_noop() { let mut samples = vec![1.0, 2.0, 3.0]; apply_insert_silence(&mut samples, 1, 1, 0).unwrap(); assert_eq!(samples, vec![1.0, 2.0, 3.0]); } #[test] fn insert_silence_out_of_bounds() { let mut samples = vec![1.0, 2.0, 3.0]; assert!(apply_insert_silence(&mut samples, 1, 10, 1).is_err()); } #[test] fn remove_range_mono() { let mut samples = vec![1.0, 0.0, 0.0, 2.0, 3.0]; apply_remove_range(&mut samples, 1, 1, 3).unwrap(); assert_eq!(samples, vec![1.0, 2.0, 3.0]); } #[test] fn remove_range_stereo() { let mut samples = vec![1.0, 2.0, 0.0, 0.0, 3.0, 4.0]; // 3 stereo frames apply_remove_range(&mut samples, 2, 1, 2).unwrap(); assert_eq!(samples, vec![1.0, 2.0, 3.0, 4.0]); } #[test] fn remove_range_invalid() { let mut samples = vec![1.0, 2.0, 3.0]; assert!(apply_remove_range(&mut samples, 1, 2, 1).is_err()); } #[test] fn remove_range_out_of_bounds() { let mut samples = vec![1.0, 2.0, 3.0]; assert!(apply_remove_range(&mut samples, 1, 0, 10).is_err()); } }