playtree: --shuffle shouldn't make playlist navigation useless

When --shuffle was used, the pt_step -1 jumped to the next file, instead
of the previously played file. This was because the playtree entries were
never actually shuffled, but instead a random unplayed file was picked.
Fix this by actually shuffling the playtree in advance. I couldn't see any
clear location where exactly this should happen, so it's done when a
playtree iterator is created.

Not removing the old code, since new playtree entries could be added while
an iterator is active.
This commit is contained in:
wm4 2011-11-30 08:28:18 +01:00
parent 3b03f4995d
commit 34b22ec6ea
1 changed files with 54 additions and 0 deletions

View File

@ -411,6 +411,58 @@ play_tree_iter_push_params(play_tree_iter_t* iter) {
iter->entry_pushed = 1;
}
// Shuffle the tree if the PLAY_TREE_RND flag is set, and unset it.
// This is done recursively, but only the siblings with the same parent are
// shuffled with each other.
static void shuffle_tree(play_tree_t *pt) {
if (!pt)
return;
int count = 0;
play_tree_t *child = pt->child;
while (child) {
// possibly shuffle children
shuffle_tree(child);
child = child->next;
count++;
}
if (pt->flags & PLAY_TREE_RND) {
// Move a random element to the front and go to the next, until no
// elements are left.
// prev = pointer to next-link to the first yet-unshuffled entry
play_tree_t** prev = &pt->child;
while (count > 1) {
int n = (int)((double)(count) * rand() / (RAND_MAX + 1.0));
// move = element that is moved to front (inserted after prev)
play_tree_t **before_move = prev;
play_tree_t *move = *before_move;
while (n > 0) {
before_move = &move->next;
move = *before_move;
n--;
}
// unlink from old list
*before_move = move->next;
// insert between prev and the following element
// note that move could be the first unshuffled element
move->next = (*prev == move) ? move->next : *prev;
*prev = move;
prev = &move->next;
count--;
}
// reconstruct prev links
child = pt->child;
play_tree_t *prev_child = NULL;
while (child) {
child->prev = prev_child;
prev_child = child;
child = child->next;
}
pt->flags = pt->flags & ~PLAY_TREE_RND;
}
}
play_tree_iter_t*
play_tree_iter_new(play_tree_t* pt,m_config_t* config) {
play_tree_iter_t* iter;
@ -430,6 +482,8 @@ play_tree_iter_new(play_tree_t* pt,m_config_t* config) {
iter->tree = NULL;
iter->config = config;
shuffle_tree(pt);
if(pt->parent)
iter->loop = pt->parent->loop;