847e4c1925
Let's just access the dbe_index variable directly. Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
270 lines
5.4 KiB
C++
270 lines
5.4 KiB
C++
/**
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
*/
|
|
#include <core/queue.h>
|
|
extern "C" {
|
|
#include <core/random.h>
|
|
}
|
|
#include <core/string.h>
|
|
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
|
|
static class DefaultNotifier : public QNotifier {
|
|
public:
|
|
DefaultNotifier() {};
|
|
void on_track_added(unsigned int pos) {};
|
|
void on_track_removed(unsigned int pos) {};
|
|
void on_track_updated(unsigned int pos) {};
|
|
} def_notify;
|
|
|
|
|
|
Queue :: Queue(unsigned int flags)
|
|
: _cur(-1), _flags(flags), _length(0), _notify(&def_notify)
|
|
{}
|
|
|
|
Queue :: Queue()
|
|
: _cur(-1), _flags(0), _length(0), _notify(&def_notify)
|
|
{}
|
|
|
|
Queue :: ~Queue()
|
|
{}
|
|
|
|
void Queue :: write(file &file)
|
|
{
|
|
file_writef(&file, "%u %zu", _flags, _tracks.size());
|
|
for (unsigned int i = 0; i < _tracks.size(); i++)
|
|
file_writef(&file, " %u", _tracks[i]->dbe_index);
|
|
}
|
|
|
|
void Queue :: read(file &file)
|
|
{
|
|
unsigned int n, id;
|
|
file_readf(&file, "%u %u", &_flags, &n);
|
|
_tracks.resize(n);
|
|
for (unsigned int i = 0; i < n; i++) {
|
|
file_readf(&file, "%u", &id);
|
|
_tracks[i] = track_get(id);
|
|
_length += _tracks[i]->tr_length;
|
|
}
|
|
}
|
|
|
|
void Queue :: set_flag(queue_flags flag)
|
|
{
|
|
_flags |= flag;
|
|
}
|
|
|
|
void Queue :: unset_flag(queue_flags flag)
|
|
{
|
|
_flags &= ~flag;
|
|
}
|
|
|
|
bool Queue :: has_flag(queue_flags flag)
|
|
{
|
|
return (_flags & flag) == (unsigned int)flag;
|
|
}
|
|
|
|
void Queue :: set_notifier(QNotifier *notify)
|
|
{
|
|
_notify = notify;
|
|
}
|
|
|
|
/*
|
|
* Returns:
|
|
* 0: lhs == rhs
|
|
* < 0: lhs < rhs, or rhs is empty
|
|
* > 0: lhs > rhs, or lhs is empty
|
|
*/
|
|
static inline int track_compare(struct track *lhs, struct track *rhs, sort_t field)
|
|
{
|
|
switch (field) {
|
|
case SORT_ARTIST:
|
|
return artist_compare(lhs->tr_artist, rhs->tr_artist);
|
|
case SORT_COUNT:
|
|
return lhs->tr_count - rhs->tr_count;
|
|
case SORT_GENRE:
|
|
return genre_compare(lhs->tr_genre, rhs->tr_genre);
|
|
case SORT_LENGTH:
|
|
return lhs->tr_length - rhs->tr_length;
|
|
case SORT_PLAYED:
|
|
return date_compare(&lhs->tr_date, &rhs->tr_date);
|
|
case SORT_TITLE:
|
|
return track_compare(lhs, rhs);
|
|
case SORT_TRACK:
|
|
return lhs->tr_track - rhs->tr_track;
|
|
case SORT_YEAR:
|
|
if (lhs->tr_album->al_year - rhs->tr_album->al_year != 0)
|
|
return lhs->tr_album->al_year - rhs->tr_album->al_year;
|
|
case SORT_ALBUM:
|
|
return album_compare(lhs->tr_album, rhs->tr_album);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool track_less_than(struct track *lhs, struct track *rhs,
|
|
std::vector<struct sort_info> &order)
|
|
{
|
|
int res;
|
|
|
|
for (unsigned int i = 0; i < order.size(); i++) {
|
|
if (order[i].ascending == true)
|
|
res = track_compare(lhs, rhs, order[i].field);
|
|
else
|
|
res = track_compare(rhs, lhs, order[i].field);
|
|
if (res == 0)
|
|
continue;
|
|
break;
|
|
}
|
|
return res < 0;
|
|
}
|
|
|
|
unsigned int Queue :: find_sorted_id(struct track *rhs)
|
|
{
|
|
struct track *lhs;
|
|
unsigned int begin = 0, end = (_tracks.size() - 1), mid;
|
|
|
|
if (_tracks.size() == 0)
|
|
return 0;
|
|
|
|
while (end > begin) {
|
|
mid = begin + ((end - begin) / 2);
|
|
lhs = _tracks[mid];
|
|
if (track_less_than(lhs, rhs, _sort_order))
|
|
begin = mid + 1;
|
|
else {
|
|
if (mid == begin)
|
|
return begin;
|
|
else
|
|
end = mid - 1;
|
|
}
|
|
}
|
|
|
|
lhs = _tracks[begin];
|
|
if (track_less_than(lhs, rhs, _sort_order))
|
|
return begin + 1;
|
|
return begin;
|
|
}
|
|
|
|
unsigned int Queue :: _add_at(struct track *track, unsigned int pos)
|
|
{
|
|
_tracks.insert(_tracks.begin() + pos, track);
|
|
_length += track->tr_length;
|
|
_notify->on_track_added(pos);
|
|
return pos;
|
|
}
|
|
|
|
unsigned int Queue :: add(struct track *track)
|
|
{
|
|
unsigned int id = _tracks.size();
|
|
if (_sort_order.size() > 0)
|
|
id = find_sorted_id(track);
|
|
return _add_at(track, id);
|
|
}
|
|
|
|
void Queue :: del(unsigned int index)
|
|
{
|
|
_length -= _tracks[index]->tr_length;
|
|
_tracks.erase(_tracks.begin() + index);
|
|
_notify->on_track_removed(index);
|
|
}
|
|
|
|
void Queue :: del(struct track *track)
|
|
{
|
|
for (unsigned int i = 0; i < _tracks.size(); i++) {
|
|
while ((i < _tracks.size()) && (_tracks[i] == track))
|
|
del(i);
|
|
}
|
|
}
|
|
|
|
void Queue :: updated(struct track *track)
|
|
{
|
|
for (unsigned int i = 0; i < _tracks.size(); i++) {
|
|
if (_tracks[i] == track)
|
|
_notify->on_track_updated(i);
|
|
}
|
|
}
|
|
|
|
struct track *Queue :: next()
|
|
{
|
|
struct track *res;
|
|
|
|
if (_tracks.size() == 0)
|
|
return NULL;
|
|
else if (_tracks.size() == 1)
|
|
_cur = 0;
|
|
else if (_flags & Q_RANDOM)
|
|
_cur += random_range(1, _tracks.size() / 2);
|
|
else
|
|
_cur++;
|
|
|
|
_cur %= _tracks.size();
|
|
res = _tracks[_cur];
|
|
if (!(_flags & Q_REPEAT)) {
|
|
del(_cur);
|
|
_cur--;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
unsigned int Queue :: size()
|
|
{
|
|
return _tracks.size();
|
|
}
|
|
|
|
unsigned int Queue :: length()
|
|
{
|
|
return _length;
|
|
}
|
|
|
|
class SortTracks {
|
|
public:
|
|
std::vector<struct sort_info> fields;
|
|
SortTracks(std::vector<sort_info> f) : fields(f) {}
|
|
bool operator()(struct track *lhs, struct track *rhs)
|
|
{
|
|
return track_less_than(lhs, rhs, fields);
|
|
}
|
|
};
|
|
|
|
void Queue :: sort(sort_t field, bool reset)
|
|
{
|
|
bool found = false;
|
|
struct sort_info info = { field, true };
|
|
|
|
if (_flags & Q_NO_SORT)
|
|
return;
|
|
if (reset)
|
|
_sort_order.clear();
|
|
|
|
for (unsigned int i = 0; i < _sort_order.size(); i++) {
|
|
if (_sort_order[i].field == info.field) {
|
|
_sort_order[i].ascending = !_sort_order[i].ascending;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
_sort_order.push_back(info);
|
|
|
|
std::stable_sort(_tracks.begin(), _tracks.end(), SortTracks(_sort_order));
|
|
|
|
for (unsigned int i = 0; i < _tracks.size(); i++)
|
|
_notify->on_track_updated(i);
|
|
}
|
|
|
|
struct track *Queue :: operator[](unsigned int index)
|
|
{
|
|
return _tracks[index];
|
|
}
|
|
|
|
void Queue :: track_selected(unsigned int index)
|
|
{
|
|
_cur = index;
|
|
if (has_flag(Q_REPEAT) == false) {
|
|
del(_cur);
|
|
_cur--;
|
|
}
|
|
}
|