use std::sync::{Arc, Mutex};
pub(crate) struct PlaybackState {
pub(crate) samples: Arc<Vec<f32>>,
pub(crate) source_channels: usize,
pub(crate) position_samples: usize,
pub(crate) playing: bool,
pub(crate) volume: f32,
}
impl PlaybackState {
pub(crate) fn new(samples: Arc<Vec<f32>>, source_channels: usize) -> Self {
Self {
samples,
source_channels,
position_samples: 0,
playing: true,
volume: 1.0,
}
}
}
pub(crate) fn seek_position_samples(
position_seconds: f64,
sample_rate: u32,
channels: usize,
sample_count: usize,
) -> Option<usize> {
if !position_seconds.is_finite() || position_seconds < 0.0 || sample_rate == 0 || channels == 0
{
return None;
}
let total_frames = sample_count / channels;
let requested_frame = (position_seconds * sample_rate as f64).floor() as usize;
Some(requested_frame.min(total_frames) * channels)
}
pub(crate) fn render_samples(
data: &mut [f32],
output_channels: usize,
playback: &Arc<Mutex<PlaybackState>>,
) {
if output_channels == 0 {
return;
}
let Ok(mut playback) = playback.lock() else {
data.fill(0.0);
return;
};
for output_frame in data.chunks_mut(output_channels) {
if !playback.playing
|| playback.position_samples + playback.source_channels > playback.samples.len()
{
output_frame.fill(0.0);
playback.playing = false;
continue;
}
let source_frame = &playback.samples
[playback.position_samples..playback.position_samples + playback.source_channels];
for (output_channel, sample) in output_frame.iter_mut().enumerate() {
let source_channel = output_channel * playback.source_channels / output_channels;
*sample = source_frame[source_channel] * playback.volume;
}
playback.position_samples += playback.source_channels;
}
}