amp

pcm player/editor for plan9
git clone git://nsmpr.xyz/amp.git
Log | Files | Refs | README

amp.c (5793B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <draw.h>
      4 #include <thread.h>
      5 #include <mouse.h>
      6 #include <cursor.h>
      7 #include <keyboard.h>
      8 
      9 enum {
     10 	DHeight = 32,
     11 	DCacheSize = 32,
     12 	Zoomout = 512,
     13 	Margin = 4,
     14 };
     15 
     16 typedef struct DCache DCache;
     17 struct DCache {
     18 	int c;
     19 	ulong start;
     20 	Image *img;
     21 };
     22 
     23 DCache dcache[DCacheSize];
     24 
     25 s8int *pcm, *pp;
     26 u8int *mono8;
     27 long pcmlen, scroll;
     28 Image *Ibg, *Itrbg, *Itrfg, *Irow;
     29 Rectangle rbars;
     30 int fid, dwidth, needflush, maxlines;
     31 char *path;
     32 
     33 void usage(void);
     34 void clear(void);
     35 void drawpcm(Point, ulong);
     36 void drawcur(Point);
     37 void redraw(ulong);
     38 void resize(void);
     39 void loadpcm(int);
     40 u8int* mkmono8(s8int*, long);
     41 int fillrow(ulong, ulong);
     42 int row(int);
     43 void drawscroll(int);
     44 void threadflush(void *);
     45 
     46 void
     47 threadmain(int argc, char **argv)
     48 {
     49 	Mousectl *mctl;
     50 	Keyboardctl *kctl;
     51 	Mouse mv;
     52 	Rune  kv;
     53 	int   rv[2];
     54 
     55 	ARGBEGIN{
     56 	default:
     57 		usage();
     58 	}ARGEND;
     59 
     60 	if (argc == 0) usage();
     61 	path = argv[0];
     62 	fid = open(path, OREAD);
     63 	loadpcm(fid);
     64 	mono8 = mkmono8(pcm, pcmlen);
     65 
     66 	if (argc <= 0) usage();
     67 	if(initdraw(0, 0, "amp") < 0)
     68 		sysfatal("inidraw failed: %r");
     69 	if((mctl = initmouse(0, screen)) == nil)
     70 		sysfatal("initmouse failed: %r");
     71 	if((kctl = initkeyboard(0)) == nil)
     72 		sysfatal("initkeyboard failed: %r");
     73 
     74 	display->locking = 1;
     75 	unlockdisplay(display);
     76 
     77 	proccreate(threadflush, nil, 1024);
     78 
     79 	lockdisplay(display);
     80 	Ibg = allocimage(display, Rect(0,0,1,1), RGB24, 1, 0xBBBBBBFF);
     81 	Itrbg = allocimage(display, Rect(0,0,1,1), RGB24, 1, DWhite);
     82 	Itrfg = allocimage(display, Rect(0,0,1,1), RGB24, 1, DBlack);
     83 	resize();
     84 	Irow = allocimage(display, Rect(0, 0, dwidth, DHeight), CMAP8, 0, DBlue);
     85 	clear();
     86 	unlockdisplay(display);
     87 	redraw(0);
     88 	needflush = 1;
     89 	Alt alts[5] = {
     90 		{kctl->c, &kv, CHANRCV},
     91 		{mctl->c, &mv, CHANRCV},
     92 		{mctl->resizec, rv, CHANRCV},
     93 		{0, 0, CHANEND},
     94 	};
     95 	for (;;) {
     96 		switch (alt(alts)) {
     97 		case 0: /* keyboard */
     98 			if (kv == 0x7f) threadexitsall(nil);
     99 			if (kv == Kdown) drawscroll(maxlines/3);
    100 			if (kv == Kup) drawscroll(-maxlines/3);
    101 			if (kv == Kpgdown) drawscroll(maxlines);
    102 			if (kv == Kpgup) drawscroll(-maxlines);
    103 			break;
    104 		case 1: /* mouse */
    105 			//if (mv.buttons == 0);
    106 			//if (mv.buttons == 1);
    107 			//if (mv.buttons == 4);
    108 			if (mv.buttons == 8) drawscroll(-row(mv.xy.y));
    109 			if (mv.buttons == 16) drawscroll(row(mv.xy.y));
    110 			break;
    111 		case 2: /* resize */
    112 			lockdisplay(display);
    113 			if(getwindow(display, Refnone) < 0)
    114 				sysfatal("resize failed: %r");
    115 			resize();
    116 			freeimage(Irow);
    117 			Irow = allocimage(display, Rect(0, 0, dwidth, DHeight),
    118 				CMAP8, 0, DBlue);
    119 			clear();
    120 			unlockdisplay(display);
    121 			redraw(scroll * dwidth);
    122 			needflush = 1;
    123 			break;
    124 		}
    125 	}
    126 }
    127 
    128 void
    129 threadflush(void *)
    130 {
    131 	threadsetname("flush");
    132 	for (;;) {
    133 		if (needflush != 0) {
    134 			lockdisplay(display);
    135 			flushimage(display, 1);
    136 			unlockdisplay(display);
    137 			needflush = 0;
    138 		}
    139 		sleep(1000/60);
    140 	}
    141 }
    142 
    143 void
    144 resize(void)
    145 {
    146 	dwidth = Dx(screen->r) - Margin * 2;
    147 	rbars = screen->r;
    148 	rbars.min.x += Margin;
    149 	rbars.max.x -= Margin;
    150 	rbars.min.y += Margin;
    151 	rbars.max.y -= Margin;
    152 	if (scroll > pcmlen/(4 * Zoomout*dwidth))
    153 		scroll = pcmlen/(4 * Zoomout*dwidth);
    154 	maxlines = Dy(rbars) / (DHeight + Margin);
    155 }
    156 
    157 void
    158 usage(void)
    159 {
    160 	fprint(2, "usage: %s file.pcm\n", argv0);
    161 	threadexitsall("usage");
    162 }
    163 
    164 void
    165 clear(void)
    166 {
    167 	draw(screen, screen->r, Ibg, nil, ZP);
    168 }
    169 
    170 Image *
    171 getmask(ulong start, ulong width)
    172 {
    173 	Rectangle r;
    174 	r = Irow->r;
    175 	r.max.x = r.min.x + fillrow(start, width);
    176 	replclipr(Irow, 0, r);
    177 	return Irow;
    178 }
    179 
    180 void
    181 drawpcm(Point p, ulong start)
    182 {
    183 	Image *mask;
    184 	Rectangle r;
    185 	mask = getmask(start, dwidth);
    186 	r.min = p;
    187 	r.max.x = r.min.x + Dx(mask->clipr);
    188 	r.max.y = r.min.y + DHeight;
    189 	lockdisplay(display);
    190 	draw(screen, r, mask, 0, ZP);
    191 	unlockdisplay(display);
    192 	needflush = 1;
    193 	return;
    194 }
    195 
    196 void
    197 redraw(ulong d)
    198 {
    199 	Point p;
    200 	p = rbars.min;
    201 	while (p.y < screen->r.max.y) {
    202 		if (d > pcmlen/(4 * Zoomout)) break;
    203 		drawpcm(p, d);
    204 		d += dwidth;
    205 		p.y += DHeight + Margin;
    206 	}
    207 }
    208 
    209 void
    210 loadpcm(int fd)
    211 {
    212 	long n;
    213 	s8int *buf;
    214 	buf = malloc(32 * 1024);
    215 	pcmlen = 0;
    216 	while((n = read(fd, buf, 32 * 1024)) > 0){
    217 		pcm = realloc(pcm, pcmlen + n);
    218 		memcpy(pcm + pcmlen, buf, n);
    219 		pcmlen += n;
    220 	}
    221 	pp = pcm;
    222 	free(buf);
    223 }
    224 
    225 int
    226 fillrow(ulong start, ulong width)
    227 {
    228 	u8int min, max;
    229 	uint dmin, dmax;
    230 	long end, bsize;
    231 	ulong n, i, j;
    232 	u8int *buf, *bp;
    233 	end = (start + width) * Zoomout;
    234 	if (end > pcmlen / 4) end = pcmlen / 4;
    235 	bsize = width * Dy(Irow->r);
    236 	buf = malloc(bsize);
    237 	bp = buf;
    238 	min = 0x7f;
    239 	max = -0x7f;
    240 	for (i=0, n=start*Zoomout; (n<end)&&(bp<buf+width); n++, i++) {
    241 		if (min > mono8[n]) min = mono8[n];
    242 		if (max < mono8[n]) max = mono8[n];
    243 		if (i >= Zoomout) {
    244 			i = 0;
    245 			dmin = min * DHeight / 256;
    246 			dmax = max * DHeight / 256;
    247 			for (j = 0; j < dmin; j++) *(bp + j * width) = 0xff;
    248 			for (j = dmin; j < dmax; j++) *(bp + j * width) = 0x00;
    249 			for (j = dmax; j < Dy(Irow->r); j++) *(bp + j * width) = 0xff;
    250 			min = 0x7f;
    251 			max = -0x7f;
    252 			bp++;
    253 		}
    254 	}
    255 	Rectangle r;
    256 	r = Irow->r;
    257 	r.max.x = r.min.x + width;
    258 	lockdisplay(display);
    259 	loadimage(Irow, r, buf, bsize);
    260 	unlockdisplay(display);
    261 	free(buf);
    262 	return bp - buf;
    263 }
    264 
    265 int
    266 row(int y)
    267 {
    268 	return 1 + (y - rbars.min.y) / (DHeight + Margin);
    269 }
    270 
    271 u8int*
    272 mkmono8(s8int *pcm, long pcmlen)
    273 {
    274 	long i, j;
    275 	u8int *mono8;
    276 	mono8 = malloc(sizeof(s8int) * pcmlen / 4);
    277 	for (i = 0, j = 0; i < pcmlen; i+=4, j++) {
    278 		mono8[j] = (pcm[i+1] + pcm[i+3] + 256) / 2;
    279 	}
    280 	return mono8;
    281 }
    282 
    283 void
    284 drawscroll(int ds)
    285 {
    286 	scroll += ds;
    287 	if (scroll < 0) {
    288 		ds -= scroll;
    289 		scroll = 0;
    290 	}
    291 	if (scroll > pcmlen / (4 * Zoomout * dwidth)) {
    292 		ds -=  scroll - pcmlen / (4 * Zoomout * dwidth);
    293 		scroll = pcmlen / (4 * Zoomout * dwidth);
    294 	}
    295 	if (ds == 0) return;
    296 	lockdisplay(display);
    297 	clear();
    298 	unlockdisplay(display);
    299 	needflush = 1;
    300 	redraw(scroll * dwidth);
    301 }