design: Split playlist design
To keep the design readable, I split the playlist class (playlist.txt) from the playlist deck (deck.txt). Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
parent
a3cf5daa18
commit
9aa2bc7df1
207
design.txt
207
design.txt
|
@ -34,6 +34,7 @@ Files:
|
|||
audio.h
|
||||
database.h
|
||||
database.hpp
|
||||
deck.h
|
||||
file.h
|
||||
filter.h
|
||||
groups.h
|
||||
|
@ -46,6 +47,7 @@ Files:
|
|||
ocarina/lib/
|
||||
audio.cpp
|
||||
database.cpp
|
||||
deck.cpp
|
||||
file.cpp
|
||||
filter.cpp
|
||||
groups.cpp
|
||||
|
@ -239,7 +241,7 @@ Database: (lib/database.cpp)
|
|||
class IndexEntry : public DatabaseEntry {
|
||||
public:
|
||||
string key;
|
||||
vector<unsigned int> values;
|
||||
set<unsigned int> values;
|
||||
|
||||
const std::string &primary_key();
|
||||
void write(File &);
|
||||
|
@ -264,6 +266,7 @@ Database: (lib/database.cpp)
|
|||
void save();
|
||||
void clear();
|
||||
void print();
|
||||
void print_keys();
|
||||
|
||||
unsigned int insert(T);
|
||||
void delete(unsigned int);
|
||||
|
@ -273,7 +276,8 @@ Database: (lib/database.cpp)
|
|||
unsigned int first();
|
||||
unsigned int last();
|
||||
unsigned int next(unsigned int &);
|
||||
unsigned int find(const std::string &);
|
||||
unsigned int find_index(const std::string &);
|
||||
T &find(const std::string &);
|
||||
T &operator[](unsigned int);
|
||||
};
|
||||
|
||||
|
@ -303,6 +307,10 @@ Database: (lib/database.cpp)
|
|||
Following a similar format for writing to disk, print the
|
||||
database to the console in a human-readable format.
|
||||
|
||||
void Database :: print_keys()
|
||||
This function exists only if CONFIG_DEBUG is enabled.
|
||||
Print out the collected primary keys in the database.
|
||||
|
||||
template <class T>
|
||||
unsigned int Database :: insert(T &);
|
||||
Adds a new item to the db and marks it as valid. A reverse
|
||||
|
@ -642,162 +650,115 @@ endif /* CONFIG_DEBUG */
|
|||
|
||||
|
||||
Playlist: (lib/playlist.cpp)
|
||||
Playlists are a list of songs that the user has configured to play. I
|
||||
will create a pool of playlists that will be filled by user actions.
|
||||
|
||||
Playlists will be put on a "deck" that is used to give an order to the
|
||||
next songs played. When deck :: next() is called, find the first
|
||||
playlist with PL_ENABLED set and call that playlists next() function.
|
||||
|
||||
When a playlist is empty, remove it from the deck.
|
||||
Playlists are a list of songs that the user has requested to play.
|
||||
|
||||
- Flags:
|
||||
enum playlist_flags {
|
||||
PL_ENABLED (1 << 0),
|
||||
PL_RANDOM (1 << 1),
|
||||
PL_DRAIN (1 << 2),
|
||||
PL_LOCKED (1 << 2),
|
||||
};
|
||||
|
||||
- Playlist:
|
||||
class Playlist : public Database {
|
||||
class Playlist {
|
||||
private:
|
||||
database<track_id> tracks; /* Keyed on track id */
|
||||
vector<track_id> tracks;
|
||||
unsigned int cur;
|
||||
unsigned int flags;
|
||||
public:
|
||||
Playlist();
|
||||
void add(vector<track_id> &);
|
||||
void del(vector<track_id> &);
|
||||
Playlist(flags);
|
||||
unsigned int add(track_id);
|
||||
void del(playlist_id);
|
||||
void set_flag(playlist_flags);
|
||||
void unset_flag(playlist_flags);
|
||||
const unsigned int get_flags();
|
||||
unsigned int size()
|
||||
unsigned int size();
|
||||
|
||||
File &operator<<(File &);
|
||||
File &operator>>(File &);
|
||||
void write(File &);
|
||||
void read(File &);
|
||||
|
||||
void sort();
|
||||
void next();
|
||||
unsigned int next();
|
||||
}
|
||||
|
||||
File << flags << tracks.size() << tracks[0] << tracks[1] << ... << tracks[N];
|
||||
|
||||
- API
|
||||
Playlist :: Playlist(unsigned int flags);
|
||||
Create a new playlist with the appropriate flags set.
|
||||
|
||||
unsigned int Playlist :: add(unsigned int track_id);
|
||||
Add a new track to the tracks vector and return the index.
|
||||
|
||||
void del(unsigned int playlist_id);
|
||||
Erase tracks[playlist_id] from the tracks vector.
|
||||
|
||||
void set_flag(playlist_flags flag);
|
||||
void unset_flag(playlist_flags flag);
|
||||
Set or unset the given flag.
|
||||
|
||||
const unsigned int get_flags();
|
||||
Return the currently enabled flags.
|
||||
|
||||
unsigned int size();
|
||||
Return tracks.size();
|
||||
|
||||
void write(File &);
|
||||
void read(File &);
|
||||
Read or write the playlist to the file.
|
||||
|
||||
void sort();
|
||||
Sort a playlist in Artist -> Year -> Track number order.
|
||||
|
||||
unsigned int next();
|
||||
if (flags & PL_RANDOM):
|
||||
cur += rand() % tracks.size();
|
||||
else:
|
||||
cur += 1;
|
||||
|
||||
if (cur > = tracks.size())
|
||||
cur -= tracks.size();
|
||||
track = tracks[cur];
|
||||
|
||||
if (!(flags & PL_LOCKED)):
|
||||
tracks.erase(cur);
|
||||
return track;
|
||||
|
||||
|
||||
|
||||
Deck: (lib/deck.cpp)
|
||||
The playlist deck is used to hold the temporary playlists created by
|
||||
the user.
|
||||
|
||||
- Deck:
|
||||
list<Playlist> deck;
|
||||
unsigned int current_track;
|
||||
|
||||
File << current_track << deck.size() << endl;
|
||||
File << deck[0] << endl;
|
||||
File << deck[1] << endl;
|
||||
|
||||
- Deck:
|
||||
list<Playlist> deck;
|
||||
File << deck[0] << endl;
|
||||
File << deck[1] << endl;
|
||||
File << deck[N] << endl;
|
||||
|
||||
- API
|
||||
deck :: init();
|
||||
Read in the playlist file
|
||||
void deck :: init();
|
||||
Read in the playlist file.
|
||||
|
||||
deck :: new();
|
||||
Adds a new playlist to the deck
|
||||
unsigned int deck :: new();
|
||||
Adds a new playlist to the end of the deck and returns its id.
|
||||
The id is only valid until the deck is changed in some way.
|
||||
|
||||
deck :: rm(N)
|
||||
Removes playlist N from the deck
|
||||
void deck :: rm(N);
|
||||
Remove playlist N from the deck.
|
||||
|
||||
Playlist *deck :: get(N)
|
||||
Return playlist N from the deck
|
||||
Playlist *deck :: get(N);
|
||||
Return playlist N from the deck.
|
||||
|
||||
deck :: next()
|
||||
Play the next song from the deck
|
||||
unsigned int deck :: next();
|
||||
Iterate through the deck until you find a playlist with the
|
||||
flag PL_ENABLED set. Call next() on this playlist and return
|
||||
the result.
|
||||
|
||||
- TODO <<<<<
|
||||
What if each playlist has its own playlist_id for tracks? This would
|
||||
allow for simpler removals, since I won't need to search for a track id.
|
||||
I can easily create a function for mapping a list of playlist_ids to
|
||||
track_ids...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- API
|
||||
void playlist :: init();
|
||||
Read in the playlist file
|
||||
|
||||
* Playlist *playlist :: add();
|
||||
Add a new playlist to the deck, return the created playlist
|
||||
to the caller.
|
||||
|
||||
* void playlist :: remove(Playlist *);
|
||||
Remove the provided playlist from the deck. The pointer will
|
||||
be unusable after calling this function.
|
||||
|
||||
void playlist :: move(Playlist *, unsigned int);
|
||||
Move the playlist to the provided location in the deck.
|
||||
|
||||
* trackid_t playlist :: next()
|
||||
Return the next trackid from the top playlist on the playlist
|
||||
deck (id = deck[0].next()). If the top playlist is now empty,
|
||||
remove it.
|
||||
|
||||
void playlist :: prev()
|
||||
Keep a playlist :: Playlist recent(PL_ENABLED)
|
||||
Whenever next() is called, add the returned track to the front
|
||||
of this playlist, reset recent.cur to 0.
|
||||
When prev() is called, return recent.next();
|
||||
|
||||
trackid_t playlist :: Playlist :: next()
|
||||
If PL_RANDOM is set:
|
||||
Randomly pick a value between 1 and size(). Increment
|
||||
the cur pointer by this value, taking into account any
|
||||
roll over.
|
||||
Else:
|
||||
cur += 1, if cur == size(): cur = 0;
|
||||
|
||||
if PL_DRAIN is set:
|
||||
Remove the trackid pointed to by cur from the list and
|
||||
return its value.
|
||||
|
||||
return list[cur]
|
||||
|
||||
void playlist :: Playlist :: set_flag(flag);
|
||||
Set the user-requested flag
|
||||
|
||||
void playlist :: Playlist :: clear_flag(flag);
|
||||
Clear the user-requested flag
|
||||
|
||||
const unsigned int playlist :: Playlist :: get_flags();
|
||||
return flags
|
||||
|
||||
bool playlist :: Playlist :: play_row(unsigned int id);
|
||||
Call this fuction to play a song from the playlist. id matches
|
||||
up to the index in the playlist to play. Return true if the
|
||||
selected row should be removed from the playlist, false
|
||||
otherwise.
|
||||
|
||||
string playlist :: Playlist :: get_length()
|
||||
Calculate the length of the playlist and return a string
|
||||
in mm:ss format with the results.
|
||||
|
||||
unsigned int playlist :: Playlist :: size()
|
||||
Return the number of tracks in your playlist
|
||||
|
||||
unsigned int playlist :: Playlist :: current_index()
|
||||
Return the current index into the playlist
|
||||
|
||||
unsigned int playlist :: Playlist :: filter(string text)
|
||||
Set the current filter text
|
||||
|
||||
unsigned int playlist :: Playlist :: is_visible(id)
|
||||
Check if the playlist id is visible based on playlis text
|
||||
|
||||
* unsigned int playlist :: Playlist :: add_track(trackid_t)
|
||||
Add a new track to the playlist
|
||||
|
||||
* unsigned int playlist :: Playlist :: rm_track(playlistid_t)
|
||||
Remove a row from the playlist
|
||||
If the playlist is empty after calling next(), remove it from
|
||||
the deck.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
audio.cpp
|
||||
|
||||
== Depends ==
|
||||
playlist library
|
||||
deck library
|
||||
|
||||
Audio: (lib/audio.cpp)
|
||||
This file will introduce an "audio" namespace containing all of the
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
== Files ==
|
||||
ocarina/include/
|
||||
deck.h
|
||||
ocarina/lib/
|
||||
deck.cpp
|
||||
$HOME/.ocarina{-debug}/
|
||||
playlists.lst
|
||||
|
||||
== Depends ==
|
||||
playlist
|
||||
|
||||
Deck: (lib/deck.cpp)
|
||||
The playlist deck is used to hold the temporary playlists created by
|
||||
the user.
|
||||
|
||||
- Deck:
|
||||
list<Playlist> deck;
|
||||
unsigned int current_track;
|
||||
|
||||
File << current_track << deck.size() << endl;
|
||||
File << deck[0] << endl;
|
||||
File << deck[N] << endl;
|
||||
|
||||
- API
|
||||
void deck :: init();
|
||||
Read in the playlist file.
|
||||
|
||||
unsigned int deck :: new();
|
||||
Adds a new playlist to the end of the deck and returns its id.
|
||||
The id is only valid until the deck is changed in some way.
|
||||
|
||||
void deck :: rm(N);
|
||||
Remove playlist N from the deck.
|
||||
|
||||
Playlist *deck :: get(N);
|
||||
Return playlist N from the deck.
|
||||
|
||||
unsigned int deck :: next();
|
||||
Iterate through the deck until you find a playlist with the
|
||||
flag PL_ENABLED set. Call next() on this playlist and return
|
||||
the result.
|
||||
|
||||
If the playlist is empty after calling next(), remove it from
|
||||
the deck.
|
|
@ -3,166 +3,82 @@
|
|||
playlist.h
|
||||
ocarina/lib/
|
||||
playlist.cpp
|
||||
$HOME/.ocarina{-debug}/
|
||||
playlists.lst
|
||||
|
||||
== Depends ==
|
||||
database
|
||||
file
|
||||
|
||||
Playlist: (lib/playlist.cpp)
|
||||
Playlists are a list of songs that the user has configured to play. I
|
||||
will create a pool of playlists that will be filled by user actions.
|
||||
|
||||
Playlists will be put on a "deck" that is used to give an order to the
|
||||
next songs played. When deck :: next() is called, find the first
|
||||
playlist with PL_ENABLED set and call that playlists next() function.
|
||||
|
||||
When a playlist is empty, remove it from the deck.
|
||||
Playlists are a list of songs that the user has requested to play.
|
||||
|
||||
- Flags:
|
||||
enum playlist_flags {
|
||||
PL_ENABLED (1 << 0),
|
||||
PL_RANDOM (1 << 1),
|
||||
PL_DRAIN (1 << 2),
|
||||
PL_LOCKED (1 << 2),
|
||||
};
|
||||
|
||||
- Playlist:
|
||||
class Playlist : public Database {
|
||||
class Playlist {
|
||||
private:
|
||||
database<track_id> tracks; /* Keyed on track id */
|
||||
vector<track_id> tracks;
|
||||
unsigned int cur;
|
||||
unsigned int flags;
|
||||
public:
|
||||
Playlist();
|
||||
void add(vector<track_id> &);
|
||||
void del(vector<track_id> &);
|
||||
void set_flag(playlist_flags);
|
||||
const unsigned int get_flags();
|
||||
unsigned int size()
|
||||
Playlist(flags);
|
||||
unsigned int add(track_id);
|
||||
void del(playlist_id);
|
||||
unsigned int size();
|
||||
|
||||
File &operator<<(File &);
|
||||
File &operator>>(File &);
|
||||
void set_flag(playlist_flags);
|
||||
void unset_flag(playlist_flags);
|
||||
const unsigned int get_flags();
|
||||
|
||||
void write(File &);
|
||||
void read(File &);
|
||||
|
||||
void sort();
|
||||
void next();
|
||||
unsigned int next();
|
||||
}
|
||||
|
||||
File << flags << tracks.size() << tracks[0] << tracks[1] << ... << tracks[N];
|
||||
|
||||
- Deck:
|
||||
list<Playlist> deck;
|
||||
unsigned int current_track;
|
||||
|
||||
File << current_track << deck.size() << endl;
|
||||
File << deck[0] << endl;
|
||||
File << deck[1] << endl;
|
||||
|
||||
- Deck:
|
||||
list<Playlist> deck;
|
||||
File << deck[0] << endl;
|
||||
File << deck[1] << endl;
|
||||
File << deck[N] << endl;
|
||||
|
||||
- API
|
||||
deck :: init();
|
||||
Read in the playlist file
|
||||
Playlist :: Playlist(unsigned int flags);
|
||||
Create a new playlist with the appropriate flags set.
|
||||
|
||||
deck :: new();
|
||||
Adds a new playlist to the deck
|
||||
unsigned int Playlist :: add(unsigned int track_id);
|
||||
Add a new track to the tracks vector and return the index.
|
||||
|
||||
deck :: rm(N)
|
||||
Removes playlist N from the deck
|
||||
void del(unsigned int playlist_id);
|
||||
Erase tracks[playlist_id] from the tracks vector.
|
||||
|
||||
Playlist *deck :: get(N)
|
||||
Return playlist N from the deck
|
||||
void set_flag(playlist_flags flag);
|
||||
void unset_flag(playlist_flags flag);
|
||||
Set or unset the given flag.
|
||||
|
||||
deck :: next()
|
||||
Play the next song from the deck
|
||||
const unsigned int get_flags();
|
||||
Return the currently enabled flags.
|
||||
|
||||
- TODO <<<<<
|
||||
What if each playlist has its own playlist_id for tracks? This would
|
||||
allow for simpler removals, since I won't need to search for a track id.
|
||||
I can easily create a function for mapping a list of playlist_ids to
|
||||
track_ids...
|
||||
unsigned int size();
|
||||
Return tracks.size();
|
||||
|
||||
void write(File &);
|
||||
void read(File &);
|
||||
Read or write the playlist to the file.
|
||||
|
||||
void sort();
|
||||
Sort a playlist in Artist -> Year -> Track number order.
|
||||
|
||||
unsigned int next();
|
||||
if (flags & PL_RANDOM):
|
||||
cur += rand() % tracks.size();
|
||||
else:
|
||||
cur += 1;
|
||||
|
||||
if (cur > = tracks.size())
|
||||
cur -= tracks.size();
|
||||
track = tracks[cur];
|
||||
|
||||
|
||||
- API
|
||||
void playlist :: init();
|
||||
Read in the playlist file
|
||||
|
||||
* Playlist *playlist :: add();
|
||||
Add a new playlist to the deck, return the created playlist
|
||||
to the caller.
|
||||
|
||||
* void playlist :: remove(Playlist *);
|
||||
Remove the provided playlist from the deck. The pointer will
|
||||
be unusable after calling this function.
|
||||
|
||||
void playlist :: move(Playlist *, unsigned int);
|
||||
Move the playlist to the provided location in the deck.
|
||||
|
||||
* trackid_t playlist :: next()
|
||||
Return the next trackid from the top playlist on the playlist
|
||||
deck (id = deck[0].next()). If the top playlist is now empty,
|
||||
remove it.
|
||||
|
||||
void playlist :: prev()
|
||||
Keep a playlist :: Playlist recent(PL_ENABLED)
|
||||
Whenever next() is called, add the returned track to the front
|
||||
of this playlist, reset recent.cur to 0.
|
||||
When prev() is called, return recent.next();
|
||||
|
||||
trackid_t playlist :: Playlist :: next()
|
||||
If PL_RANDOM is set:
|
||||
Randomly pick a value between 1 and size(). Increment
|
||||
the cur pointer by this value, taking into account any
|
||||
roll over.
|
||||
Else:
|
||||
cur += 1, if cur == size(): cur = 0;
|
||||
|
||||
if PL_DRAIN is set:
|
||||
Remove the trackid pointed to by cur from the list and
|
||||
return its value.
|
||||
|
||||
return list[cur]
|
||||
|
||||
void playlist :: Playlist :: set_flag(flag);
|
||||
Set the user-requested flag
|
||||
|
||||
void playlist :: Playlist :: clear_flag(flag);
|
||||
Clear the user-requested flag
|
||||
|
||||
const unsigned int playlist :: Playlist :: get_flags();
|
||||
return flags
|
||||
|
||||
bool playlist :: Playlist :: play_row(unsigned int id);
|
||||
Call this fuction to play a song from the playlist. id matches
|
||||
up to the index in the playlist to play. Return true if the
|
||||
selected row should be removed from the playlist, false
|
||||
otherwise.
|
||||
|
||||
string playlist :: Playlist :: get_length()
|
||||
Calculate the length of the playlist and return a string
|
||||
in mm:ss format with the results.
|
||||
|
||||
unsigned int playlist :: Playlist :: size()
|
||||
Return the number of tracks in your playlist
|
||||
|
||||
unsigned int playlist :: Playlist :: current_index()
|
||||
Return the current index into the playlist
|
||||
|
||||
unsigned int playlist :: Playlist :: filter(string text)
|
||||
Set the current filter text
|
||||
|
||||
unsigned int playlist :: Playlist :: is_visible(id)
|
||||
Check if the playlist id is visible based on playlis text
|
||||
|
||||
* unsigned int playlist :: Playlist :: add_track(trackid_t)
|
||||
Add a new track to the playlist
|
||||
|
||||
* unsigned int playlist :: Playlist :: rm_track(playlistid_t)
|
||||
Remove a row from the playlist
|
||||
if (!(flags & PL_LOCKED)):
|
||||
tracks.erase(cur);
|
||||
return track;
|
||||
|
|
Loading…
Reference in New Issue