amp

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

ampfs.c (6021B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <fcall.h>
      4 #include <thread.h>
      5 #include <9p.h>
      6 #include <plumb.h>
      7 
      8 #include "pages.h"
      9 
     10 enum {
     11 	FrameSize = sizeof(s16int) * 2,
     12 };
     13 
     14 PBuf pg;
     15 
     16 struct {
     17 	vlong min;
     18 	vlong max;
     19 	char str[12*3+1]; // see update_selstr
     20 } sel;
     21 
     22 void plumbsel(void);
     23 
     24 void fs_open(Req *r);
     25 void fs_read(Req *r);
     26 void fs_write(Req *r);
     27 
     28 void fcut_open(Req *r);
     29 void fcut_write(Req *r);
     30 
     31 void normalize_sel(void);
     32 void update_selstr(void);
     33 
     34 void threadplumb(void *);
     35 
     36 Srv ampsrv = {
     37 	.read = fs_read,
     38 	.write = fs_write,
     39 	.open = fs_open,
     40 };
     41 
     42 File *fdata, *fcut, *fctl;
     43 char *service, *mountpath = "/mnt/amp";
     44 
     45 struct {
     46 	int send, recv;
     47 	char *port;
     48 } plumb = {.port = "amp"};
     49 
     50 void
     51 usage(void)
     52 {
     53 	fprint(2,"usage: %s\n", argv0);
     54 	threadexitsall("usage");
     55 }
     56 
     57 void
     58 threadmain(int argc, char **argv)
     59 {
     60 	ARGBEGIN {
     61 	case 'D':
     62 		chatty9p++;
     63 		break;
     64 	case 's':
     65 		service = EARGF(usage());
     66 		break;
     67 	case 'm':
     68 		mountpath = EARGF(usage());
     69 		break;
     70 	default: usage();
     71 	} ARGEND
     72 	if (argc != 0) usage();
     73 
     74 	plumb.send = plumbopen("send", OWRITE);
     75 	if (plumb.send < 0) fprint(2, "%r\n");
     76 	plumb.recv = plumbopen(plumb.port, OREAD);
     77 	if (plumb.recv <0) fprint(2, "%r\n");
     78 
     79 	proccreate(threadplumb, nil, 1024);
     80 	update_selstr();
     81 	ampsrv.tree = alloctree("amp", "amp", DMDIR|0555, nil);
     82 	fdata = createfile(ampsrv.tree->root, "data", "amp", 0666, nil);
     83 	fcut = createfile(ampsrv.tree->root, "cut", "amp", 0666, nil);
     84 	fctl = createfile(ampsrv.tree->root, "ctl", "amp", 0666, nil);
     85 	threadpostmountsrv(&ampsrv, service, mountpath, MREPL);
     86 }
     87 
     88 void
     89 threadplumb(void *)
     90 {
     91 	Plumbmsg *m;
     92 	vlong s, e;
     93 	if (plumb.recv < 0) return;
     94 	threadsetname("plumb");
     95 	for (;;) {
     96 		m = plumbrecv(plumb.recv);
     97 		if (m->ndata < 24) fprint(2, "plumb message too short\n");
     98 		else if (strcmp(m->src, "ampfs") != 0){
     99 			s = strtoll(m->data, nil, 10);
    100 			e = strtoll(m->data + 12, nil, 10);
    101 			sel.max = s, sel.min = e;
    102 			normalize_sel();
    103 			update_selstr();
    104 			fcut->length = (sel.max - sel.min);
    105 		}
    106 		plumbfree(m);
    107 	}
    108 }
    109 
    110 void
    111 plumbsel(void)
    112 {
    113 	Plumbmsg *m;
    114 	m = mallocz(sizeof(Plumbmsg), 1);
    115 	m->src = smprint("ampfs");
    116 	m->dst = strdup(plumb.port);
    117 	m->type = strdup("text");
    118 	m->data = smprint("%11lld %11lld ", sel.min, sel.max);
    119 	m->ndata = strlen(m->data);
    120 	plumbsend(plumb.send, m);
    121 	plumbfree(m);
    122 }
    123 
    124 void
    125 fs_open(Req *r)
    126 {
    127 	char *rstr = nil;
    128 	File *file = r->fid->file;
    129 	uchar mode = r->ifcall.mode;
    130 	if (file == fcut) {
    131 		fcut_open(r);
    132 		goto end;
    133 	}
    134 	if ((mode & OTRUNC) == 0) goto end;
    135 	if (file == fctl) goto end;
    136 	if (file == fdata) {
    137 		pg.length = 0;
    138 		fdata->length = 0;
    139 		// TODO: free pages ???
    140 		// probably better to do it on fs_close()
    141 		goto end;
    142 	}
    143 	rstr = "what";
    144 end:
    145 	respond(r, rstr);
    146 }
    147 
    148 void
    149 fs_read(Req *r)
    150 {
    151 	if (r->fid->file == fdata) {
    152 		r->ofcall.count = pbread(&pg, r->ofcall.data,
    153 		  r->ifcall.count, r->ifcall.offset);
    154 		respond(r, nil);
    155 	} else if (r->fid->file == fcut) {
    156 		long min = sel.min;
    157 		long max = sel.max;
    158 		r->ifcall.offset += min;
    159 		if (r->ifcall.offset + r->ifcall.count > max)
    160 			r->ifcall.count = max - r->ifcall.offset;
    161 		if (r->ifcall.offset > max) r->ifcall.count = 0;
    162 		r->ofcall.count = pbread(&pg, r->ofcall.data,
    163 		  r->ifcall.count, r->ifcall.offset);
    164 		respond(r, nil);
    165 	} else if (r->fid->file == fctl) {
    166 		readstr(r, sel.str);
    167 		respond(r, nil);
    168 	} else {
    169 		respond(r, "nope");
    170 	}
    171 }
    172 
    173 void
    174 fs_write(Req *r)
    175 {
    176 	if (r->fid->file == fdata) {
    177 		r->ofcall.count = pbwrite(&pg, r->ifcall.data,
    178 		  r->ifcall.count, r->ifcall.offset);
    179 		if (pg.length > fdata->length) fdata->length = pg.length;
    180 		update_selstr();
    181 		respond(r, nil);
    182 	} else if (r->fid->file == fcut) {
    183 		fcut_write(r);
    184 		update_selstr();
    185 		respond(r, nil);
    186 	} else if (r->fid->file == fctl) {
    187 		vlong newmin, newmax;
    188 		char *np, *rp;
    189 		np = r->ifcall.data;
    190 		newmin = strtol(np, &rp, 10);
    191 		if (rp <= np) {
    192 			respond(r, "bad first value");
    193 			return;
    194 		}
    195 		newmax = strtol(rp, &rp, 10);
    196 		if (rp <= np) {
    197 			respond(r, "bad second value");
    198 			return;
    199 		}
    200 		if (rp - np > r->ifcall.count) {
    201 			respond(r, "somehow buffer overrun");
    202 			return;
    203 		}
    204 		sel.min = newmin;
    205 		sel.max = newmax;
    206 		normalize_sel();
    207 		update_selstr();
    208 		fcut->length = (sel.max - sel.min);
    209 		r->ofcall.count = r->ifcall.count;
    210 		plumbsel();
    211 		respond(r, nil);
    212 	} else {
    213 		respond(r, "nope");
    214 	}
    215 }
    216 
    217 void
    218 fcut_open(Req *r)
    219 {
    220 	if ((r->ifcall.mode & OTRUNC) != 0) {
    221 		Page *maxpg = splitpage(&pg, sel.max);
    222 		Page *minpg = splitpage(&pg, sel.min);
    223 		assert(minpg != nil);
    224 		assert(maxpg != nil);
    225 		if (minpg->prev != nil) {
    226 			minpg->prev->next = maxpg;
    227 			maxpg->prev = minpg->prev;
    228 		} else {
    229 			pg.start = maxpg;
    230 			maxpg->prev = nil;
    231 		}
    232 		while (minpg != maxpg) {
    233 			Page *fp = minpg;
    234 			fp->as->len = 0;
    235 			minpg = fp->next;
    236 			freepage(fp);
    237 		}
    238 		pg.length -= sel.max - sel.min;
    239 		fdata->length = pg.length;
    240 		fcut->length = 0;
    241 		sel.max = sel.min;
    242 		normalize_sel();
    243 		plumbsel();
    244 	}
    245 }
    246 
    247 void
    248 fcut_write(Req *r)
    249 {
    250 	Page *maxpage;
    251 	vlong offset;
    252 	long count;
    253 
    254 	maxpage = splitpage(&pg, sel.max);
    255 	if (maxpage == nil) {
    256 		maxpage = addpage(&pg);
    257 	}
    258 	// insert more pages as needed
    259 	offset = r->ifcall.offset + sel.min;
    260 	count = r->ifcall.count;
    261 	while (offset + count > sel.max) {
    262 		long n = offset + count - sel.max;
    263 		if (n > PageSize) n = PageSize;
    264 		Page *ins = allocpage();
    265 		ins->as->len = n;
    266 		ins->next = maxpage;
    267 		ins->prev = maxpage->prev;
    268 		if (maxpage->prev != nil) maxpage->prev->next = ins;
    269 		else {
    270 			pg.start = ins;
    271 		}
    272 		maxpage->prev = ins;
    273 		sel.max += n;
    274 		pg.length  += n;
    275 	}
    276 	normalize_sel();
    277 	fcut->length = (sel.max - sel.min);
    278 	fdata->length = pg.length;
    279 	plumbsel();
    280 	// write to pagebuffer as usual
    281 	r->ofcall.count = pbwrite(&pg, r->ifcall.data, count, offset);
    282 }
    283 
    284 void
    285 normalize_sel(void)
    286 {
    287 	vlong bufmax = pg.length;
    288 	if (sel.min > bufmax) sel.min = bufmax;
    289 	if (sel.max > bufmax) sel.max = bufmax;
    290 	if (sel.min > sel.max) {
    291 		int x = sel.max;
    292 		sel.max = sel.min;
    293 		sel.min = x;
    294 	}
    295 }
    296 
    297 void
    298 update_selstr(void)
    299 {
    300 	snprint(sel.str, sizeof(sel.str), "%11lld %11lld %11lld \n",
    301 	  sel.min, sel.max, pg.length);
    302 }