From d17577639d3842baa0e4bf9afcfd2b4a096dd01b Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 13 Oct 2013 11:00:22 +0300 Subject: [PATCH] Externalize playlist management from Jukebox This enables playlists to be stored and loaded from files. There's also support for streaming from data packs. --- source/jukebox.cpp | 98 +++++++++--------------------------- source/jukebox.h | 18 +++---- source/playlist.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++++ source/playlist.h | 56 +++++++++++++++++++++ 4 files changed, 208 insertions(+), 84 deletions(-) create mode 100644 source/playlist.cpp create mode 100644 source/playlist.h diff --git a/source/jukebox.cpp b/source/jukebox.cpp index 52f673e..b753e6b 100644 --- a/source/jukebox.cpp +++ b/source/jukebox.cpp @@ -2,6 +2,7 @@ #include #include #include "jukebox.h" +#include "playlist.h" #include "sounddecoder.h" using namespace std; @@ -11,9 +12,10 @@ namespace AL { Jukebox::Jukebox(): streamer(source), + in(0), decoder(0), - current_track(tracks.end()), - shuffle(false) + playlist(0), + current(0) { } Jukebox::~Jukebox() @@ -22,100 +24,44 @@ Jukebox::~Jukebox() delete decoder; } -void Jukebox::add_track(const string &trk) -{ - bool was_empty = tracks.empty(); - tracks.push_back(trk); - if(was_empty) - { - current_track = tracks.begin(); - signal_track_changed.emit(*current_track); - } -} - -void Jukebox::remove_track(const string &trk) -{ - list::iterator i = find(tracks.begin(), tracks.end(), trk); - if(i!=tracks.end()) - { - if(i==current_track) - next(); - tracks.erase(i); - if(tracks.empty()) - current_track = tracks.end(); - } -} - -void Jukebox::clear_tracks() +void Jukebox::set_playlist(const Playlist *p) { + bool was_playing = decoder; stop(); - tracks.clear(); - current_track = tracks.end(); -} - -const string &Jukebox::get_current_track() const -{ - if(tracks.empty()) - throw logic_error("No current track"); - return *current_track; -} - -void Jukebox::set_shuffle(bool s) -{ - shuffle = s; + playlist = p; + if(playlist && was_playing) + play(); } void Jukebox::play() { - if(tracks.empty() || decoder) + if(!playlist || playlist->empty() || decoder) return; - decoder = SoundDecoder::open_file(*current_track); + in = playlist->open(current); + decoder = SoundDecoder::open_io(*in); streamer.play(*decoder); } void Jukebox::next() { + if(!playlist || playlist->empty()) + return; + stop(); - if(tracks.size()>1) - { - if(shuffle) - { - while(1) - { - list::iterator i = tracks.begin(); - advance(i, rand()%tracks.size()); - if(i!=current_track) - { - current_track = i; - break; - } - } - } - else - { - ++current_track; - if(current_track==tracks.end()) - current_track = tracks.begin(); - } - signal_track_changed.emit(*current_track); - } + current = playlist->advance(current, 1); + signal_track_changed.emit(current); play(); } void Jukebox::previous() { - if(shuffle) - return next(); + if(!playlist || playlist->empty()) + return; stop(); - if(tracks.size()>1) - { - if(current_track==tracks.begin()) - current_track = tracks.end(); - --current_track; - signal_track_changed.emit(*current_track); - } + current = playlist->advance(current, -1); + signal_track_changed.emit(current); play(); } @@ -124,6 +70,8 @@ void Jukebox::stop() streamer.stop(); delete decoder; decoder = 0; + delete in; + in = 0; } void Jukebox::tick() diff --git a/source/jukebox.h b/source/jukebox.h index fe17f2e..ea19723 100644 --- a/source/jukebox.h +++ b/source/jukebox.h @@ -4,37 +4,37 @@ #include #include #include +#include #include "source.h" #include "streamer.h" namespace Msp { namespace AL { +class Playlist; class SoundDecoder; class Jukebox { public: - sigc::signal signal_track_changed; + sigc::signal signal_track_changed; private: Source source; Streamer streamer; + IO::Seekable *in; SoundDecoder *decoder; - std::list tracks; - std::list::iterator current_track; - bool shuffle; + const Playlist *playlist; + unsigned current; public: Jukebox(); ~Jukebox(); Source &get_source() { return source; } - void add_track(const std::string &); - void remove_track(const std::string &); - void clear_tracks(); - const std::string &get_current_track() const; - void set_shuffle(bool); + void set_playlist(const Playlist *); + const Playlist *get_playlist() const { return playlist; } + unsigned get_current_track() const { return current; } void play(); void next(); diff --git a/source/playlist.cpp b/source/playlist.cpp new file mode 100644 index 0000000..10640ee --- /dev/null +++ b/source/playlist.cpp @@ -0,0 +1,120 @@ +#include +#include +#include "playlist.h" + +using namespace std; + +namespace Msp { +namespace AL { + +Playlist::Playlist(): + shuffle(false) +{ } + +void Playlist::add_track(const string &trk) +{ + tracks.push_back(trk); +} + +void Playlist::remove_track(const string &trk) +{ + for(vector::iterator i=tracks.begin(); i!=tracks.end(); ++i) + if(i->filename==trk) + { + tracks.erase(i); + break; + } +} + +void Playlist::clear_tracks() +{ + tracks.clear(); +} + +void Playlist::set_shuffle(bool s) +{ + shuffle = s; +} + +const string &Playlist::get_track(unsigned i) const +{ + if(i>=tracks.size()) + throw out_of_range("Playlist::get_track"); + return tracks[i].filename; +} + +unsigned Playlist::advance(unsigned i, int d) const +{ + unsigned s = tracks.size(); + if(i>=s) + throw out_of_range("Playlist::next_track"); + + if(shuffle) + { + if(s>1) + { + unsigned j = i; + while(j==i) + j = rand()%s; + i = j; + } + } + else if(d>0) + i = (i+d)%s; + else + i = s-1-(s-1-i-d)%s; + + return i; +} + +IO::Seekable *Playlist::open(unsigned i) const +{ + if(i>=tracks.size()) + throw out_of_range("Playlist::open"); + + const Track &track = tracks[i]; + if(track.collection) + return track.collection->open_raw(track.filename); + + return new IO::BufferedFile(track.filename); +} + + +Playlist::Track::Track(): + collection(0) +{ } + +Playlist::Track::Track(const string &fn): + collection(0), + filename(fn) +{ } + + +Playlist::Loader::Loader(Playlist &p): + DataFile::CollectionObjectLoader(p, 0) +{ + init(); +} + +Playlist::Loader::Loader(Playlist &p, Collection &c): + DataFile::CollectionObjectLoader(p, &c) +{ + init(); +} + +void Playlist::Loader::init() +{ + add("track", &Loader::track); + add("shuffle", &Playlist::shuffle); +} + +void Playlist::Loader::track(const string &fn) +{ + Track trk; + trk.collection = coll; + trk.filename = fn; + obj.tracks.push_back(trk); +} + +} // namespace AL +} // namespace Msp diff --git a/source/playlist.h b/source/playlist.h new file mode 100644 index 0000000..72226ad --- /dev/null +++ b/source/playlist.h @@ -0,0 +1,56 @@ +#ifndef MSP_AL_PLAYLIST_H_ +#define MSP_AL_PLAYLIST_H_ + +#include +#include +#include + +namespace Msp { +namespace AL { + +class Playlist +{ +public: + class Loader: public DataFile::CollectionObjectLoader + { + public: + Loader(Playlist &); + Loader(Playlist &, Collection &); + private: + void init(); + + void track(const std::string &); + }; + +private: + struct Track + { + const DataFile::Collection *collection; + std::string filename; + + Track(); + Track(const std::string &); + }; + + bool shuffle; + std::vector tracks; + +public: + Playlist(); + + void add_track(const std::string &); + void remove_track(const std::string &); + void clear_tracks(); + void set_shuffle(bool); + const std::string &get_track(unsigned) const; + unsigned size() const { return tracks.size(); } + bool empty() const { return tracks.empty(); } + + unsigned advance(unsigned, int = 1) const; + IO::Seekable *open(unsigned) const; +}; + +} // namespace AL +} // namespace Msp + +#endif -- 2.43.0