diff --git a/Cargo.lock b/Cargo.lock index e7ad10b..8562c16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -338,12 +338,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "extended" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365" - [[package]] name = "ffmpeg-next" version = "7.0.4" @@ -1031,28 +1025,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9" dependencies = [ "lazy_static", - "symphonia-bundle-flac", "symphonia-bundle-mp3", - "symphonia-codec-aac", - "symphonia-codec-adpcm", - "symphonia-codec-pcm", - "symphonia-codec-vorbis", - "symphonia-core", - "symphonia-format-isomp4", - "symphonia-format-riff", - "symphonia-metadata", -] - -[[package]] -name = "symphonia-bundle-flac" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e34f34298a7308d4397a6c7fbf5b84c5d491231ce3dd379707ba673ab3bd97" -dependencies = [ - "log", "symphonia-core", "symphonia-metadata", - "symphonia-utils-xiph", ] [[package]] @@ -1067,48 +1042,6 @@ dependencies = [ "symphonia-metadata", ] -[[package]] -name = "symphonia-codec-aac" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbf25b545ad0d3ee3e891ea643ad115aff4ca92f6aec472086b957a58522f70" -dependencies = [ - "lazy_static", - "log", - "symphonia-core", -] - -[[package]] -name = "symphonia-codec-adpcm" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94e1feac3327cd616e973d5be69ad36b3945f16b06f19c6773fc3ac0b426a0f" -dependencies = [ - "log", - "symphonia-core", -] - -[[package]] -name = "symphonia-codec-pcm" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f395a67057c2ebc5e84d7bb1be71cce1a7ba99f64e0f0f0e303a03f79116f89b" -dependencies = [ - "log", - "symphonia-core", -] - -[[package]] -name = "symphonia-codec-vorbis" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a98765fb46a0a6732b007f7e2870c2129b6f78d87db7987e6533c8f164a9f30" -dependencies = [ - "log", - "symphonia-core", - "symphonia-utils-xiph", -] - [[package]] name = "symphonia-core" version = "0.5.4" @@ -1122,31 +1055,6 @@ dependencies = [ "log", ] -[[package]] -name = "symphonia-format-isomp4" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfdf178d697e50ce1e5d9b982ba1b94c47218e03ec35022d9f0e071a16dc844" -dependencies = [ - "encoding_rs", - "log", - "symphonia-core", - "symphonia-metadata", - "symphonia-utils-xiph", -] - -[[package]] -name = "symphonia-format-riff" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f7be232f962f937f4b7115cbe62c330929345434c834359425e043bfd15f50" -dependencies = [ - "extended", - "log", - "symphonia-core", - "symphonia-metadata", -] - [[package]] name = "symphonia-metadata" version = "0.5.4" @@ -1159,16 +1067,6 @@ dependencies = [ "symphonia-core", ] -[[package]] -name = "symphonia-utils-xiph" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "484472580fa49991afda5f6550ece662237b00c6f562c7d9638d1b086ed010fe" -dependencies = [ - "symphonia-core", - "symphonia-metadata", -] - [[package]] name = "syn" version = "2.0.73" diff --git a/Cargo.toml b/Cargo.toml index 0b369a3..4028ddb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,6 @@ file-format = "0.25.0" metadata = "0.1.9" rand = "0.8.5" regex = "1.10.6" -rodio = { version = "0.19.0", features = ["symphonia-all"] } +rodio = "0.19.0" serde = { version = "1.0.206", features = ["derive"] } serde_yaml = "0.9.34" diff --git a/cool.yml b/cool.yml deleted file mode 100644 index 0b5ac91..0000000 --- a/cool.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -songs: -- title: Big Cheese - artist: Nirvana - album: Bleach - track: 12 - duration: - secs: 221 - nanos: 0 - cover_path: /home/justine/NAS/Musique/A_classer/Bleach/cover.jpg - path: /home/justine/NAS/Musique/A_classer/Bleach/12 Big Cheese.mp3 -- title: Dods... - artist: Galaverna - album: Dodsdans - track: 1 - duration: - secs: 148 - nanos: 0 - cover_path: /home/justine/NAS/Musique/Folk/Galaverna - Dodsdans/cover.jpg - path: /home/justine/NAS/Musique/Folk/Galaverna - Dodsdans/Galaverna - Dodsdans - 01 Dods....flac diff --git a/src/audioplayer.rs b/src/audioplayer.rs index e69de29..47dd724 100644 --- a/src/audioplayer.rs +++ b/src/audioplayer.rs @@ -0,0 +1,156 @@ +///Contains everything needed to play music. +///The player is akin to a virtual cassette player, where the audio files would be cassettes themselves, +///stored inside the playlist. +pub mod audioplayer { + + use std::fs::File; + use std::io::BufReader; + use std::path::{Path, PathBuf}; + use std::time::Duration; + use rodio::{Decoder, OutputStream, Sink, Source}; + use std::error::Error; + use std::fmt; + use crate::playlist::playlist::*; + use crate::songmeta::songmeta::*; + use std::io::{Read, Seek}; + + //-----------------------------------Errors + #[derive(Debug, Clone)] + pub enum PlayerError { + Something, + } + + ///Main error container for the player. + impl fmt::Display for PlayerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + PlayerError::Something => write!(f, "Uh-oh"), + } + } + } + + impl Error for PlayerError {} + + + //-----------------------------------------Structs + pub struct AudioPlayer { + ///A facility for controlling the playing of sound. + pub sink: Sink, + ///A handle to the sound device. Must live as long as the sink. + stream: OutputStream, + ///List of songs to pick from. + pub playlist: Playlist, + ///If true, the player will loop back to the beginning of the playlist when it's done + pub repeating: bool, + ///Stores the current state of the player, can be used as a source of truth for an UI. + pub state: PlayerState, + + } + + //-----------------------------------Enums + #[derive(Debug)] + pub enum PlayerState { + Playing, + Paused, + Stopped, + } + + //-------------------------------------Impls + + + + + impl AudioPlayer { + + ///Returns a new empty player to the default device. + pub fn new() -> Result> { + let (stream, stream_handle) = OutputStream::try_default()?; + let sink = Sink::try_new(&stream_handle)?; + let playlist = Playlist::new(); + + let me = Self { + sink: sink, + stream: stream, + playlist: playlist, + repeating: false, + state: PlayerState::Stopped, + }; + Ok(me) + } + + ///Plays all files in the playlist starting from index. + pub fn play_at(&mut self, index: usize) -> Result<(), Box> { + self.playlist.check_index(index.clone())?; + self.sink.clear(); + self.state = PlayerState::Paused; + for song in &self.playlist.songs[index..] { + let file = BufReader::new(File::open(&song.path)?); + let source = Decoder::new(file)?; + self.sink.append(source); + } + self.sink.play(); + self.state = PlayerState::Playing; + return Ok(()); + } + + fn get_current_song(&self) { + unimplemented!(); + } + + fn skip_forward(&mut self) { + unimplemented!(); + } + + fn skip_backwards(&mut self) { + unimplemented!(); + } + + fn pause(&mut self) { + unimplemented!(); + } + + fn unpause(&mut self) { + unimplemented!(); + } + + fn get_pos(&self) { + unimplemented!(); + } + + fn set_vol(&mut self, vol: f32) { + unimplemented!(); + } + + fn get_vol(&mut self) { + unimplemented!(); + } + + fn goto(&mut self, index: usize) { + unimplemented!(); + } + + fn press_shuffle(&mut self) { + unimplemented!(); + } + + fn press_repeat(&mut self) { + unimplemented!(); + } + + fn seek(&mut self, goto: Duration) { + unimplemented!(); + } + + fn stop(&mut self) { + unimplemented!(); + } + + fn load_file(&mut self) { + unimplemented!(); + } + + fn load_folder(&mut self) { + unimplemented!(); + } + } +} diff --git a/src/main.rs b/src/main.rs index ca29c8b..df6f1b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,14 +4,35 @@ use crate::songmeta::songmeta::*; pub mod playlist; use crate::playlist::playlist::*; +pub mod audioplayer; +use crate::audioplayer::audioplayer::*; + +use std::thread::sleep; +use std::time::Duration; + fn main() { - //let mysong = SongMeta::frompath(&String::from("/home/justine/NAS/Musique/A_classer/Bleach/12 Big Cheese.mp3")).unwrap(); - //let mysong2 = SongMeta::frompath(&String::from("/home/justine/NAS/Musique/Folk/Galaverna - Dodsdans/Galaverna - Dodsdans - 01 Dods....flac")).unwrap(); - //let mysong3 = SongMeta::frompath(&String::from("/home/justine/NAS/Musique/Jeux/Superliminal/Matt Christensen - Superliminal/12. Astral.mp3")).unwrap(); + let mysong = SongMeta::frompath(&String::from("/home/justine/NAS/Musique/A_classer/Bleach/12 Big Cheese.mp3")).unwrap(); + let mysong2 = SongMeta::frompath(&String::from("/home/justine/NAS/Musique/Folk/Galaverna - Dodsdans/Galaverna - Dodsdans - 01 Dods....flac")).unwrap(); + let mysong3 = SongMeta::frompath(&String::from("/home/justine/NAS/Musique/Jeux/Superliminal/Matt Christensen - Superliminal/12. Astral.mp3")).unwrap(); - let playlist = Playlist::from_file("./myplaylist.yml", true); + let mut playlist = Playlist::new(); + playlist.songs.push(mysong); + playlist.songs.push(mysong2); + playlist.songs.push(mysong3); + + let mut player = AudioPlayer::new().unwrap(); + + + player.playlist = playlist; + + player.play_at(0).unwrap(); + println!("{:?} {:?} {:?}", player.state, player.sink.volume(), player.sink.is_paused()); + sleep(Duration::from_secs(10)); + player.play_at(2).unwrap(); + loop { + dbg!(player.sink.get_pos()); + } - dbg!(playlist); } diff --git a/src/playlist.rs b/src/playlist.rs index b41e598..915e74e 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -48,6 +48,7 @@ pub mod playlist { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Playlist { pub songs: Vec, + pub shuffled: bool, } impl Playlist { @@ -55,6 +56,7 @@ pub mod playlist { pub fn new() -> Self { Self { songs: vec![], + shuffled: false, } } @@ -125,21 +127,19 @@ pub mod playlist { } ///Checks if a number is a valid index in this playlist. - pub fn check_index(&self, index: usize) -> bool { + pub fn check_index(&self, index: usize) -> Result<(), Box> { if self.songs.len() == 0 { - return false; + return Err(Box::new(PlaylistError::IndexNotFound)); } if index > (self.songs.len() - 1) { - return false; + return Err(Box::new(PlaylistError::IndexNotFound)); } - return true; + return Ok(()); } ///Removes a song at index (if possible) pub fn remove(&mut self, index: usize) -> Result<(), Box> { - if !self.check_index(index.clone()) { - return Err(Box::new(PlaylistError::IndexNotFound)); - } + self.check_index(index.clone())?; self.songs.remove(index); return Ok(()); } @@ -151,6 +151,7 @@ pub mod playlist { return; } self.songs.shuffle(&mut thread_rng()); + self.shuffled = true; } ///Sorts the playlist by artist, album, trackorder, title @@ -162,6 +163,7 @@ pub mod playlist { .then_with(|| a.track.cmp(&b.track)) .then_with(|| a.title.cmp(&b.title)) }); + self.shuffled = false; } } }