Plan 9 from Bell Labs’s /sys/src/games/agui/main.c

Copyright © 2021 Plan 9 Foundation
Distributed under the MIT License.
Download the Plan 9 distribution.


#include	<audio.h>

void
main(int argc, char *argv[])
{
	int etype, but, i;
	char *file;
	long so;

	rootbin = "/bin";
	rootaudio = "/lib/audio";
	devaudio = "/dev/audio";
	devvolume = "/dev/volume";

	ARGBEGIN {
	default:
		fprint(2, "usage: agui\n");
		exits("usage");
	case 'm':			/* read and convert agui */
		mflag = 1;
		break;
	} ARGEND

	file = getenv("devaudio");
	if(file)
		devaudio = file;
	file = getenv("devvolume");
	if(file)
		devvolume = file;

	file = getenv("home");
	if(file)
		sprint(markfile, "%s/tmp/agui/%s", file, "%s");

	file = "/lib/audio/rawmap";
	if(argc > 0)
		file = argv[0];
	bin = Iopen(file, OREAD);
	if(bin == 0) {
		fprint(2, "cannot open: %s: %r\n", file);
		exits(0);
	}

	Iseek(bin, 0, 0);
	for(i=0; i<4; i++)
		if(Igetc(bin) != "admp"[i]) {
			fprint(2, "%s: not an audio rawmap\n", file);
			exits(0);
		}
	strings = get4(bin, 0);
	nstrings = get4(bin, strings);
	strings += 4;

	Iseek(bin, strings+4*nstrings, 0);
	for(i=0; i<nelem(bschar); i++)
		bschar[i] = get4(bin, 0);

//	for(i = 0; i < nelem(bschar); i += 2)
//		print("%6ld %6ld\n", bschar[i], bschar[i+1]);

	if(mflag) {
		/* recanonical the mark file */
		i = openmark("def");
		if(i >= 0)
			close(i);
		so = Osearch;

	mnext:
		readmark("inzy", so);
		for(i=0; i<nmark; i++) {
			if(marks[i] == so-1)
				continue;
			if(marks[i] == so+1) {
				so = marks[i];
				goto mnext;
			}
			mark(marks[i]);
		}
		exits(0);
	}

	guiinit();
	einit(Emouse|Ekeyboard|Ewait);
	initwait();

	srand(time(0));

	nabove = 0;
	nbelow = 0;
	oplaying = Onone;

	mkgui();

	but = 0;
	update = 0;
	if(0) {
		random = 1;
		play(Oroot);
	}

	for(;;) {
		etype = eread(Emouse|Ekeyboard|Ewait, &ev);
		if(etype & Emouse) {
			but = ev.mouse.buttons;
			guimouse(ev.mouse);
		}
		if(etype & Ekeyboard) {
			if(resetline) {
				resetline = 0;
				if(ev.kbdc != ' ' && ev.kbdc != '\b' && ev.kbdc != '\n')
					guikbd('U'-'@');
			}
			guikbd(ev.kbdc);
		}
		if(etype & Ewait) {
			if(songstopped(ev.data))
				firstsong();
		}
		if(update && !but) {
			guiupdate(update);
			update = 0;
		}
	}
}

int
openmark(char *suffix)
{
	char file[200];
	int f;

	snprint(file, sizeof(file), markfile, suffix);
	f = open(file, OWRITE);
	if(f < 0)
		f = create(file, OWRITE, 0666);
	if(f < 0) {
		markfile[0] = 0;
		return f;
	}
	seek(f, 0, 2);
	return f;
}

void
initwait(void)
{
	int f;
	char buf[20];

	sprint(buf, "/proc/%d/wait", getpid());
	f = open(buf, OREAD);
	if(f < 0) {
		print("cant open %s %r", buf);
		exits("wait");
	}
        estart(Ewait, f, sizeof(Waitmsg));
}

void
expand(long o, int shuf)
{
	int i;
	long o1;

	update |= Dselect;
	nbelow = 0;

	if(shuf) {
		i = nabove - abovdisp - 1;
		if(i >= 0 && i < nabove) {
			o1 = above[i];
			for(i++; i<nabove; i++)
				above[i-1] = above[i];
			above[nabove-1] = o1;
		}
		for(i=0; i<nabove; i++)
			if(above[i] == o)
				break;
		if(i >= nabove && nabove >= nelem(above))
			i = 0;
		if(i < nabove) {
			for(i++; i<nabove; i++)
				above[i-1] = above[i];
		} else
			nabove++;
		above[nabove-1] = o;
		abovdisp = 0;
	}

	if(isoplaying(o))
		o = oplaying;
	if(isospecial(o)) {
		if(dosearch(o) || doqueue(o)) {
			nbelow = 0;
			for(i=0; i<nsearch; i++)
				if(nbelow < nelem(below))
					below[nbelow++] = search[i];
			return;
		}
		return;
	}

	nbelow = get2(bin, get4(bin, o));
	if(nbelow >= nelem(below))
		nbelow = nelem(below);
	for(i=0; i<nbelow; i++) {
		below[i] = Iseek(bin, 0, 1);
		get4(bin, 0);
		get4(bin, 0);
		gets(bin, 0);
	}
}

void
donowplay(void)
{
	long o;
	int n;

	strcpy(nowplaying, "");
	if(!isonone(oplaying))
		snprint(nowplaying, sizeof(nowplaying), "%d. %s", nqueue+1, tstring(oplaying));
	n = nabove - abovdisp - 1;
	if(n >= 0 && n < nabove) {
		o = above[n];
		if(isoplaying(o) || isoqueue(o))
			expand(o, 1);
	}
	update |= Dcursong;
}

void
firstsong(void)
{
	int n;

	if(nqueue == 0) {
		oplaying = Onone;
		donowplay();
		return;
	}

	n = 0;
	if(random)
		n = nrand(nqueue);

	oplaying = queue[n];
	nqueue--;
	memmove(&queue[n], &queue[n+1], (nqueue-n)*sizeof(queue[0]));

	donowplay();
	gets(bin, oplaying+8);		// position to path
	playsong(rootbin, rootaudio, gets(bin, 0));
}

void
play1(long o)
{
	int i, n;
	long m;

	if(isoplaying(o))
		o = oplaying;
	if(isospecial(o)) {
		if(dosearch(o)) {
			for(i=0; i<nsearch; i++) {
				m = search[i];
				if(m != o-1)
					play1(m);
			}
		}
		return;
	}

	o = get4(bin, o+4);
	n = get2(bin, o);

	for(i=0; i<n; i++) {
		o = get4(bin, 0);
		if(nqueue >= nelem(queue)) {
			nqueue++;
			if(random && nrand(nqueue) < nelem(queue))
				queue[nrand(nelem(queue))] = o;
		} else
			queue[nqueue++] = o;
	}
}

void
play(long o)
{

	if(now)
		skipsong(1);

	play1(o);
	if(nqueue > nelem(queue))
		nqueue = nelem(queue);

	if(isonone(oplaying))
		firstsong();
	else
		donowplay();
}

char*
scond(char *s, char *t)
{
	int n;

	n = strlen(t);
	if(memcmp(s, t, n) != 0)
		return 0;
	s += n;
	while(*s == ' ')
		s++;
	if(*s == 0)
		return 0;
	return s;

//	for(t=s; *t; t++)
//		if(*t < '0' || *t > '9')
//			return s;
//	return 0;
}

void
mmap(int f, long o)
{
	int n, i, p, any;
	char *s, *t;
	long m;

	n = get2(bin, o);
	for(p=0; p<4; p++) {
		any = 0;
		m = o+10;
		for(i=0; i<n; i++) {
			s = gets(bin, m);
			m = Iseek(bin, 0, 1) + 8;
			switch(p) {
			case 0:	/* look for title */
				if(t = scond(s, "title")) {
					if(any)
						fprint(f, "	title: %s\n", t);
					else
						fprint(f, "title: %s\n", t);
					any++;
				}
				break;
			case 1:	/* look for artists */
				if(t = scond(s, "artist")) {
					fprint(f, "	artist: %s\n", t);
					any++;
				}
				break;
			case 2:	/* look for other */
				if(t = scond(s, "class")) {
					fprint(f, "	class: %s\n", t);
					any++;
				}
				break;
			case 3:	/* look for path */
				if(t = scond(s, "path")) {
					fprint(f, "	file: %s\n", t);
					any++;
				}
				break;
			}
		}
		if(p == 3 && !any)
			fprint(f, "	file: none\n");
	}
}

void
mark(long o)
{
	int i, n, f;
	long m;

	if(markfile[0] == 0)
		return;

	if(isoplaying(o))
		o = oplaying;
	if(isospecial(o)) {
		if(dosearch(o)) {
			for(i=0; i<nsearch; i++) {
				m = search[i];
				if(m != o-1)
					mark(m);
			}
		}
		return;
	}

	o = get4(bin, o+4);
	n = get2(bin, o);
	o += 2;

	f = openmark("def");
	if(f < 0)
		return;

	for(i=0; i<n; i++) {
		m = get4(bin, o);
		o += 4;
		mmap(f, get4(bin, m));
	}
	close(f);
}

void
skipsong(int flag)
{

	if(flag)	/* stop/skip */
		nqueue = 0;
	stopsong();
}

void
doexit(void)
{
	skipsong(1);
	exits(0);
}

char*
tstring(long o)
{

	if(isospecial(o)) {
		if(isomissing(o))
			return "missing>";
		if(isoplaying(o))
			return "playing>";
		if(isoqueue(o))
			return queuename(o);
		if(isosearch(o))
			return searchname(o);
		return "";
	}
	return gets(bin, o+8);
}

typedef	struct	Head	Head;
struct	Head
{
	int	m;
	long	o;
	long	h;
};

int
wcmp(void *a1, void *a2)
{
	Head *h1, *h2;

	h1 = a1;
	h2 = a2;
	return h1->m - h2->m;
}

void
lookup(char *s, long so)
{
	Head w[10];
	long o, h, h0;
	int i, n, m, c, nskip;
	char *p;


	nsearch = 0;
	if(s == 0)
		return;

	i = (so - Osearch) % Npage;	// page number
	nskip = i * (Pagesize-2);
	if(i > 0) {
		nskip++;
		search[nsearch++] = so-1;
	}

	for(n=0; n<nelem(w); n++) {
		while(*s == ' ')
			s++;
		if(*s == 0)
			break;
		for(p=s; *p != ' ' && *p != 0; p++)
			;
		c = *p;
		*p = 0;
		o = bsearch(s);
		*p = c;
		if(o == 0)
			goto out;
		w[n].m = get2(bin, o);
		w[n].h = 0;
		w[n].o = o+2;
		s = p;
	}
	if(n <= 0)
		goto out;
	qsort(w, n, sizeof(w[0]), wcmp);
	h0 = 1;

loop:
	for(i=0; i<n; i++) {
		h = w[i].h;
		if(h0 > h) {
			m = w[i].m;
			o = w[i].o;
			while(h0 > h) {
				m--;
				if(m < 0)
					goto out;
				h = get4(bin, o);
				o += 4;
			}
			w[i].m = m;
			w[i].o = o;
			w[i].h = h;
		}
		if(h0 < h) {
			h0 = h;
			goto loop;
		}
	}
	if(nskip > 0) {
		nskip--;
		h0++;
		goto loop;
	}

	if(nsearch >= nelem(search)) {
		search[nelem(search)-1] = so+1;
		goto out;
	}
	search[nsearch++] = h0;
	h0++;
	goto loop;

out:;
}

int
doqueue(long o)
{
	int i, nskip;

	nsearch = 0;
	if(!isoqueue(o))
		return 0;

	i = (o - Oqueue);		// page number
	nskip = i * (Pagesize-2);
	if(i > 0) {
		nskip++;
		search[nsearch++] = o-1;
	}

	if(!isonone(oplaying)) {
		if(nskip > 0)
			nskip--;
		else
			search[nsearch++] = oplaying;
	}
	for(i=0; i<nqueue; i++) {
		if(nsearch >= nelem(search)) {
			search[nelem(marks)-1] = o+1;
			goto out;
		}
		if(nskip > 0) {
			nskip--;
			continue;
		}
		search[nsearch++] = queue[i];
	}
out:;
	return 1;
}


int
dosearch(long o)
{
	char *s;
	int i;

	if(!isosearch(o))
		return 0;

	i = (o - Osearch) / Npage;	// search number
	s = searches[i];
	if(s == nil)
		return 0;
	if(s[0] == '.') {
		readmark((s[1]==0)? "def": s+1, o);
		for(i=0; i<nmark; i++)
			search[i] = marks[i];
		nsearch = nmark;
		return 1;
	}
	lookup(s, o);
	return 1;
}

char*
queuename(long o)
{
	char *s;
	int i;

	i = (o - Oqueue);		// search number
	s = gets(bin, Oroot+8);		// just to get static buffer
	sprint(s, "queue.%d>", i);
	return s;
}

char*
searchname(long o)
{
	char *s;
	int i;

	i = (o - Osearch) / Npage;	// search number
	s = searches[i];
	if(s == nil)
		return "gok";
	s = gets(bin, Oroot+8);		// just to get static buffer
	sprint(s, "%s.%ld>", searches[i], (o - Osearch) % Npage);
	return s;
}

void
execute(char *s)
{
	int i;

	i = searchno % Nsearch;
	if(searches[i])
		free(searches[i]);
	searches[i] = strdup(s);
	searchno++;
	expand(Osearch + i*Npage, 1);
}

int
getc(Fio *f)
{
	int c, n;

	if(f->p >= f->ep) {
		n = read(f->f, f->buf, sizeof(f->buf));
		if(n <= 0)
			return -1;
		f->p = f->buf;
		f->ep = f->p + n;
	}
	c = *f->p & 0xff;
	f->p++;
	return c;
}

void
readmark(char *suffix, long so)
{
	int c, i, nskip;
	Fio f;
	char file[200];

	nmark = 0;
	if(markfile[0] == 0)
		return;
	snprint(file, sizeof(file), markfile, suffix);
	f.f = open(file, OREAD);
	if(f.f < 0)
		return;

	i = (so - Osearch) % Npage;	// page number
	nskip = i * (Pagesize-2);
	if(i > 0) {
		nskip++;
		marks[nmark++] = so-1;
	}
	f.p = 0;
	f.ep = 0;

	c = 0;

l0:
	while(c != 'f') {
		if(c < 0)
			goto out;
		c = getc(&f);
	}
	for(i=0; i<4; i++) {
		c = getc(&f);
		if(c != "ile:"[i])
			goto l0;
	}

	i = 0;
	for(;;) {
		c = getc(&f);
		if(c < 0)
			goto out;
		if(c == ' ' || c == '\t')
			continue;
		if(c == '\n')
			break;
		file[i] = c;
		if(i < nelem(file)-5)
			i++;
	}
	if(nskip > 0) {
		nskip--;
		goto l0;
	}
	file[i] = 0;
	lookup(file, Osearch);
	if(nsearch == 0 && nmark < nelem(marks))
		marks[nmark++] = Omissing;		// shouldnt happen
	for(i=0; i<nsearch; i++) {
		if(nmark >= nelem(marks)) {
			marks[nelem(marks)-1] = so+1;
			goto out;
		}
		marks[nmark++] = search[i];
	}
	goto l0;

out:
	close(f.f);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@plan9.bell-labs.com.