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\