ref: 8f75ccd8bca408e6f080f774658ec23ac4839838
parent: 9714f4b05d5759db2086edc34044b48305c7087e
author: qwx <[email protected]>
date: Mon Nov 14 15:52:48 EST 2022
experimental chunked buffers to allow editing (itself disabled for testing) - keep track of a `dot', either a point position or a range; ranges are set with the loop bounds mouse commands; any operation acts on the dot - interaction is through an interface similar to paint: start typing, then the first letter is the command, the rest are arguments; things like | are passed to rc -c, so things like selecting a range and issuing: | norm -f 5 >buf.pcm works just fine - with copy/cut and others, a range across multiple chunks is merged into one prior to any handling - a `hold' chunk is used as a temporary scratch buffer for cut/copy/paste - audio thread and other functions ask for a pointer to data and provide a buffer, which may be unused if the data range is small not across chunks - split input file straightaway into ≈ 1mb chunks to avoid huge ops later - implemented but temporarily disabled: copy/cut/paste - naive implementation, but i prefer this to a more complicated one with a bunch of state to maintain: this just has positions in bytes; to look up chunks etc, we scan the list of chunks left to right. this should be improved for large files, but the rest is nice - remove -f: it makes everything complicated and there is no point; if the file is too big, just split it up manually - normalize status string - fix locking issue in drawsamp
--- a/cmd.c
+++ b/cmd.c
@@ -4,45 +4,357 @@
#include "dat.h"
#include "fns.h"
+/* stupidest implementation with the least amount of state to keep track of */
+
+Dot dot;
+usize totalsz;
+static Chunk norris = {.left = &norris, .right = &norris};
+static Chunk *held;
+static uchar plentyofroom[Iochunksz];
+static int cutheld;
+static int epfd[2];
+
+static Chunk *
+newchunk(usize n)
+{
+ Chunk *c;
+
+ assert((n & 3) == 0);
+ c = emalloc(sizeof *c);
+ c->bufsz = n;
+ c->buf = emalloc(c->bufsz);
+ return c;
+}
+
+static Chunk *
+clonechunk(void)
+{
+ Chunk *c;
+
+ assert(held != nil);
+ c = newchunk(held->bufsz);
+ memcpy(c->buf, held->buf, c->bufsz);
+ return c;
+}
+
+static void
+freechunk(Chunk *c)
+{
+ if(c == nil)
+ return;
+ free(c->buf);
+ free(c);
+}
+
+static void
+linkchunk(Chunk *left, Chunk *c)
+{
+ c->right = left->right;
+ c->left = left;
+ c->right->left = c;
+ left->right = c;
+}
+
+static void
+unlinkchunk(Chunk *c)
+{
+ c->left->right = c->right;
+ c->right->left = c->left;
+ c->left = c->right = nil;
+}
+
+/* stupidest possible approach for now: minimal bookkeeping */
+static Chunk *
+p2c(usize p, usize *off)
+{
+ Chunk *c;
+
+ c = norris.right;
+ while(p > c->bufsz){
+ p -= c->bufsz;
+ c = c->right;
+ }
+ if(off != nil)
+ *off = p;
+ assert(c != &norris);
+ return c;
+}
+static usize
+c2p(Chunk *tc)
+{
+ Chunk *c;
+ usize p;
+
+ p = 0;
+ c = norris.right;
+ while(c != tc){
+ p += c->bufsz;
+ c = c->right;
+ }
+ return p;
+}
+
+void
+setrange(usize from, usize to)
+{
+ dot.from.pos = from;
+ dot.to.pos = to;
+}
+
+int
+setpos(usize off)
+{
+ if(off < dot.from.pos || off > dot.to.pos){
+ werrstr("cannot jump outside of loop bounds\n");
+ return -1;
+ }
+ setrange(0, totalsz);
+ dot.pos = off;
+ return 0;
+}
+
+void
+jump(usize off)
+{
+ dot.pos = off;
+}
+
static int
-writediskbuf(int fd)
+holdchunk(int cut)
{
- int n, m, iosz;
+ if(held != nil){
+ if(held == p2c(dot.pos, nil))
+ return 0;
+ else if(cutheld){
+ unlinkchunk(held);
+ freechunk(held);
+ }
+ }
+ held = p2c(dot.from.pos, nil);
+ cutheld = cut;
+ if(cut){
+ setpos(dot.from.pos);
+ unlinkchunk(held);
+ }
+ return 0;
+}
- seek(ifd, loops, 0);
- if((iosz = iounit(fd)) == 0)
- iosz = 8192;
- for(m=loope-loops; m>0;){
- n = m < iosz ? m : iosz;
- if(read(ifd, pcmbuf, n) != n)
- return -1;
- if(write(fd, pcmbuf, n) != n)
- return -1;
- m -= n;
+static Chunk *
+merge(Chunk *left, Chunk *right)
+{
+ if(left->buf == nil || right->buf == nil){
+ werrstr("can\'t merge self into void");
+ return nil;
}
- seek(ifd, seekp, 0);
+ if(left->buf != right->buf){
+ left->buf = erealloc(left->buf, left->bufsz + right->bufsz, left->bufsz);
+ memmove(left->buf + left->bufsz, right->buf, right->bufsz);
+ }else
+ right->buf = nil;
+ left->bufsz += right->bufsz;
+ unlinkchunk(right);
+ freechunk(right);
return 0;
}
+/* does not modify dot range; merges range then splits
+ * at left and right offset */
+static void
+split(void)
+{
+ usize n, p, Δ;
+ Chunk *c, *from, *to, *tc;
+
+ from = p2c(dot.pos, &p);
+ to = p2c(dot.to.pos, nil);
+ if(from != to){
+ for(p=dot.pos; p<dot.to.pos; p+=n){
+ tc = from->right;
+ assert(tc != &norris);
+ n = tc->bufsz;
+ from = merge(from, tc);
+ }
+ }
+ if(p < dot.from.pos){
+ Δ = dot.from.pos - p;
+ c = newchunk(Δ);
+ memcpy(c->buf, from->buf, Δ);
+ linkchunk(from->left, c);
+ }
+ tc = p2c(dot.to.pos, &p);
+ p += tc->bufsz;
+ if(dot.to.pos < p){
+ Δ = p - dot.to.pos;
+ c = newchunk(Δ);
+ memcpy(c->buf, tc->buf + dot.to.pos, Δ);
+ linkchunk(from, c);
+ }
+}
+
+uchar *
+getbuf(Dot d, usize n, uchar *scratch, usize *boff)
+{
+ uchar *bp, *p;
+ usize Δbuf, Δloop, m, off, Δ;
+ Chunk *c;
+
+ c = p2c(d.pos, &off);
+ p = c->buf + off;
+ m = n;
+ bp = scratch;
+ while(m > 0){
+ Δloop = d.to.pos - d.pos;
+ Δbuf = c->bufsz - off;
+ if(m < Δloop && m < Δbuf){
+ Δ = m;
+ memcpy(bp, p, Δ);
+ d.pos += Δ;
+ }else if(Δloop <= Δbuf){
+ Δ = Δloop;
+ memcpy(bp, p, Δ);
+ d.pos = d.from.pos;
+ c = p2c(d.from.pos, nil);
+ off = 0;
+ p = c->buf;
+ }else{
+ if(c == &norris)
+ c = c->right;
+ Δ = Δbuf;
+ memcpy(bp, p, Δ);
+ d.pos += Δ;
+ c = c->right;
+ off = 0;
+ p = c->buf;
+ }
+ bp += Δ;
+ m -= Δ;
+ }
+ *boff = n;
+ return scratch;
+}
+
+void
+advance(Dot *d, usize n)
+{
+ usize Δ, Δbuf, Δloop, m, off;
+ Chunk *c;
+
+ c = p2c(d->pos, &off);
+ m = n;
+ while(m > 0){
+ Δloop = d->to.pos - d->pos;
+ Δbuf = c->bufsz - off;
+ if(m < Δloop && m < Δbuf){
+ d->pos += m;
+ break;
+ }else if(Δloop < Δbuf){
+ Δ = Δloop;
+ d->pos = d->from.pos;
+ c = p2c(d->from.pos, nil);
+ off = 0;
+ }else{
+ Δ = Δbuf;
+ d->pos += Δ;
+ c = c->right;
+ off = 0;
+ }
+ m -= Δ;
+ }
+}
+
static int
+paste(char *)
+{
+ Chunk *c, *l, *dotc;
+
+ c = clonechunk();
+ if(dot.from.pos == dot.to.pos){ /* insert */
+ linkchunk(p2c(dot.to.pos, nil), c);
+ setrange(dot.to.pos, dot.to.pos + c->bufsz);
+ totalsz += c->bufsz;
+ }else{ /* replace */
+ dotc = p2c(dot.pos, nil);
+ l = dotc->left;
+ totalsz -= dotc->bufsz;
+ unlinkchunk(dotc);
+ freechunk(dotc);
+ linkchunk(l, c);
+ setrange(dot.from.pos, dot.from.pos + c->bufsz);
+ totalsz += c->bufsz;
+ }
+ return 0;
+}
+
+static int
+copy(char *)
+{
+ split();
+ holdchunk(0);
+ return 0;
+}
+
+static int
+cut(char *)
+{
+ split();
+ totalsz -= p2c(dot.pos, nil)->bufsz;
+ holdchunk(1);
+ return 0;
+}
+
+static Chunk *
+readintochunks(int fd)
+{
+ int n;
+ usize off;
+ Chunk *c, *nc;
+
+ c = newchunk(Iochunksz);
+ linkchunk(&norris, c);
+ for(off=0;; off+=n){
+ if(off == Iochunksz){
+ totalsz += Iochunksz;
+ nc = newchunk(Iochunksz);
+ linkchunk(c, nc);
+ c = nc;
+ off = 0;
+ }
+ if((n = read(fd, c->buf+off, Ioreadsz)) <= 0)
+ break;
+ }
+ close(fd);
+ if(n < 0)
+ fprint(2, "readintochunks: %r\n");
+ c->buf = erealloc(c->buf, off, c->bufsz);
+ c->bufsz = off;
+ totalsz += c->bufsz;
+ return norris.right;
+}
+
+static int
writebuf(int fd)
{
- int n, iosz;
- uchar *p, *e;
+ usize n, m;
+ uchar *p;
+ Dot d;
- if((iosz = iounit(fd)) == 0)
- iosz = 8192;
- for(p=pcmbuf+loops, e=pcmbuf+loope; p<e;){
- n = e - p < iosz ? e - p : iosz;
- if(write(fd, p, n) != n)
+ d.pos = d.from.pos = dot.from.pos;
+ d.to.pos = dot.to.pos;
+ for(m=d.to.pos-d.from.pos; m>0;){
+ n = sizeof plentyofroom < m ? sizeof plentyofroom : m;
+ if((p = getbuf(d, n, plentyofroom, &n)) == nil){
+ fprint(2, "writebuf: getbuf won't feed\n");
return -1;
- p += n;
+ }
+ if((n = write(fd, p, m)) != n){
+ fprint(2, "writebuf: short write not %zd\n", n);
+ return -1;
+ }
+ m -= n;
}
return 0;
}
-static int epfd[2];
-
static void
rc(void *s)
{
@@ -74,7 +386,7 @@
{
int r, fd;
- if(loope - loops == 0){
+ if(dot.to.pos - dot.from.pos == 0){
werrstr("writeto: dot isn't a range");
return -1;
}
@@ -82,7 +394,7 @@
werrstr("writeto: %r");
return -1;
}
- r = file ? writediskbuf(fd) : writebuf(fd);
+ r = writebuf(fd);
close(fd);
return r;
}
@@ -107,18 +419,27 @@
s += n;
}
switch(r){
-// case 'd': return delete(s);
-// case 'c': return cut(s);
-// case 'p': return paste(s);
-// case 'x': return crop(s);
+// case '<': return pipefrom(s);
// case '^': return exchange(s);
case '|': return pipeto(s);
-// case '<': return pipefrom(s);
- case 'w': return writeto(s);
+// case 'c': return copy(s);
+// case 'd': return cut(s);
+// case 'p': return paste(s);
// case 'r': return readfrom(s);
+ case 'w': return writeto(s);
+// case 'x': return crop(s);
default: werrstr("unknown command %C", r); break;
}
return -1;
+}
+
+int
+loadin(int fd)
+{
+ if(readintochunks(fd) == nil)
+ sysfatal("loadin: %r");
+ setrange(0, totalsz);
+ return 0;
}
static void
--- a/dat.h
+++ b/dat.h
@@ -1,14 +1,35 @@
+typedef struct Chunk Chunk;
+typedef struct Pos Pos;
+typedef struct Dot Dot;
+
enum{
- Ndelay = 44100 / 25,
- Nchunk = Ndelay * 4,
- Nreadsz = 4*1024*1024,
+ Rate = 44100,
+ WriteRate = 25,
+ WriteDelay = Rate / WriteRate, /* 1764 default delay */
+ Sampsz = 2 * 2,
+ Outsz = WriteDelay * Sampsz,
+ Iochunksz = 1*1024*1024, /* ≈ 6 sec. at 44.1 kHz */
+ Ioreadsz = Iochunksz / 32,
};
+struct Chunk{
+ uchar *buf;
+ usize bufsz;
+ Chunk *left;
+ Chunk *right;
+};
+struct Pos{
+ usize pos; /* bytes */
+};
+extern struct Dot{
+ Pos;
+ Pos from;
+ Pos to;
+};
+extern Dot dot;
+extern usize totalsz;
-extern int ifd;
-extern uchar *pcmbuf;
-extern vlong filesz, nsamp;
-
-extern vlong seekp, T, loops, loope;
-
-extern int file, stereo;
+extern int stereo;
extern int zoom;
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
--- a/draw.c
+++ b/draw.c
@@ -15,9 +15,11 @@
static Image *viewbg, *view;
static Rectangle liner;
static Point statp;
-static vlong views, viewe, viewmax;
+static usize views, viewe, viewmax;
static int bgscalyl, bgscalyr, bgscalf;
static Channel *drawc;
+static usize T;
+static uchar sbuf[Iochunksz];
static Image *
eallocimage(Rectangle r, int repl, ulong col)
@@ -32,38 +34,36 @@
static void
drawsamps(void*)
{
- int x, n, lmin, lmax, rmin, rmax;
+ int x, lmin, lmax, rmin, rmax;
+ usize n, m;
s16int s;
- uchar *p, *e, *et;
+ uchar *p, *e;
Rectangle l, r;
+ Dot d;
for(;;){
+end:
recvul(drawc);
again:
lockdisplay(display);
draw(viewbg, viewbg->r, display->black, nil, ZP);
unlockdisplay(display);
- n = viewe - views;
- /*if(!file)*/
- p = pcmbuf + views;
- /*else{
- seek(ifd, bgofs, 0);
- n = read(ifd, bgbuf, n);
- seek(ifd, seekp, 0);
- p = bgbuf;
- }*/
- e = p + n;
+ d.pos = views;
+ m = viewe - views;
x = 0;
- while(p < e){
+ while(m > 0){
if(nbrecvul(drawc) == 1)
goto again;
- n = T;
- if(n > e - p)
- n -= n - (e - p);
- et = p + n;
+ n = m < T ? m : T;
+ if((p = getbuf(d, n, sbuf, &n)) == nil){
+ fprint(2, "getbuf: %r\n");
+ goto end;
+ }
+ d.pos += n;
+ e = p + n;
lmin = lmax = 0;
rmin = rmax = 0;
- while(p < et){
+ while(p < e){
s = (s16int)(p[1] << 8 | p[0]);
if(s < lmin)
lmin = s;
@@ -78,15 +78,16 @@
}
p += 4;
}
+ m -= n;
l = Rect(x, bgscalyl - lmax / bgscalf,
x+1, bgscalyl - lmin / bgscalf);
r = Rect(x, bgscalyr - rmax / bgscalf,
x+1, bgscalyr - rmin / bgscalf);
- lockdisplay(display);
+ lockdisplay(display);
draw(viewbg, l, col[Csamp], nil, ZP);
- unlockdisplay(display);
if(stereo)
draw(viewbg, r, col[Csamp], nil, ZP);
+ unlockdisplay(display);
x++;
}
}
@@ -93,9 +94,9 @@
}
static void
-b2t(uvlong ofs, int *th, int *tm, int *ts, int *tμ)
+b2t(usize ofs, int *th, int *tm, int *ts, int *tμ)
{
- uvlong nsamp;
+ usize nsamp;
nsamp = ofs / 4;
*ts = nsamp / 44100;
@@ -109,27 +110,21 @@
drawstat(void)
{
int th, tm, ts, tμ;
- uvlong ssamp;
char s[256], *p;
- ssamp = seekp / 4;
- ts = ssamp / 44100;
- tm = ts / 60;
- th = tm / 60;
- tμ = 100 * (ssamp - ts * 44100) / 44100;
- ts %= 60;
+ b2t(dot.pos, &th, &tm, &ts, &tμ);
p = seprint(s, s+sizeof s, "T %lld @ %02d:%02d:%02d.%03d (%llud) ⋅ ",
- T/4, th, tm, ts, tμ, ssamp);
- if(loops != 0 && loops >= views){
- b2t(loops, &th, &tm, &ts, &tμ);
+ T/4, th, tm, ts, tμ, dot.pos/4);
+ if(dot.from.pos > 0){
+ b2t(dot.from.pos, &th, &tm, &ts, &tμ);
p = seprint(p, s+sizeof s, "%02d:%02d:%02d.%03d (%llud) ↺ ",
- th, tm, ts, tμ, loops);
+ th, tm, ts, tμ, dot.from.pos/4);
}else
p = seprint(p, s+sizeof s, "0 ↺ ");
- if(loope != filesz){
- b2t(loope, &th, &tm, &ts, &tμ);
+ if(dot.to.pos != totalsz){
+ b2t(dot.to.pos, &th, &tm, &ts, &tμ);
seprint(p, s+sizeof s, "%02d:%02d:%02d.%03d (%llud)",
- th, tm, ts, tμ, loope);
+ th, tm, ts, tμ, dot.to.pos/4);
}else
seprint(p, s+sizeof s, "∞");
string(screen, statp, col[Cline], ZP, font, s);
@@ -139,18 +134,21 @@
drawview(void)
{
int x;
+ usize left, right;
Rectangle r;
+ left = dot.from.pos;
draw(view, view->r, viewbg, nil, ZP);
- if(loops != 0 && loops >= views){
- x = (loops - views) / T;
+ if(left != 0 && left >= views){
+ x = (left - views) / T;
r = view->r;
r.min.x += x;
r.max.x = r.min.x + 1;
draw(view, r, col[Cloop], nil, ZP);
}
- if(loope != filesz ){
- x = (loope - views) / T;
+ right = dot.to.pos;
+ if(right != totalsz){
+ x = (right - views) / T;
r = view->r;
r.min.x += x;
r.max.x = r.min.x + 1;
@@ -162,16 +160,18 @@
update(void)
{
int x;
+ usize p;
+ p = dot.pos;
lockdisplay(display);
drawview();
- x = screen->r.min.x + (seekp - views) / T;
- //if(liner.min.x == x || seekp < views && x > liner.min.x)
+ x = screen->r.min.x + (p - views) / T;
+ //if(liner.min.x == x || p < views && x > liner.min.x)
// return;
draw(screen, screen->r, view, nil, ZP);
liner.min.x = x;
liner.max.x = x + 1;
- if(seekp >= views)
+ if(p >= views)
draw(screen, liner, col[Cline], nil, ZP);
drawstat();
flushimage(display, 1);
@@ -189,7 +189,7 @@
z = zoom >> -Δz;
else
z = zoom << Δz;
- if(z < 1 || z > nsamp / Dx(screen->r))
+ if(z < 1 || z > (totalsz / 4) / Dx(screen->r))
return;
zoom = z;
redraw(0);
@@ -206,36 +206,43 @@
}
void
-setloop(vlong ofs)
+setloop(vlong off)
{
- ofs *= T;
- ofs += views;
- if(ofs < 0 || ofs > filesz)
+ off *= T;
+ off += views;
+ if(off < 0 || off > totalsz)
return;
- if(ofs < seekp)
- loops = ofs;
+ if(off < dot.pos)
+ setrange(off, dot.to.pos);
else
- loope = ofs;
+ setrange(dot.from.pos, off);
update();
}
void
-setpos(vlong ofs)
+setcur(usize off, int jumponly)
{
- if(ofs < loops || ofs > loope - Nchunk)
+ if(off < dot.from.pos || off > dot.to.pos - Outsz)
return;
- seekp = ofs;
- if(file)
- seek(ifd, ofs, 0);
+ if(jumponly)
+ jump(off);
+ else
+ setpos(off);
update();
}
void
-setofs(vlong ofs)
+setjump(usize off)
{
- setpos(views + ofs * T);
+ setcur(off, 1);
}
+void
+setofs(usize ofs)
+{
+ setcur(views + ofs * T, 0);
+}
+
static void
resetdraw(void)
{
@@ -242,7 +249,7 @@
int x;
Rectangle viewr, midr;
- x = screen->r.min.x + (seekp - views) / T;
+ x = screen->r.min.x + (dot.pos - views) / T;
viewr = rectsubpt(screen->r, screen->r.min);
freeimage(viewbg);
freeimage(view);
@@ -268,17 +275,15 @@
void
redraw(int all)
{
- vlong span;
+ usize span;
lockdisplay(display);
- T = filesz / zoom / Dx(screen->r) & ~3;
+ T = totalsz / zoom / Dx(screen->r) & ~3;
if(T == 0)
T = 4;
span = Dx(screen->r) * T;
- viewmax = filesz - span;
- if(views < 0)
- views = 0;
- else if(views > viewmax)
+ viewmax = totalsz - span;
+ if(views > viewmax)
views = viewmax;
viewe = views + span;
if(all)
@@ -298,7 +303,6 @@
col[Csamp] = eallocimage(Rect(0,0,1,1), 1, 0x440000FF);
col[Cline] = eallocimage(Rect(0,0,1,1), 1, 0x884400FF);
col[Cloop] = eallocimage(Rect(0,0,1,1), 1, 0x777777FF);
- loope = filesz;
if((drawc = chancreate(sizeof(ulong), 4)) == nil)
sysfatal("chancreate: %r");
if(proccreate(drawsamps, nil, mainstacksize) < 0)
--- a/fns.h
+++ b/fns.h
@@ -4,8 +4,18 @@
void setzoom(int, int);
void setpan(int);
void setloop(vlong);
-void setpos(vlong);
-void setofs(vlong);
+void setcur(usize, int);
+void setofs(usize);
+void setjump(usize);
void redraw(int);
void initdrw(void);
-void* emalloc(ulong);
+void advance(Dot*, usize);
+void jump(usize);
+void setrange(usize, usize);
+int setpos(usize);
+uchar* getbuf(Dot, usize, uchar*, usize*);
+int loadin(int);
+void* emalloc(usize);
+void* erealloc(void*, usize, usize);
+char* estrdup(char*);
+int setpri(int);
--- a/mkfile
+++ b/mkfile
@@ -6,6 +6,7 @@
cmd.$O\
draw.$O\
pplay.$O\
+ util.$O\
HFILES=dat.h fns.h
</sys/src/cmd/mkone
--- a/pplay.c
+++ b/pplay.c
@@ -7,68 +7,36 @@
#include "dat.h"
#include "fns.h"
-int ifd;
-uchar *pcmbuf;
-vlong filesz, nsamp;
-int file, stereo, zoom = 1;
-vlong seekp, T, loops, loope;
+int stereo, zoom = 1;
static Keyboardctl *kc;
static Mousectl *mc;
static int cat;
static int afd = -1;
+static uchar sbuf[Iochunksz];
-void *
-emalloc(ulong n)
-{
- void *p;
-
- if((p = mallocz(n, 1)) == nil)
- sysfatal("emalloc: %r");
- setmalloctag(p, getcallerpc(&n));
- return p;
-}
-
-static int
-setpri(int pri)
-{
- int n, fd, pid;
- char path[32];
-
- if((pid = getpid()) == 0)
- return -1;
- snprint(path, sizeof path, "/proc/%d/ctl", pid);
- if((fd = open(path, OWRITE)) < 0)
- return -1;
- n = fprint(fd, "pri %d\n", pri);
- close(fd);
- if(n < 0)
- return -1;
- return 0;
-}
-
static void
athread(void *)
{
- int n;
+ int nerr;
uchar *p;
+ usize n;
- p = pcmbuf;
+ nerr = 0;
for(;;){
- if(afd < 0)
+ if(afd < 0 || nerr > 10)
return;
- n = seekp + Nchunk >= loope ? loope - seekp : Nchunk;
- if(!file)
- p = pcmbuf + seekp;
- else if(read(ifd, pcmbuf, n) != n)
- fprint(2, "read: %r\n");
- if(write(afd, p, n) != n){
+ if((p = getbuf(dot, Outsz, sbuf, &n)) == nil){
fprint(2, "athread: %r\n");
+ nerr++;
+ continue;
+ }
+ if(write(afd, p, n) != n){
+ fprint(2, "athread write: %r (nerr %d)\n", nerr);
break;
}
- seekp += n;
- if(seekp >= loope)
- setpos(loops);
+ nerr = 0;
+ advance(&dot, n);
update();
yield();
}
@@ -106,48 +74,9 @@
}
static void
-reallocbuf(ulong n)
-{
- if((pcmbuf = realloc(pcmbuf, n)) == nil)
- sysfatal("realloc: %r");
-}
-
-static void
-initbuf(int fd)
-{
- int n, sz;
- vlong ofs;
- Dir *d;
-
- reallocbuf(filesz += Nreadsz);
- ifd = fd;
- if(file){
- if((d = dirfstat(fd)) == nil)
- sysfatal("dirfstat: %r");
- filesz = d->length;
- nsamp = filesz / 4;
- free(d);
- return;
- }
- if((sz = iounit(fd)) == 0)
- sz = 8192;
- ofs = 0;
- while((n = read(fd, pcmbuf+ofs, sz)) > 0){
- ofs += n;
- if(ofs + sz >= filesz)
- reallocbuf(filesz += Nreadsz);
- }
- if(n < 0)
- sysfatal("read: %r");
- filesz = ofs;
- reallocbuf(filesz);
- nsamp = filesz / 4;
-}
-
-static void
usage(void)
{
- fprint(2, "usage: %s [-cfs] [pcm]\n", argv0);
+ fprint(2, "usage: %s [-cs] [pcm]\n", argv0);
threadexits("usage");
}
@@ -161,13 +90,13 @@
ARGBEGIN{
case 'c': cat = 1; break;
- case 'f': file = 1; break;
case 's': stereo = 1; break;
default: usage();
}ARGEND
if((fd = *argv != nil ? open(*argv, OREAD) : 0) < 0)
sysfatal("open: %r");
- initbuf(fd);
+ if(loadin(fd) < 0)
+ sysfatal("inittrack: %r");
close(fd);
initdrw();
if((kc = initkeyboard(nil)) == nil)
@@ -208,8 +137,8 @@
case 2:
switch(r){
case ' ': toggleplay(); break;
- case 'b': setpos(loops); break;
- case Kesc: loops = 0; loope = filesz; update(); break;
+ case 'b': setjump(dot.from.pos); break;
+ case Kesc: setrange(0, totalsz); update(); break;
case Kdel:
case 'q': threadexitsall(nil);
case 'z': setzoom(-zoom + 1, 0); break;
--- /dev/null
+++ b/util.c
@@ -1,0 +1,54 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+void *
+emalloc(usize n)
+{
+ void *p;
+
+ if((p = mallocz(n, 1)) == nil)
+ sysfatal("emalloc: %r");
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
+
+void *
+erealloc(void *p, usize n, usize oldn)
+{
+ if((p = realloc(p, n)) == nil)
+ sysfatal("realloc: %r");
+ setrealloctag(p, getcallerpc(&p));
+ if(n > oldn)
+ memset((uchar *)p + oldn, 0, n - oldn);
+ return p;
+}
+
+char *
+estrdup(char *s)
+{
+ if((s = strdup(s)) == nil)
+ sysfatal("estrdup: %r");
+ setmalloctag(s, getcallerpc(&s));
+ return s;
+}
+
+int
+setpri(int pri)
+{
+ int n, fd, pid;
+ char path[32];
+
+ if((pid = getpid()) == 0)
+ return -1;
+ snprint(path, sizeof path, "/proc/%d/ctl", pid);
+ if((fd = open(path, OWRITE)) < 0)
+ return -1;
+ n = fprint(fd, "pri %d\n", pri);
+ close(fd);
+ if(n < 0)
+ return -1;
+ return 0;
+}