play_at implemented
This commit is contained in:
@ -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!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
src/main.rs
31
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user