ref: fde5a0286017c96a4c127b45ba69af27b61c4835
parent: f0bb0451afe4b3d4719c6b2446dfa8034c9eb4fc
author: Jacob Moody <[email protected]>
date: Tue Sep 17 10:06:26 EDT 2019
Parse folder of albums instead of just one, and draw >1 to the screen if possible Fix playback on native 9front install Fallback to file name if MP3 IDV1 tags are not found Do case insesitive check on vorbis tag keys
--- a/dec.c
+++ b/dec.c
@@ -50,6 +50,12 @@
if(afd < 0)
sysfatal("could not open audio device");
bufsize = iounit(afd);
+ /*
+ * On native plan9 installs this will return 0,
+ * so we default to the default iosize.
+ */
+ if(bufsize == 0)
+ bufsize = 8192;
buf = emalloc(bufsize);
for(;;){
--- a/dir.c
+++ b/dir.c
@@ -62,10 +62,9 @@
return nil;
}
-Album*
-dir2album(char *path)
+void
+dir2album(Album *a, char *path)
{
- Album *a;
Dir *files;
int fd;
long n;
@@ -78,21 +77,23 @@
fd = open(path, OREAD);
if(fd < 0)
- return nil;
+ return;
n = dirreadall(fd, &files);
close(fd);
if(n <= 0)
- return nil;
+ return;
- a = emalloc(sizeof(Album));
-
/* Do a single pass to find cover.^(jp^(eg g) png) */
for(i=0;i<n;i++){
- dot = strstr(path, "cover.");
- if(dot == nil)
- continue;
- dot+=1;
+ dot = cistrstr(files[i].name, "cover.");
+ if(dot == nil){
+ dot = cistrstr(files[i].name, "folder.");
+ if(dot == nil)
+ continue;
+ }
+ dot = strrchr(dot, '.');
+ dot++;
snprint(buf, 512, "%s/%s", path, files[i].name);
fd = open(buf, OREAD);
if(fd<0)
@@ -101,8 +102,10 @@
a->cover = convpic(fd, dot);
if(a->cover != nil){
needpic = 0;
+ close(fd);
break;
}
+ close(fd);
}
/* Greedy alloc to start, we will trim down later */
@@ -146,5 +149,42 @@
a->songs = realloc(a->songs, sizeof(Song*) * songcount);
free(files);
- return a;
+ return;
+}
+
+int
+parselibrary(Album **als, char *path)
+{
+ Dir *files;
+ int fd;
+ uint n, i;
+ uint numdirs = 0;
+ uint alcount = 0;
+ char buf[512];
+
+ fd = open(path, OREAD);
+ if(fd < 0)
+ return 0;
+
+ n = dirreadall(fd, &files);
+ close(fd);
+ if(n <= 0)
+ return 0;
+
+ for(i=0;i<n;i++)
+ if(files[i].qid.type&QTDIR)
+ numdirs++;
+
+ *als = emalloc(sizeof(Album)*numdirs);
+ for(i=0;i<n;i++)
+ if(files[i].qid.type&QTDIR){
+ snprint(buf, 512, "%s/%s", path, files[i].name);
+ dir2album(*als+alcount, buf);
+ if(*als+alcount != nil)
+ alcount++;
+ }
+
+ *als = realloc(*als, sizeof(Album)*alcount);
+
+ return alcount;
}
\ No newline at end of file
--- a/draw.c
+++ b/draw.c
@@ -133,16 +133,18 @@
return i;
}
-void
-drawalbum(Album *a, Image *textcolor, Image *active, int cursong)
+Point
+drawalbum(Album *a, Image *textcolor, Image *active, Point start, int cursong)
{
uint i;
- Point p = screen->r.min;
Font *f = screen->display->defaultfont;
Rune *tracktitle = nil;
+ Point p = start;
- draw(screen, screen->r, a->cover, nil, ZP);
- p.x += a->cover->r.max.x;
+ if(a->cover != nil){
+ draw(screen, Rpt(p, addpt(p, a->cover->r.max)), a->cover, nil, ZP);
+ p.x += a->cover->r.max.x;
+ }
runestring(screen, p, textcolor, ZP, f, a->name);
p.y += f->height * 2;
@@ -162,5 +164,19 @@
runestring(screen, p, i == cursong ? active : textcolor, ZP, f, tracktitle);
p.y += f->height;
}
+ start.y+=256;
+ return start;
}
+void
+drawlibrary(Album *start, Album *stop, Album *cur, Image *textcolor, Image *active, int cursong)
+{
+ Point p = screen->r.min;
+ int height = screen->r.max.y - screen->r.min.y;
+ Album *screenstop = start+(height/256)-1;
+ stop = screenstop < stop ? screenstop : stop;
+ stop+=1;
+
+ for(;start!=stop;start++)
+ p = drawalbum(start, textcolor, active, p, start == cur ? cursong : -1);
+}
\ No newline at end of file
--- a/fncs.h
+++ b/fncs.h
@@ -10,6 +10,7 @@
u64int lebtoi(uchar*,int);
void kill(int);
void killgrp(int);
+int runecstrcmp(Rune*,Rune*);
/* id3.c */
ID3v1* readid3(int);
@@ -22,9 +23,11 @@
FlacMeta* readflacmeta(int, int);
/* draw.c */
-void drawalbum(Album*, Image*, Image*, int);
+Point drawalbum(Album*, Image*, Image*, Point, int);
Image* convpic(int, char*);
Image* convpicbuf(uchar*, uvlong, char*);
+void drawlibrary(Album*, Album*, Album*, Image*, Image*, int);
/* dir.c */
-Album* dir2album(char*);
\ No newline at end of file
+void dir2album(Album*,char*);
+int parselibrary(Album**,char*);
\ No newline at end of file
--- a/id3.c
+++ b/id3.c
@@ -6,6 +6,19 @@
#include "dat.h"
#include "fncs.h"
+/* If we can't read the tag, at least default to file names */
+void
+fillnotag(ID3v1 *id, int fd)
+{
+ char buf[512];
+ char *slash, *dot;
+ fd2path(fd, buf, 512);
+ slash = strrchr(buf, '/');
+ dot = strrchr(buf, '.');
+ *dot = '\0';
+ id->title = runesmprint("%s", slash+1);
+}
+
ID3v1*
readid3(int fd)
{
@@ -23,11 +36,13 @@
if(pread(fd, buf, 128, length-128) != 128)
return nil;
-
- if(memcmp(buf, "TAG", 3) != 0)
- return nil;
id = emalloc(sizeof(ID3v1));
+
+ if(memcmp(buf, "TAG", 3) != 0){
+ fillnotag(id, fd);
+ return id;
+ }
memcpy(fieldbuf, buf+3, 30);
fieldbuf[30] = '\0';
--- a/mpl.c
+++ b/mpl.c
@@ -23,7 +23,7 @@
Channel *queuein;
Channel *queueout;
Channel *ctl;
-Album *a;
+Album *start, *cur, *stop;
int cursong;
int decpid;
@@ -49,7 +49,7 @@
quit("eresized: Can't reattach to window");
draw(screen, screen->r, background, nil, ZP);
- drawalbum(a, black, red, cursong);
+ drawlibrary(cur, stop, cur, black, red, cursong);
flushimage(display, Refnone);
}
@@ -56,9 +56,19 @@
char*
nextsong(void)
{
- cursong = cursong < 0 ? a->nsong-1 : cursong;
- cursong = cursong > a->nsong-1 ? 0 : cursong;
- return a->songs[cursong]->path;
+ if(cursong < 0){
+ cur--;
+ if(cur < start)
+ cur = stop;
+ cursong = cur->nsong-1;
+ }
+ if(cursong > cur->nsong-1){
+ cur++;
+ if(cur > stop)
+ cur = start;
+ cursong = 0;
+ }
+ return cur->songs[cursong]->path;
}
void
@@ -109,6 +119,7 @@
Mouse mouse;
Rune kbd;
int resize[2];
+ int nalbum;
cursong = 0;
queuein = queueout = ctl = nil;
@@ -129,13 +140,13 @@
black = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DBlack);
background = allocimagemix(display, DPaleyellow, DPalegreen);
- a = dir2album(argv[1]);
- if(a == nil)
- quit("nil album");
- if(a->nsong == 0)
- quit("no songs");
+ nalbum = parselibrary(&start, argv[1]);
+ if(nalbum == 0)
+ quit("No songs found");
+ cur = start;
+ stop = start+(nalbum-1);
spawndec(&queuein, &ctl, &queueout);
- send(queuein, &(a->songs[0]->path));
+ send(queuein, &(cur->songs[0]->path));
handleaction('w');
Alt alts[] = {
--- a/util.c
+++ b/util.c
@@ -69,4 +69,22 @@
sysfatal("could not write to note");
close(nfd);
free(note);
+}
+
+int
+runecstrcmp(Rune *s1, Rune *s2)
+{
+ Rune c1, c2;
+
+ for(;;) {
+ c1 = tolowerrune(*s1++);
+ c2 = tolowerrune(*s2++);
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ if(c1 == 0)
+ return 0;
+ }
}
\ No newline at end of file
--- a/vorbis.c
+++ b/vorbis.c
@@ -11,15 +11,15 @@
{
uint i;
for(i=0;i<v->ncom;i++){
- if(runestrcmp(v->key[i], L"ALBUM") == 0){
+ if(runecstrcmp(v->key[i], L"album") == 0){
v->album = v->val[i];
continue;
}
- if(runestrcmp(v->key[i], L"TITLE") == 0){
+ if(runecstrcmp(v->key[i], L"title") == 0){
v->title = v->val[i];
continue;
}
- if(runestrcmp(v->key[i], L"ARTIST") == 0){
+ if(runecstrcmp(v->key[i], L"artist") == 0){
v->artist = v->val[i];
continue;
}