From d96b9b6cbd5fe06c5c3350ecd1f36be85913101c Mon Sep 17 00:00:00 2001 From: aprzn Date: Thu, 2 Mar 2023 01:50:06 -0500 Subject: [PATCH] audio plays, but pausing and playing again fails --- src/main.rs | 48 +++++++++++++++++++++++++++++++++--------------- src/music.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8c391f4..2916495 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,10 +86,10 @@ struct WizardData { struct Song { name: String, id: i64, - buffer: rodio::buffer::SamplesBuffer, - length: time::Duration, + source: rodio::source::Buffered>, stream: rodio::OutputStream, sink: rodio::Sink, + playing: bool, } #[derive(Error, Debug)] @@ -219,23 +219,34 @@ impl Song { (Err(err), Err(_)) => return Err(err.into()), }; - let decoder = rodio::Decoder::new_mp3(file)?; - - let channels = decoder.channels(); - let sample_rate = decoder.sample_rate(); - let samples: Vec = decoder.collect(); - - let length = time::Duration::from_secs(samples.len() as u64 / channels as u64 / sample_rate as u64); - let buffer = rodio::buffer::SamplesBuffer::new(channels, sample_rate, samples); + let source = rodio::Decoder::new_mp3(file)?.buffered(); let (stream, stream_handle) = rodio::OutputStream::try_default()?; let sink = rodio::Sink::try_new(&stream_handle)?; - Ok(Self { name, id, buffer, length, stream, sink }) + Ok(Self { name, id, source, stream, sink, playing: false }) } else { Err(SongError::NotNewgrounds) } } + + pub fn length(&self) -> time::Duration { + self.source.total_duration().expect("the source should have a well-defined duration") + } + + pub fn play_from(&mut self, position: time::Duration) { + self.playing = true; + self.sink.append(self.source.clone().skip_duration(position)) + } + + pub fn stop(&mut self) { + self.playing = false; + self.sink.stop(); + } + + pub fn playing(&self) -> bool { + self.playing + } } impl Editor { @@ -270,14 +281,21 @@ impl Editor { /// points in width of entire song fn song_width(&self, song: &Song) -> f64 { - song.length.as_secs_f64() * self.state.pts_per_second + song.length().as_secs_f64() * self.state.pts_per_second } - fn play_pause(&self, song: &Song) { - todo!("toggle song playback") + fn play_pause(&self, song: &mut Song) { + if song.playing() { + println!("stopping"); + song.stop(); + } else { + println!("starting"); + song.play_from(time::Duration::default()); + } + // todo!("toggle song playback") } - fn handle_keyboard_input(&mut self, ctx: &egui::Context, song: &Song) { + fn handle_keyboard_input(&mut self, ctx: &egui::Context, song: &mut Song) { use egui::Key; use egui::Event; ctx.input().events diff --git a/src/music.rs b/src/music.rs index b7683ac..b04fe95 100644 --- a/src/music.rs +++ b/src/music.rs @@ -1,6 +1,7 @@ use std::time::Duration; use ordered_float::OrderedFloat as Float; use std::collections::{BTreeMap, BTreeSet}; +use rodio::{Source, Sample}; pub type BeatPosition = Float; @@ -172,6 +173,43 @@ where } } +// #[derive(Debug, Clone, Copy, PartialEq, Eq)] +// struct SamplesSlice<'a, T: Sample, const N: usize> { +// samples: &'a [T], +// frame_changes: [usize; N], +// channel_counts: &'a [u16; N], +// sample_rates: &'a [u32; N], +// position: usize, +// } + +// impl Iterator for SamplesSlice<'_, T, N> { +// type Item = T; + +// fn next(&mut self) -> Option { +// self.position += 1; +// self.samples.get(self.position - 1).map(|x| *x) +// } +// } + +// impl Source for SamplesSlice<'_, T, N> { +// fn current_frame_len(&self) -> Option { +// self.frame_changes.iter().find(|&f| f > &self.position).map(|f| f - self.position) +// } + +// fn channels(&self) -> u16 { +// *self.frame_changes.iter().zip(self.channel_counts).rfind(|(&f, _)| f <= self.position).expect("there will always be a frame change before the current position").1 +// } + +// fn sample_rate(&self) -> u32 { +// *self.frame_changes.iter().zip(self.sample_rates).rfind(|(&f, _)| f <= self.position).expect("there will always be a frame change before the current position").1 +// } + +// fn total_duration(&self) -> Option { +// todo!() +// } +// } + + #[cfg(test)] mod tests { use super::*;