ref: 524e32b1cd45a332c58b8cd681662f815628deee
parent: 13eb015acabef04e4b983dee43c376318c6726c0
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Thu May 28 14:06:46 EDT 2020
add shuffled mode
--- a/README.md
+++ b/README.md
@@ -39,15 +39,16 @@
+ volume up
left/right seek backwards/forward (10 seconds step)
-,/. seek backwards/forward (one minute step)
-up/down/pgup/pgdn/home/end move within the playlist
+, . seek backwards/forward (one minute step)
+up down pgup pgdn home end move within the playlist
o move to the currently playing track
enter play the selected track
-> skip next
-< skip prev
-s stop
-p pause/resume
+> b skip next
+< z skip prev
+v stop
+p c pause/resume
+s toggle shuffle
q/del quit
/ search forward
--- /dev/null
+++ b/shuffle.c
@@ -1,0 +1,92 @@
+#include "shuffle.h"
+
+void
+shuffle_init(Shuffle *s, int (*rndrange)(int max_excluding), int total, int first)
+{
+ assert(first < total && total > 0);
+ s->m = s->n = total;
+ s->i = 0;
+ s->xi = s->x0 = first;
+
+ if(total < 4){
+ s->a = 1;
+ s->c = 3;
+ s->m = 7;
+ return;
+ }
+
+ s->m += 1;
+ s->m |= s->m >> 1;
+ s->m |= s->m >> 2;
+ s->m |= s->m >> 4;
+ s->m |= s->m >> 8;
+ s->m |= s->m >> 16;
+
+ s->a = 1 + rndrange(s->m/4)*4; /* 1 ≤ a < m && a mod 4 = 1 */
+ s->c = 3 + rndrange((s->m-2)/2)*2; /* 3 ≤ c < m-1 && c mod 2 = 1 */
+}
+
+void
+shuffle_resize(Shuffle *s, int total)
+{
+ assert(total > 0);
+ s->n = total;
+}
+
+static int
+next(Shuffle *s)
+{
+ int res;
+
+ res = s->xi;
+ if(s->n < 2){
+ /* if it's less than two items, just use the first one (if any) */
+ s->x0 = s->xi = s->i = 0;
+ return 0;
+ }else if(s->x0 >= s->n){
+ /* if items were removed up to this one -- update for a period */
+ s->x0 = 0;
+ }
+
+ for(;;){
+ s->xi = (s->a*s->xi + s->c) & s->m;
+ if(s->xi < s->n){
+ s->i++;
+ if(s->xi == s->x0)
+ s->i = 0;
+ break;
+ }
+ }
+
+ return res;
+}
+
+int
+shuffle_one(Shuffle *s, int index)
+{
+ if(s->n < 1 || index < 0)
+ return index;
+ index %= s->n;
+ while(s->i < s->n && s->i != index)
+ next(s);
+
+ return next(s);
+}
+
+int
+shuffle_for(Shuffle *s, int index)
+{
+ int i, r;
+
+ if(index < 0 || index >= s->n)
+ return index;
+ for(i = 0; i < s->n; i++){
+ r = s->i;
+ if(next(s) == index){
+ next(s);
+ return r;
+ }
+ }
+
+ return index;
+}
--- /dev/null
+++ b/shuffle.h
@@ -1,0 +1,11 @@
+typedef struct Shuffle Shuffle;
+
+struct Shuffle {
+ int i, n;
+ int m, a, c, x0, xi;
+};
+
+void shuffle_init(Shuffle *s, int (*rndrange)(int max_excluding), int total, int first);
+void shuffle_resize(Shuffle *s, int total);
+int shuffle_one(Shuffle *s, int index);
+int shuffle_for(Shuffle *s, int index);
--- a/zuke.c
+++ b/zuke.c
@@ -1,4 +1,5 @@
#include "theme.c"
+#include "shuffle.c"
#include <mouse.h>
#include <keyboard.h>
#include <ctype.h>
@@ -57,6 +58,8 @@
static int entering;
static int colwidth[3];
static int mincolwidth[3];
+static Shuffle shuffle;
+static int shuffled;
static char *covers[] = {"folder", "cover", "Cover", "scans/CD", "Scans/Front", "Covers/Front"};
static char *menu3i[] = {
@@ -111,6 +114,12 @@
colwidth[i] = (Dx(screen->r) - 8) * mincolwidth[i] / total;
}
+static Meta *
+getmeta(int i)
+{
+ return &pl[shuffled ? shuffle_one(&shuffle, i) : i];
+}
+
static void
redraw(int full)
{
@@ -187,17 +196,17 @@
p.x = left + 2;
sel.max.x = p.x + colwidth[0];
replclipr(screen, 0, sel);
- string(screen, p, col, sp, f, pl[i].artist[0]);
+ string(screen, p, col, sp, f, getmeta(i)->artist[0]);
p.x += colwidth[0] + 8;
sel.min.x = p.x;
sel.max.x = p.x + colwidth[1];
replclipr(screen, 0, sel);
- string(screen, p, col, sp, f, pl[i].album);
+ string(screen, p, col, sp, f, getmeta(i)->album);
p.x += colwidth[1] + 8;
sel.min.x = p.x;
sel.max.x = p.x + colwidth[2];
replclipr(screen, 0, sel);
- string(screen, p, col, sp, f, pl[i].title);
+ string(screen, p, col, sp, f, getmeta(i)->title);
replclipr(screen, 0, r);
@@ -214,9 +223,9 @@
}
if(pcurplaying >= 0)
- snprint(tmp, sizeof(tmp), "%P/%P %d%%", (int)(byteswritten/Bps), pl[pcurplaying].duration/1000, volume);
+ snprint(tmp, sizeof(tmp), "%s%P/%P %d%%", shuffled ? "∫ " : "", (int)(byteswritten/Bps), getmeta(pcurplaying)->duration/1000, volume);
else
- snprint(tmp, sizeof(tmp), "%d%%", volume);
+ snprint(tmp, sizeof(tmp), "%s%d%%", shuffled ? "∫ " : "", volume);
r = screen->r;
r.min.x = r.max.x - stringwidth(f, tmp) - 4;
r.min.y = r.max.y - f->height - 4;
@@ -257,7 +266,7 @@
threadsetname("cover");
player = player_;
- m = &pl[player->pcur];
+ m = getmeta(player->pcur);
pid = -1;
ch = player->img;
fd = -1;
@@ -405,7 +414,7 @@
pid = -1;
restart:
- if((fd = open(pl[player->pcur].path, OREAD)) < 0){
+ if((fd = open(getmeta(player->pcur)->path, OREAD)) < 0){
fprint(2, "%r\n");
sendul(player->ev, Everror);
goto freeplayer;
@@ -417,7 +426,7 @@
dup(fd, 0); close(fd);
dup(open("/dev/null", OWRITE), 2);
close(p[1]);
- snprint(cmd, sizeof(cmd), "/bin/audio/%sdec", pl[player->pcur].filefmt);
+ snprint(cmd, sizeof(cmd), "/bin/audio/%sdec", getmeta(player->pcur)->filefmt);
execl(cmd, cmd, nil);
sysfatal("execl: %r");
}
@@ -672,7 +681,7 @@
char *s, *snext;
static char buf[48];
static int sz;
- int inc;
+ int inc, i;
inc = (d == '/' || d == 'n') ? 1 : -1;
if(d == '/' || d == '?'){
@@ -680,10 +689,11 @@
sz = enter(inc > 0 ? "forward:" : "backward:", buf, sizeof(buf), mctl, kctl, nil);
entering = 0;
}
- if(sz < 1 || (inc > 0 && pcur >= plnum-1) || (inc < 0 && pcur < 1))
+ i = getmeta(pcur) - pl;
+ if(sz < 1 || (inc > 0 && i >= plnum-1) || (inc < 0 && i < 1))
return;
- s = pl[pcur + (inc > 0 ? 0 : -1)].path;
+ s = pl[i + (inc > 0 ? 0 : -1)].path;
s += strlen(s) + 1;
for(; s > plraw && s < plraw+plrawsize-sz; s += inc){
if(cistrncmp(s, buf, sz) != 0)
@@ -697,7 +707,7 @@
}
for(s--; s != plraw; s--){
if(memcmp(s, "\0# ", 3) == 0 && isdigit(s[3])){
- pcur = atoi(s+3);
+ pcur = shuffled ? shuffle_for(&shuffle, atoi(s+3)) : atoi(s+3);
redraw(1);
return;
}
@@ -753,6 +763,20 @@
close(f);
}
+static void
+toggleshuffle(void)
+{
+ shuffled = !shuffled;
+ if(shuffled){
+ shuffle_init(&shuffle, nrand, plnum, pcurplaying < 0 ? pcur : pcurplaying);
+ pcur = shuffle_for(&shuffle, pcur);
+ pcurplaying = shuffle_for(&shuffle, pcurplaying);
+ }else{
+ pcur = shuffle_one(&shuffle, pcur);
+ pcurplaying = shuffle_one(&shuffle, pcurplaying);
+ }
+}
+
void
threadmain(int argc, char **argv)
{
@@ -892,14 +916,17 @@
playercurr = newplayer(pcur, 1);
start(playercurr);
break;
- case 'q': case Kdel:
+ case 'q':
+ case Kdel:
stop(playercurr);
goto end;
+ case 'i':
case 'o':
if(pcur == pcurplaying)
oldpcur = -1;
pcur = pcurplaying;
break;
+ case 'b':
case '>':
if(playercurr == nil)
break;
@@ -911,6 +938,7 @@
start(playercurr);
redraw(1);
break;
+ case 'z':
case '<':
if(playercurr == nil)
break;
@@ -930,7 +958,7 @@
chvolume(+1);
redraw(0);
break;
- case 's':
+ case 'v':
stop(playercurr);
playercurr = nil;
pcurplaying = -1;
@@ -938,10 +966,18 @@
cover = nil;
redraw(1);
break;
+ case 's':
+ toggleshuffle();
+ redraw(1);
+ break;
+ case 'c':
case 'p':
toggle(playercurr);
break;
- case '/': case '?': case 'n': case 'N':
+ case '/':
+ case '?':
+ case 'n':
+ case 'N':
search(key);
break;
}