play_at implemented

This commit is contained in:
Justine
2024-08-12 15:25:40 +02:00
parent c2591bc2a2
commit fdceee8e54
6 changed files with 192 additions and 135 deletions

View File

@ -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<Self, Box<dyn Error>> {
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<dyn Error>> {
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!();
}
}
}

View File

@ -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);
}

View File

@ -48,6 +48,7 @@ pub mod playlist {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Playlist {
pub songs: Vec<SongMeta>,
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<dyn Error>> {
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<dyn Error>> {
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;
}
}
}