ref: 5d597414f63bb9c98aa442d3fd6d33fc230848b4
parent: 4f13cda5bf98bc825ffc7f7ef135f0b919523ad5
author: Jacob Moody <[email protected]>
date: Thu Nov 21 09:25:52 EST 2019
Add different ways to load playlist Add ability to play form grid radio Add ability to play single file Add ability to dump and load the current queue as a playlist Add ability to play from dumped playlists
--- a/dat.h
+++ b/dat.h
@@ -4,6 +4,7 @@
STOP,
START,
PAUSE,
+ DUMP,
};
enum volmsg{
@@ -24,7 +25,7 @@
Rune *title;
Rune *artist;
Rune *album;
- int year;
+ int year;
Rune *comment;
char genre;
};
@@ -46,11 +47,11 @@
typedef struct FlacPic FlacPic;
struct FlacPic{
- char *mime;
- Rune *desc;
- Point p;
- uvlong size;
- uchar *data;
+ char *mime;
+ Rune *desc;
+ Point p;
+ uvlong size;
+ uchar *data;
};
typedef struct FlacMeta FlacMeta;
@@ -64,6 +65,7 @@
FLAC,
MP3,
VORBIS,
+ RADIO,
};
typedef struct Song Song;
@@ -73,6 +75,7 @@
FlacMeta *fmeta;
VorbisMeta *vmeta;
ID3v1 *idmeta;
+ Rune *title;
};
char *path;
};
@@ -79,11 +82,12 @@
typedef struct Album Album;
struct Album{
- char *path;
Rune *name;
Image *cover;
int nsong;
- Song **songs;
+ Song *songs;
+
+ int nocover;
};
typedef struct Lib Lib;
@@ -90,6 +94,7 @@
struct Lib{
int nalbum, cursong;
Album *start, *stop, *cur;
+ char *name;
};
typedef struct Click Click;
@@ -114,4 +119,4 @@
void *val;
Hnode *next;
} *nodes;
-};
\ No newline at end of file
+};
--- a/dir.c
+++ b/dir.c
@@ -6,19 +6,19 @@
#include "dat.h"
#include "fncs.h"
-Song*
-file2song(char *path, int needpic)
+int
+file2song(Song *s, char *path, int needpic)
{
char *dot;
- Song *s;
int fd;
+ s->path = strdup(path);
+
dot = strrchr(path, '.');
- if(dot == nil)
- return nil;
+ if(dot == nil || *dot == '\0')
+ return 0;
dot+=1;
- s = emalloc(sizeof(Song));
if(strcmp(dot, "flac") == 0){
s->type = FLAC;
goto done;
@@ -32,12 +32,12 @@
goto done;
}
/* Unsupported file suffix */
- goto error;
+ return 0;
done:
fd = open(path, OREAD);
if(fd < 0)
- goto error;
+ return 0;
switch(s->type){
case FLAC:
@@ -53,20 +53,16 @@
close(fd);
/* We can check the pointer without having to worry about which one it is */
if(s->fmeta == nil)
- goto error;
+ return 0;
- return s;
-
-error:
- free(s);
- return nil;
+ return 1;
}
int
songcmp(void *a, void *b)
{
- Song *s1 = *((Song**)a);
- Song *s2 = *((Song**)b);
+ Song *s1 = a;
+ Song *s2 = b;
int t1, t2;
t1 = t2 = 0;
@@ -128,23 +124,22 @@
/* Greedy alloc to start, we will trim down later */
a->nsong = n;
- a->songs = emalloc(sizeof(Song*) * n);
+ a->songs = emalloc(sizeof(Song) * n);
for(i=0;i<n;i++){
snprint(buf, 512, "%s/%s", path, files[i].name);
- a->songs[songcount] = file2song(buf, needpic++);
- if(a->songs[songcount] == nil)
+ if(!file2song(a->songs+songcount, buf, 0))
continue;
if(a->name == nil){
- switch(a->songs[songcount]->type){
+ switch((a->songs+songcount)->type){
case FLAC:
- albumtitle = a->songs[songcount]->fmeta->com->album;
+ albumtitle = (a->songs+songcount)->fmeta->com->album;
break;
case MP3:
- albumtitle = a->songs[songcount]->idmeta->album;
+ albumtitle = (a->songs+songcount)->idmeta->album;
break;
case VORBIS:
- albumtitle = a->songs[songcount]->vmeta->album;
+ albumtitle = (a->songs+songcount)->vmeta->album;
break;
default:
albumtitle = nil;
@@ -152,14 +147,13 @@
if(albumtitle != nil)
a->name = runesmprint("%S", albumtitle);
}
- a->songs[songcount]->path = strdup(buf);
songcount++;
}
a->nsong = songcount;
- a->songs = realloc(a->songs, sizeof(Song*) * songcount);
+ a->songs = realloc(a->songs, sizeof(Song) * songcount);
- qsort(a->songs, songcount, sizeof(Song*), songcmp);
+ qsort(a->songs, songcount, sizeof(Song), songcmp);
free(files);
return 1;
@@ -200,4 +194,36 @@
*als = realloc(*als, sizeof(Album)*alcount);
return alcount;
-}
\ No newline at end of file
+}
+
+void
+file2album(Album *a, Rune *aname, char *path)
+{
+ a->name = runestrdup(aname);
+ a->cover = nil;
+ a->nsong = 1;
+ a->songs = emalloc(sizeof(Song));
+ /* As a special case for http streams */
+ if(strstr(path, "http")==path){
+ a->name = runesmprint("%s", path);
+ a->nocover = 1;
+ a->songs->path = strdup(path);
+ a->songs->title = runestrdup(aname);
+ a->songs->type = RADIO;
+ return;
+ }
+ if(!file2song(a->songs, path, 0))
+ sysfatal("Could not parse song %s", path);
+}
+
+void
+radio2album(Album *a, char *path)
+{
+ a->name = runesmprint("Radio");
+ a->cover = nil;
+ a->nsong = 1;
+ a->songs = emalloc(sizeof(Song));
+ a->songs->type = RADIO;
+ a->songs->title = nil;
+ a->songs->path = strdup(path);
+}
--- a/draw.c
+++ b/draw.c
@@ -27,6 +27,7 @@
i+=n;
towrite-=n;
}
+ close(fd);
}
typedef struct{
@@ -143,6 +144,7 @@
Dir *files;
Image *im;
+
if(s->type == FLAC && s->fmeta->pic != nil){
p = s->fmeta->pic;
return convpicbuf(p->data, p->size, p->mime);
@@ -193,8 +195,9 @@
Point p = start;
Click c;
- if(a->cover == nil)
- a->cover = readcover(a->songs[0]);
+ if(a->nocover == 0 && a->cover == nil)
+ if((a->cover = readcover(a->songs)) == nil)
+ a->nocover = 1; /* Don't search again */
if(a->cover != nil){
draw(screen, Rpt(p, addpt(p, a->cover->r.max)), a->cover, nil, ZP);
@@ -205,16 +208,23 @@
p.y += f->height * 2;
for(i=0;i<a->nsong;i++){
- switch(a->songs[i]->type){
+ switch((a->songs+i)->type){
case FLAC:
- tracktitle = a->songs[i]->fmeta->com->title;
+ tracktitle = (a->songs+i)->fmeta->com->title;
break;
case MP3:
- tracktitle = a->songs[i]->idmeta->title;
+ tracktitle = (a->songs+i)->idmeta->title;
break;
case VORBIS:
- tracktitle = a->songs[i]->vmeta->title;
+ tracktitle = (a->songs+i)->vmeta->title;
break;
+ case RADIO:
+ tracktitle = (a->songs+i)->title;
+ if(tracktitle == nil)
+ return start;
+ break;
+ default:
+ sysfatal("Unknown song type");
}
runestring(screen, p, i == cursong ? active : textcolor, ZP, f, tracktitle);
c.r = Rpt(p, Pt(p.x+runestrlen(tracktitle)*f->width,p.y+f->height));
@@ -239,8 +249,12 @@
stop = screenstop < stop ? screenstop : stop;
stop+=1;
- for(;start!=stop;start++)
+ if(start==stop)
+ stop++;
+
+ for(;start!=stop;start++){
p = drawalbum(start, textcolor, active, p, start == cur ? cursong : -1, clickout);
+ }
}
void
@@ -253,5 +267,5 @@
p.y = screen->r.min.y;
p.x = screen->r.max.x;
p.x-=(n*f->width);
- string(screen, p, color, ZP, f, buf);;
+ string(screen, p, color, ZP, f, buf);
}
--- a/fncs.h
+++ b/fncs.h
@@ -30,7 +30,11 @@
void drawvolume(int, Image*);
/* dir.c */
+int file2song(Song*, char*,int);
+int dir2album(Album*,char*);
int parselibrary(Album**,char*);
+void radio2album(Album*,char*);
+void file2album(Album*,Rune*,char*);
/* dat.c */
Hmap* allocmap(int);
@@ -39,10 +43,24 @@
void* mapget(Hmap*,char*);
/* lib.c */
-void spawnlib(Channel*,Channel*,Channel*,Channel*,char*);
+void spawnlib(Channel*,Channel*,Channel*,Channel*,Channel*,char*);
/* vol.c */
void spawnvol(Channel*,Channel*);
/* event.c */
-void spawnevent(Channel*,Channel*,Channel*,Channel*);
\ No newline at end of file
+void spawnevent(Channel*,Channel*,Channel*,Channel*);
+
+/* index.c */
+void marshalstr(int,char*);
+void unmarshalstr(int,char**);
+void marshalrune(int,Rune*);
+void unmarshalrun(int,Rune**);
+void marshalalbum(int,Album*);
+void unmarshalalbum(int,Album*);
+void marshallib(int,Lib*);
+void unmarshallib(int,Lib*);
+
+/* list.c */
+void dumplib(Lib*);
+void loadlib(Lib*);
--- /dev/null
+++ b/index.c
@@ -1,0 +1,221 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+
+#include "dat.h"
+#include "fncs.h"
+
+const uchar none[] = {0};
+
+/*
+ * Rune and str marshal functions do not write null.
+ */
+
+void
+marshalrune(int fd, Rune *r)
+{
+ static char buf[128];
+ uchar n;
+
+ if(r == nil || r[0] == '\0')
+ write(fd, none, sizeof none);
+ else{
+ n = snprint(buf, 128, "%S", r);
+ write(fd, &n, sizeof n);
+ write(fd, buf, n);
+ }
+}
+
+void
+unmarshalrune(int fd, Rune **r)
+{
+ static uchar buf[128];
+ uchar n;
+ read(fd, &n, sizeof n);
+ if(n == 0)
+ return;
+ read(fd, buf, n);
+ buf[n] = '\0';
+ *r = runesmprint("%s", (char*)buf);
+}
+
+void
+marshalstr(int fd, char *s)
+{
+ uint n = strlen(s);
+ write(fd, &n, sizeof n);
+ write(fd, s, n);
+}
+
+void
+unmarshalstr(int fd, char **s)
+{
+ uint n;
+ read(fd, &n, sizeof n);
+ *s = emalloc(n+1);
+ s[n] = '\0';
+ read(fd, *s, n);
+}
+
+void
+marshalvorbis(int fd, VorbisMeta *v)
+{
+ //TODO: store whole key-value pair
+ marshalrune(fd, v->title);
+ marshalrune(fd, v->artist);
+ marshalrune(fd, v->album);
+ write(fd, &(v->year), sizeof v->year);
+ write(fd, &(v->tracknumber), sizeof v->tracknumber);
+}
+
+void
+unmarshalvorbis(int fd, VorbisMeta **v)
+{
+ *v = emalloc(sizeof(VorbisMeta));
+ unmarshalrune(fd, &((*v)->title));
+ unmarshalrune(fd, &((*v)->artist));
+ unmarshalrune(fd, &((*v)->album));
+ read(fd, &((*v)->year), sizeof (*v)->year);
+ read(fd, &((*v)->tracknumber), sizeof (*v)->tracknumber);
+}
+
+void
+marshalflacpic(int fd, FlacPic *p)
+{
+ //TODO store other fields
+ marshalstr(fd, p->mime);
+ write(fd, &(p->size), sizeof p->size);
+ write(fd, p->data, p->size);
+}
+
+void
+unmarshalflacpic(int fd, FlacPic **p)
+{
+ *p = emalloc(sizeof(FlacPic));
+ unmarshalstr(fd, &((*p)->mime));
+ read(fd, &((*p)->size), sizeof (*p)->size);
+ read(fd, (*p)->data, (*p)->size);
+}
+
+void
+marshalflacmeta(int fd, FlacMeta *f)
+{
+ marshalvorbis(fd, f->com);
+// marshalflacpic(fd, f->pic);
+}
+
+void
+unmarshalflacmeta(int fd, FlacMeta **f)
+{
+ *f = emalloc(sizeof(FlacMeta));
+ unmarshalvorbis(fd, &((*f)->com));
+// unmarshalflacpic(fd, &((*f)->pic));
+}
+
+void
+marshalid3(int fd, ID3v1 *id)
+{
+ marshalrune(fd, id->title);
+ marshalrune(fd, id->artist);
+ marshalrune(fd, id->album);
+ write(fd, &(id->year), sizeof id->year);
+ marshalrune(fd, id->comment);
+ write(fd, &(id->genre), sizeof id->genre);
+}
+
+void
+unmarshalid3(int fd, ID3v1 **id)
+{
+ *id = emalloc(sizeof(ID3v1));
+ unmarshalrune(fd, &((*id)->title));
+ unmarshalrune(fd, &((*id)->artist));
+ unmarshalrune(fd, &((*id)->album));
+ read(fd, &((*id)->year), sizeof (*id)->year);
+ unmarshalrune(fd, &((*id)->comment));
+ read(fd, &((*id)->genre), sizeof (*id)->genre);
+}
+
+void
+marshalsong(int fd, Song *s)
+{
+ write(fd, &(s->type), sizeof s->type);
+ switch(s->type){
+ case FLAC:
+ marshalflacmeta(fd, s->fmeta);
+ break;
+ case MP3:
+ marshalid3(fd, s->idmeta);
+ break;
+ default:
+ sysfatal("not recognized or unsupported format");
+ }
+ marshalstr(fd, s->path);
+}
+
+void
+unmarshalsong(int fd, Song *s)
+{
+ read(fd, &(s->type), sizeof s->type);
+ switch(s->type){
+ case FLAC:
+ unmarshalflacmeta(fd, &(s->fmeta));
+ break;
+ case MP3:
+ unmarshalid3(fd, &(s->idmeta));
+ break;
+ default:
+ sysfatal("not recognized or unsupported format");
+ }
+ unmarshalstr(fd, &(s->path));
+}
+
+void
+marshalalbum(int fd, Album *a)
+{
+ int i;
+ int havepic = a->cover == nil ? 0 : 1;
+ marshalrune(fd, a->name);
+ write(fd, &(a->nsong), sizeof a->nsong);
+ write(fd, &havepic, sizeof havepic);
+ if(havepic)
+ writeimage(fd, a->cover, 0);
+ for(i=0;i<a->nsong;i++)
+ marshalsong(fd, a->songs+i);
+}
+
+void
+unmarshalalbum(int fd, Album *a)
+{
+ int i, havepic;
+ unmarshalrune(fd, &(a->name));
+ read(fd, &(a->nsong), sizeof a->nsong);
+ read(fd, &havepic, sizeof havepic);
+ if(havepic)
+ a->cover = readimage(display, fd, 0);
+ a->songs = emalloc(sizeof(Song)*a->nsong);
+ for(i=0;i<a->nsong;i++)
+ unmarshalsong(fd, a->songs+i);
+}
+
+void
+marshallib(int fd, Lib *l)
+{
+ int i;
+ write(fd, &(l->nalbum), sizeof l->nalbum);
+ for(i=0;i<l->nalbum;i++)
+ marshalalbum(fd, l->start+i);
+}
+
+void
+unmarshallib(int fd, Lib *l)
+{
+ int i;
+ l->cursong = 0;
+ read(fd, &(l->nalbum), sizeof l->nalbum);
+ l->start = emalloc(sizeof(Album)*l->nalbum);
+ for(i=0;i<l->nalbum;i++)
+ unmarshalalbum(fd, l->start+i);
+ l->stop = l->start+i;
+ l->cur = l->start;
+}
--- a/lib.c
+++ b/lib.c
@@ -1,5 +1,6 @@
#include <u.h>
#include <libc.h>
+#include <bio.h>
#include <thread.h>
#include <draw.h>
@@ -7,15 +8,9 @@
#include "fncs.h"
Channel *queuein, *queueout, *decctl;
+Channel *radiochan;
Lib lib;
-enum{
- LMSG,
- QUEUEPOP,
- EIN,
- OUT,
-};
-
char*
nextsong(Lib *lib)
{
@@ -31,7 +26,7 @@
lib->cur = lib->start;
lib->cursong = 0;
}
- return lib->cur->songs[lib->cursong]->path;
+ return (lib->cur->songs+(lib->cursong))->path;
}
void
@@ -38,6 +33,9 @@
handlemsg(enum cmsg msg)
{
switch(msg){
+ case DUMP:
+ dumplib(&lib);
+ break;
case NEXT:
lib.cursong++;
sendp(queuein, nextsong(&lib));
@@ -61,19 +59,34 @@
Channel *lctl = chans[0];
Channel *out = chans[1];
Channel *ein = chans[2];
- Channel *resize = chans[3];
+ Channel *redraw = chans[3];
+ Channel *loadc = chans[4];
free(chans);
enum cmsg msg;
Click c;
+ char *radiotitle = nil;
+ char *toload;
+
Alt alts[] = {
{lctl, &msg, CHANRCV},
{queueout, nil, CHANRCV},
{ein, &c, CHANRCV},
{out, &lib, CHANSND},
+ {radiochan, &radiotitle, CHANRCV},
+ {loadc, &toload, CHANRCV},
{nil, nil, CHANEND},
};
+ enum{
+ LMSG,
+ QUEUEPOP,
+ EIN,
+ OUT,
+ RADIOIN,
+ LOADC,
+ };
+
for(;;){
switch(alt(alts)){
case LMSG:
@@ -89,32 +102,119 @@
break;
case OUT:
continue;
+ case RADIOIN:
+ /* Eat everything in the channel;
+ * This leaks memory,
+ * but fixes a race.
+ * TODO: Find a better fix.
+ */
+ while(nbrecv(radiochan, &radiotitle))
+ ;
+ if(lib.cur->songs->title != nil)
+ free(lib.cur->songs->title);
+ lib.cur->songs->title = runesmprint("%s", radiotitle);
+ free(radiotitle);
+ break;
+ case LOADC:
+ free(lib.name);
+ lib.name = strdup(toload);
+ loadlib(&lib);
+ lib.stop = lib.start+(lib.nalbum-1);
+ lib.cursong = 0;
+ lib.cur = lib.start;
+ break;
}
- send(resize, nil);
+ send(redraw, nil);
}
}
void
-spawnlib(Channel *ctl, Channel *out, Channel *ein, Channel *resize, char *path)
+radioproc(void *arg)
{
+ char *path = arg;
+ char buf[512];
+ char *dot, *end;
+ Biobuf *b;
+
+ dot = strrchr(path, '/');
+ if(dot == nil)
+ sysfatal("readradiosong: bad song path");
+ end = buf+(dot-path)+1;
+ if(end - buf > sizeof buf)
+ sysfatal("readradiosong: buffer too small");
+ seprint(buf, end, "%s", path);
+ snprint(buf, 512, "%s/playing", buf);
+ free(path);
+ b = Bopen(buf, OREAD);
+ if(b == nil)
+ sysfatal("readradiosong: Bopen %r");
+ for(;;){
+ path = Brdstr(b, '\n', 1);
+ sendp(radiochan, path);
+ }
+}
+
+void
+spawnlib(Channel *ctl, Channel *out, Channel *ein, Channel *redraw, Channel *loadc, char *path)
+{
Channel **chans;
+ char *name;
queuein = queueout = decctl = nil;
+ radiochan = nil;
+
spawndec(&queuein, &decctl, &queueout);
+ radiochan = chancreate(sizeof(char*), 1024);
+ name = strrchr(path, '/');
+ lib.name = strdup(name == nil ? path : name);
+
+ extern int mflag;
+ extern int sflag;
+ extern int rflag;
+ extern int pflag;
+ extern int fflag;
+
+ if(mflag == 1){
+ chanclose(radiochan);
+ lib.nalbum = parselibrary(&(lib.start), path);
+ if(lib.nalbum == 0)
+ sysfatal("no songs found");
+ lib.stop = lib.start+(lib.nalbum-1);
+ }else if(sflag == 1){
+ chanclose(radiochan);
+ lib.nalbum = 1;
+ lib.start = emalloc(sizeof(Album));
+ if(!dir2album(lib.start, path))
+ sysfatal("no songs found");
+ lib.stop = lib.start;
+ }else if(rflag == 1){
+ lib.nalbum = 1;
+ lib.start = emalloc(sizeof(Album));
+ lib.stop = lib.start;
+ radio2album(lib.start, path);
+ proccreate(radioproc, strdup(path), 8192);
+ }else if(pflag == 1){
+ chanclose(radiochan);
+ loadlib(&lib);
+ lib.stop = lib.start+(lib.nalbum-1);
+ }else if(fflag == 1){
+ lib.nalbum = 1;
+ lib.start = emalloc(sizeof(Album));
+ lib.stop = lib.start;
+ file2album(lib.start, L"", path);
+ }
+
lib.cursong = 0;
- lib.nalbum = parselibrary(&(lib.start), path);
- if(lib.nalbum == 0)
- quit("No songs found");
lib.cur = lib.start;
- lib.stop = lib.start+(lib.nalbum-1);
- chans = emalloc(sizeof(Channel*)*4);
+ chans = emalloc(sizeof(Channel*)*5);
chans[0] = ctl;
chans[1] = out;
chans[2] = ein;
- chans[3] = resize;
+ chans[3] = redraw;
+ chans[4] = loadc;
sendp(queuein, nextsong(&lib));
threadcreate(libproc, chans, 8192);
-}
\ No newline at end of file
+}
--- /dev/null
+++ b/list.c
@@ -1,0 +1,167 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+#include <draw.h>
+
+#include "dat.h"
+#include "fncs.h"
+
+void
+dumpalbum(int fd, Album *a)
+{
+ int i;
+ char nl = '\n';
+ char buf[128];
+ int n = snprint(buf, 128, "%S", a->name);
+
+ write(fd, buf, n);
+ write(fd, &nl, 1);
+
+ for(i=0;i<a->nsong;i++){
+ write(fd, a->songs[i].path, strlen(a->songs[i].path));
+ write(fd, &nl, 1);
+ }
+}
+
+void
+libdir(char *buf, int n)
+{
+ char *home;
+ int s;
+ home = getenv("home");
+ s = snprint(buf, n, "%s/lib/mpl", home);
+ buf[s] = '\0';
+ free(home);
+}
+
+void
+createlibdir(char *path)
+{
+ int fd;
+ fd = open(path, OREAD);
+ if(fd>0){
+ close(fd);
+ return;
+ }
+ fd = create(path, OREAD, DMDIR|0755);
+ if(fd<0)
+ sysfatal("could not create lib dir: %r");
+ close(fd);
+}
+
+void
+dumplib(Lib *l)
+{
+ int fd;
+ int i;
+ char buf[512];
+ char fname[512];
+ char sep[] = "\n\n";
+
+ libdir(buf, 512);
+ assert(l->name != nil);
+ createlibdir(buf);
+ i = snprint(fname, 512, "%s/%s.list", buf, l->name);
+ fname[i] = '\0';
+ fd = create(fname, ORDWR, 0644);
+ if(fd<0){
+ fprint(2, "Could not create list file: %r\n");
+ quit(nil);
+ }
+ for(i=0;i<l->nalbum;i++){
+ dumpalbum(fd, l->start+i);
+ write(fd, sep, sizeof sep - 1);
+ }
+ close(fd);
+ snprint(fname, 512, "%s/%s.db", buf, l->name);
+ fd = create(fname, ORDWR, 0644);
+ if(fd<0){
+ fprint(2, "Count not create list db file: %r");
+ quit(nil);
+ }
+ marshallib(fd, l);
+ close(fd);
+}
+
+void
+loadalbum(Biobuf *b, Album *a)
+{
+ int size, cap;
+ char *dot;
+ dot = Brdstr(b, '\n', 1);
+ if(dot == nil){
+ return;
+ }
+ a->name = runesmprint("%s", dot);
+ free(dot);
+
+ cap = 10;
+ a->songs = emalloc(sizeof(Song)*cap);
+ for(size=0;(dot = Brdstr(b, '\n', 1));size++){
+ if(strlen(dot) == 0){
+ free(dot);
+ break;
+ }
+ if(size == cap-1){
+ cap = cap * 2;
+ a->songs = realloc(a->songs, sizeof(Song)*cap);
+ }
+ if(file2song(a->songs+size, dot, 0) == 0)
+ sysfatal("Could not parse song %s", dot);
+ }
+
+ a->songs = realloc(a->songs, sizeof(Song)*size);
+ a->nsong = size;
+ a->cover = nil;
+ return;
+}
+
+void
+loadlib(Lib *l)
+{
+ Biobuf *b;
+ char buf[512];
+ char fname[512];
+ int size, cap;
+ int fd;
+ long r;
+
+ assert(l->name != nil);
+ libdir(buf, 512);
+
+ /* Check for db cache file first */
+ snprint(fname, 512, "%s/%s.db", buf, l->name);
+ if((fd = open(fname, OREAD))>0){
+ unmarshallib(fd, l);
+ close(fd);
+ return;
+ }
+
+ snprint(fname, 512, "%s/%s.list", buf, l->name);
+ b = Bopen(fname, OREAD);
+ if(b == nil){
+ fprint(2, "Could not open list file: %s\n", fname);
+ quit(nil);
+ }
+ cap = 10;
+ l->start = emalloc(sizeof(Album)*cap);
+ for(size = 0;(r = Bgetrune(b)) > 0;size++){
+ if(size == cap-1){
+ cap = cap * 2;
+ l->start = realloc(l->start, sizeof(Album)*cap);
+ }
+ if(r != L'\n'){
+ Bungetrune(b);
+ }
+ (l->start+size)->name = nil;
+ loadalbum(b, l->start+size);
+ }
+ if((l->start+size)->name == nil){
+ size--;
+ }
+ close(Bfildes(b));
+ free(b);
+ l->start = realloc(l->start, sizeof(Album)*size);
+ l->nalbum = size;
+}
--- a/mkfile
+++ b/mkfile
@@ -14,6 +14,8 @@
lib.$O \
vol.$O \
event.$O \
+ index.$O \
+ list.$O \
-</sys/src/cmd/mkone
\ No newline at end of file
+</sys/src/cmd/mkone
--- a/mpl.c
+++ b/mpl.c
@@ -12,16 +12,19 @@
enum {
RESIZEC,
KEYC,
+ REDRAW,
NONE
};
Mousectl *mctl;
Keyboardctl *kctl;
-Channel *ctl, *lout;
+Channel *ctl, *lout, *loadc;
Channel *vctl, *vlevel;
Channel *clickin, *clickreset;
-int decpid;
+int decpid;
+int mflag, sflag, pflag, rflag, fflag;
+
Image *black;
Image *red;
Image *background;
@@ -39,9 +42,7 @@
void
quit(char *err)
{
- closedisplay(display);
- closemouse(mctl);
- closekeyboard(kctl);
+ cleanup(nil, nil);
threadexitsall(err);
}
@@ -67,6 +68,7 @@
{
enum volmsg vmsg;
enum cmsg msg;
+ char buf[512] = {0};
switch(kbd){
case Kbs:
case Kdel:
@@ -99,15 +101,22 @@
vmsg = UP;
send(vctl, &vmsg);
break;
+ case 'd':
+ msg = DUMP;
+ send(ctl, &msg);
+ break;
+ case 'o':
+ enter("Playlist?", buf, sizeof buf, mctl, kctl, nil);
+ sendp(loadc, buf);
+ break;
}
eresized(0);
}
-
void
usage(void)
{
- fprint(2, "Usage: %s file", argv0);
+ fprint(2, "Usage: -mspr %s file", argv0);
sysfatal("usage");
}
@@ -118,12 +127,33 @@
Channel *clickout;
int resize[2];
ctl = vctl = vlevel = nil;
+ mflag = sflag = pflag = rflag = fflag = 0;
- //TODO: Use ARGBEGIN
- argv0 = argv[0];
+ /*
+ * This shouldn't need to be buffered,
+ * but for some reason it likes to still be
+ * blocked by the time the libproc is asked
+ * to produce the Lib struct. TODO: Investigate.
+ */
+ Channel *redraw = chancreate(1, 1);
+
+ ARGBEGIN{
+ case 'm': mflag++; break;
+ case 's': sflag++; break;
+ case 'p': pflag++; break;
+ case 'r': rflag++; break;
+ case 'f': fflag++; break;
+ default: usage();
+ }ARGEND
+
+ if(mflag+sflag+pflag+rflag+fflag < 1){
+ fprint(2, "Please specify a playlist flag(m, s, r, or p)\n");
+ threadexits(nil);
+ }
+
threadnotify(cleanup, 1);
- if(argc != 2)
+ if(argc != 1)
usage();
if(initdraw(nil, nil, "mpl") < 0)
@@ -140,7 +170,8 @@
ctl = chancreate(sizeof(enum cmsg), 0);
lout = chancreate(sizeof(Lib), 0);
- spawnlib(ctl, lout, clickout, mctl->resizec, argv[1]);
+ loadc = chancreate(sizeof(char*), 0);
+ spawnlib(ctl, lout, clickout, redraw, loadc, argv[0]);
vctl = chancreate(sizeof(enum volmsg), 0);
vlevel = chancreate(sizeof(int), 0);
@@ -155,6 +186,7 @@
Alt alts[] = {
{mctl->resizec, resize, CHANRCV},
{kctl->c, &kbd, CHANRCV},
+ {redraw, nil, CHANRCV},
{nil, nil, CHANEND},
};
@@ -166,6 +198,9 @@
case RESIZEC:
eresized(1);
break;
+ case REDRAW:
+ eresized(0);
+ break;
}
}
-}
\ No newline at end of file
+}
--- a/vol.c
+++ b/vol.c
@@ -78,10 +78,12 @@
switch(vmsg){
case UP:
level+=5;
+ level = level > 100 ? 100 : level;
writevol(fd, muted == 0 ? level : 0);
break;
case DOWN:
level-=5;
+ level = level < 0 ? 0 : level;
writevol(fd, muted == 0 ? level : 0);
break;
case MUTE: