shithub: neindaw

Download patch

ref: d397b794326c17d9404d2d420461659014852d89
parent: 757dd96b3f01b987bcbeb088b7527a65111b30f2
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Feb 26 19:23:30 EST 2020

ay38910: implement fs tree, no reg writes/reads yet though

--- a/ay38910/ay38910.c
+++ b/ay38910/ay38910.c
@@ -1,18 +1,30 @@
 #include <u.h>
 #include <libc.h>
+#include <fcall.h>
 #include <thread.h>
-#include <libsec.h>
-#include <draw.h>
-#include <keyboard.h>
+#include <9p.h>
+#include "common.h"
+#include "aux.h"
 #define CHIPS_IMPL
 #define CHIPS_ASSERT assert
 #include "ay38910.h"
+#include "uiglue.h"
 
+/*
+FIXME just a note, remove later
+	ay = aynew(1.0);
+	amp(ay, 0, Levelenv | 4);
+	envp(ay, ms2ep(500));
+	envsc(ay, Continue|Attack);
+	toneon(ay, 0);
+	tone(ay, 0, 500);
+*/
+
 #define MIN(a,b) ((a)<=(b)?(a):(b))
 #define MAX(a,b) ((a)>=(b)?(a):(b))
 
 enum {
-	Tickhz = 2000000,
+	Tickhz = 1000000,
 
 	Levelenv = 1<<4,
 
@@ -22,6 +34,33 @@
 	Continue = 1<<3,
 };
 
+struct Auxdsp {
+	ay38910_t ay;
+	struct {
+		float freq;
+		float amp;
+		float envelope;
+		float noise;
+		float enable;
+	}chan[3];
+	float hold, alternate, attack, cont;
+	float volume;
+};
+
+static Aux rootaux[] = {
+	[Xctl] = {.type = Xctl},
+	[Xmetadata] = {.type = Xmetadata},
+	[Xclone] = {.type = Xclone},
+};
+
+extern Srv fs;
+
+static int rate = 44100;
+static Aux *objs[32];
+static char *meta =
+	"name\tAY-3-8910\n"
+	"group\tSynthesis\n";
+
 static void
 regw(ay38910_t *ay, int reg, int v)
 {
@@ -120,74 +159,291 @@
 	regw(ay, AY38910_REG_AMP_A+chan, level);
 }
 
-static ay38910_t *
-aynew(float mag)
+static void *
+auxtype2obj(int *type)
 {
+	switch (*type) {
+	case Xdspctl:
+	case Xuictl:
+		return (uchar*)type - offsetof(Aux, ctl);
+	case Xdspdata:
+		return (uchar*)type - offsetof(Aux, data);
+	case Xuimeta:
+		return (uchar*)type - offsetof(Aux, metadata);
+	default:
+		sysfatal("trying to get aux out of type %d", *type);
+	}
+
+	return nil;
+}
+
+static void
+buildui(Auxdsp *dsp, UIGlue *ui)
+{
+	float min, step, max;
+	char s[32];
+	int i;
+
+	min = ceil(Tickhz/(16.0f*4095.0f));
+	max = floor(Tickhz/16.0f);
+	step = ceil(Tickhz/(16.0f*4094.0f)) - min;
+
+	ui->openVerticalBox(ui->f, "AY-3-8910");
+
+	ui->openVerticalBox(ui->f, "Tone");
+	for (i = 0; i < 1; i++) {
+		sprint(s, "%c", 'A'+i);
+		ui->openVerticalBox(ui->f, s);
+
+		ui->declare(ui->f, &dsp->chan[i].freq, "0", "");
+		ui->declare(ui->f, &dsp->chan[i].freq, "unit", "Hz");
+		ui->addHorizontalSlider(ui->f, "Tone", &dsp->chan[i].freq, 400.0f, min, max, step);
+
+		ui->declare(ui->f, &dsp->chan[i].amp, "1", "");
+		ui->addHorizontalSlider(ui->f, "Volume", &dsp->chan[i].amp, 15.0f, 0.0f, 15.0f, 1.0f);
+
+		ui->declare(ui->f, &dsp->chan[i].enable, "2", "");
+		ui->addCheckButton(ui->f, "Enable", &dsp->chan[i].enable);
+
+		ui->declare(ui->f, &dsp->chan[i].envelope, "3", "");
+		ui->addCheckButton(ui->f, "Envelope", &dsp->chan[i].envelope);
+
+		ui->declare(ui->f, &dsp->chan[i].noise, "4", "");
+		ui->addCheckButton(ui->f, "Noise", &dsp->chan[i].noise);
+
+		ui->closeBox(ui->f);
+	}
+	ui->closeBox(ui->f);
+
+	ui->openVerticalBox(ui->f, "Envelope");
+	ui->declare(ui->f, &dsp->hold, "0", "");
+	ui->addCheckButton(ui->f, "Hold", &dsp->hold);
+	ui->declare(ui->f, &dsp->alternate, "1", "");
+	ui->addCheckButton(ui->f, "Alternate", &dsp->alternate);
+	ui->declare(ui->f, &dsp->attack, "2", "");
+	ui->addCheckButton(ui->f, "Attack", &dsp->attack);
+	ui->declare(ui->f, &dsp->cont, "3", "");
+	ui->addCheckButton(ui->f, "Continue", &dsp->cont);
+	ui->closeBox(ui->f);
+
+	ui->addHorizontalSlider(ui->f, "Volume", &dsp->volume, 1.0f, 0.0f, 1.0f, 0.001f);
+
+	ui->closeBox(ui->f);
+}
+
+static Aux *
+newobj(char *name)
+{
+	File *f;
+	Aux *o;
+	Auxdsp *dsp;
+	int i;
 	ay38910_desc_t d = {
 		.type = AY38910_TYPE_8910,
 		.tick_hz = Tickhz,
-		.sound_hz = 44100,
-		.magnitude = mag,
+		.sound_hz = rate,
+		.magnitude = 1.0,
 	};
-	ay38910_t *ay;
 
-	ay = malloc(sizeof(*ay));
-	ay38910_init(ay, &d);
-	regw(ay, AY38910_REG_ENABLE, 0xff); /* disable everything */
+	for (i = 0, o = nil; o == nil && i < nelem(objs); i++) {
+		if (objs[i] == nil){
+			o = objs[i] = calloc(1, sizeof(*o)+sizeof(Auxdsp));
+			break;
+		}
+	}
+	if (o == nil)
+		return nil;
 
-	return ay;
-}
+	o->id = i;
+	o->type = Xdsp;
+	o->ctl = Xdspctl;
+	o->data = Xdspdata;
+	o->dsp = dsp = (Auxdsp*)(o+1);
+	ay38910_init(&dsp->ay, &d);
+	regw(&dsp->ay, AY38910_REG_ENABLE, 0xff); /* disable everything */
 
-void
-threadmain(int argc, char **argv)
-{
-	u64int tick;
-	ay38910_t *ay[2];
-	int i, base, diff[] = {20, 200, 40, 220, 60};
-	float f[2], x;
-	bool havesample[2];
+	sprint(name, "%d", o->id);
+	if ((f = createfile(fs.tree->root, name, nil, DMDIR|0775, o)) == nil)
+		return nil;
+	closefile(createfile(f, "ctl", nil, 0664, &o->ctl));
+	closefile(createfile(f, "data", nil, 0664, &o->data));
+	closefile(f);
 
-	USED(argc); USED(argv);
+	uiglue.f = f;
+	buildui(dsp, &uiglue);
 
-	ay[0] = aynew(1.0);
-	amp(ay[0], 0, Levelenv | 4);
-	envp(ay[0], ms2ep(200));
-	envsc(ay[0], Continue|Alternate);
-	toneon(ay[0], 0);
+	return o;
+}
 
-	ay[1] = aynew(1.0);
-	amp(ay[1], 0, Levelenv | 4);
-	envp(ay[1], ms2ep(500));
-	envsc(ay[1], Continue|Attack);
-	toneon(ay[1], 0);
-	tone(ay[1], 0, 500);
+static void
+fsopen(Req *r)
+{
+	respond(r, nil);
+}
 
-	base = 200;
-	for (i = 0, tick = 0;; tick++) {
-		/* 100Hz */
-		if ((tick % (Tickhz / 100)) == 0) {
-			if (i >= nelem(diff))
-				i = 0;
-			tone(ay[0], 0, base+diff[i++]);
-		}
+static void
+fsread(Req *r)
+{
+	Aux *a, *o;
+	Auxdsp *dsp;
+	char b[256];
+	float *p;
+	int n;
 
-		if (!havesample[0] && ay38910_tick(ay[0])) {
-			f[0] = ay[0]->sample;
-			havesample[0] = true;
-		}
-		if (!havesample[1] && ay38910_tick(ay[1])) {
-			f[1] = ay[1]->sample;
-			havesample[1] = true;
-		}
-		if (havesample[0] && havesample[1]) {
-			havesample[0] = havesample[1] = false;
-			x = f[0] + f[1];
-			if (write(1, &x, sizeof(x)) < 0) 
+	a = r->fid->file->aux;
+	switch (a->type) {
+	case Xctl:
+		respond(r, nil);
+		break;
+	case Xmetadata:
+		readstr(r, meta);
+		respond(r, nil);
+		break;
+	case Xclone:
+		if (r->ifcall.offset == 0) {
+			if (newobj(b) != nil) {
+				readstr(r, b);
+			} else {
+				snprint(b, sizeof(b), "no free objects: %r");
+				respond(r, b);
 				break;
+			}
 		}
+		respond(r, nil);
+		break;
+	case Xuictl:
+	case Xuimeta:
+		o = auxtype2obj(&a->type);
+		if (o->ui->readstr != nil)
+			readstr(r, o->ui->readstr(o->ui, a->type, b, sizeof(b)));
+		respond(r, nil);
+		break;
+	case Xdspdata:
+		o = auxtype2obj(&a->type);
+		dsp = o->dsp;
+		n = r->ifcall.count;
+		for (p = (float*)r->ofcall.data; n >= sizeof(float); p++) {
+			while (!ay38910_tick(&dsp->ay));
+			*p = dsp->ay.sample;
+			n -= sizeof(float);
+		}
+		r->ofcall.count = r->ifcall.count - n;
+		respond(r, nil);
+		break;
+	default:
+		respond(r, "not implemented");
+		break;
 	}
+}
 
-	free(ay[0]);
-	free(ay[1]);
-	threadexitsall(nil);
+static void
+fswrite(Req *r)
+{
+	Aux *a, *o;
+	char b[256];
+	int st;
+
+	if (r->ifcall.count >= sizeof(b)) {
+		respond(r, "can't fit into buffer");
+		return;
+	}
+
+	memmove(b, r->ifcall.data, r->ifcall.count);
+	b[r->ifcall.count] = '\0';
+	r->ofcall.count = r->ifcall.count;
+
+	a = r->fid->file->aux;
+	switch (a->type) {
+	case Xuictl:
+		o = auxtype2obj(&a->type);
+		st = o->ui->write != nil ? o->ui->write(o->ui, a->type, b) : -1;
+		respond(r, st == 0 ? nil : "write failed");
+		break;
+	case Xdspctl: /* FIXME changing sampling rate */
+		o = auxtype2obj(&a->type);
+		if (strncmp(b, "reset", 5) == 0)
+			ay38910_reset(&o->dsp->ay);
+		respond(r, nil);
+		break;
+	case Xmetadata: /* FIXME should be possible to add new key/value */
+	default:
+		respond(r, "not implemented");
+		break;
+	}
+}
+
+Srv fs = {
+	.open = fsopen,
+	.read = fsread,
+	.write = fswrite,
+};
+
+static void
+freeobj(Aux *o)
+{
+	if (o == nil)
+		return;
+
+	if (o->type == Xdsp)
+		objs[o->id] = nil;
+
+	free(o);
+}
+
+static void
+usage(void)
+{
+	print("usage: %s [-s srv] [-m mtpt] [-r rate]\n", argv0);
+	threadexitsall("usage");
+}
+
+static void
+fsdestroyfile(File *f)
+{
+	Aux *a;
+
+	if ((a = f->aux) == nil)
+		return;
+	switch (a->type) {
+	case Xdsp:
+	case Xui:
+		freeobj(a);
+		f->aux = nil;
+		break;
+	}
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	char *srv, *mtpt;
+
+	srv = nil;
+	mtpt = nil;
+	ARGBEGIN{
+	case 'D':
+		chatty9p++;
+		break;
+	case 's':
+		srv = EARGF(usage());
+		break;
+	case 'm':
+		mtpt = EARGF(usage());
+		break;
+	case 'r':
+		rate = atoi(EARGF(usage()));
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if (srv == nil && mtpt == nil)
+		sysfatal("must specify -s or -m option");
+
+	fs.tree = alloctree(nil, nil, DMDIR|0775, fsdestroyfile);
+	closefile(createfile(fs.tree->root, "ctl", nil, 0666, &rootaux[Xctl]));
+	closefile(createfile(fs.tree->root, "metadata", nil, 0444, &rootaux[Xmetadata]));
+	closefile(createfile(fs.tree->root, "clone", nil, 0444, &rootaux[Xclone]));
+	threadpostmountsrv(&fs, srv, mtpt, MREPL);
+	threadexits(nil);
 }
--- a/ay38910/mkfile
+++ b/ay38910/mkfile
@@ -1,18 +1,20 @@
 </$objtype/mkfile
 
 TARG=ay38910
-CFLAGS=$CFLAGS -p
-BIN=/$objtype/bin/audio
-MAN=/sys/man/1
+CFLAGS=$CFLAGS -p -I..
+BIN=/$objtype/bin/daw
 
-HFILES=\
-	ay38910.h\
-
 OFILES=\
 	ay38910.$O\
+	common.$O\
+	uiglue.$O\
 
 default:V:	all
 
 </sys/src/cmd/mkone
 
-install:V: $MAN/$TARG
+common.$O: ../common.c
+	$CC $CFLAGS $prereq
+
+uiglue.$O: ../uiglue.c
+	$CC $CFLAGS $prereq
--- a/mkfile
+++ b/mkfile
@@ -4,6 +4,7 @@
 	microui\
 
 CMDS=\
+	ay38910\
 	cfg\
 	dsp\
 	repeat\