commit 9e45f3b6099022e4be1da1ac19abac92f5a73c38
parent eadf2ce1fa6978a1d9e201d9b4235fa3f5bd33a3
Author: Pavel Renev <rpa@traveller.nsmpr.xyz>
Date: Thu, 12 Aug 2021 03:27:30 +0300
miditest, buildtest, program assemly, example program
miditest will send a note for one second on midithru/0
buildtest will run program from stdin and print some machine stats
usynth will accept program either as arg or from stdin
example program is replica of previously hardcoded program
Diffstat:
11 files changed, 368 insertions(+), 43 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
include config.mk
# SRC = usynth.c fm.c machine.c midi.c operator.c wavetable.c
-SRC = usynth.c midi.c machine.c wavetable.c
+SRC = midi.c machine.c wavetable.c build.c util.c
OBJ = ${SRC:.c=.o}
@@ -18,8 +18,14 @@ all: usynth
${OBJ}:
-usynth: ${OBJ}
- ${CC} -o $@ ${OBJ} ${LDFLAGS}
+usynth: $@.o ${OBJ}
+ ${CC} -o $@ $@.o ${OBJ} ${LDFLAGS}
+
+miditest: miditest.c
+ ${CC} miditest.c -o $@ -lsndio
+
+buildtest: buildtest.c ${OBJ}
+ ${CC} -o $@ buildtest.c ${OBJ} ${LDFLAGS}
wavetable.o: wavetable.h
@@ -38,6 +44,6 @@ uninstall:
${DESTDIR}${MANDIR}/usynth.1
clean:
- rm -f usynth ${OBJ}
+ rm -f usynth buildtest miditest ${OBJ}
.PHONY: all clean instal uninstall
diff --git a/build.c b/build.c
@@ -0,0 +1,202 @@
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "machine.h"
+#include "build.h"
+
+const Label builtin[] = {
+ /* memory mapping */
+ {"VM_PC", VM_PC},
+ {"VM_ACTIVE", VM_ACTIVE},
+ {"VM_HALTED", VM_HALTED},
+ {"VM_KEY", VM_KEY},
+ {"VM_KEY_ON", VM_KEY_ON},
+ {"VM_OPERATORS", VM_OPERATORS},
+ {"VM_SP", VM_SP},
+ {"VM_STACK", VM_STACK},
+ {"VM_PROG_START", VM_PROG_START},
+ {"VM_MEM_END", VM_MEM_END},
+ /* processor instructions */
+ {"halt", I_HALT},
+ {"lit", I_LIT},
+ {"fetch", I_FETCH},
+ {"op", I_OP},
+ {"adsr", I_ADSR},
+ {"wave", I_WAVE},
+ {"2dt", I_2DT},
+ {"dup", I_DUP},
+ {"drop", I_DROP},
+ {"swap", I_SWAP},
+ {"add", I_ADD},
+ {"comb", I_COMB},
+};
+
+
+void
+splittokens(char *dat, Array *tokens)
+{
+ char *sp, *p;
+ sp = dat;
+ for (p = dat; *p != '\0'; p++) {
+ if (*p == '\n') {
+ Token *tok;
+ *p = '\0';
+ p++;
+ tok = arrayinc(tokens);
+ *tok = (struct Token){*sp, sp+1};
+ sp = p;
+ }
+ }
+}
+
+void
+addwords(Array *words, char *p)
+{
+ char *w;
+ while(p != NULL) {
+ w = strsep(&p, " \t");
+ if (*w != '\0') {
+ char **n;
+ n = arrayinc(words);
+ *n = w;
+ }
+ }
+}
+
+int
+run1(Array *tokens, Array *labels, Array *words)
+{
+ struct Token *tok;
+ struct Label *l;
+ char *np, *vp, *ep;
+ int v, i;
+ for (i = 0; i < tokens->n; i++) {
+ tok = arrayget(tokens, i);
+ switch (tok->t) {
+ case '\t':
+ case ' ':
+ addwords(words, tok->p);
+ break;
+ case ':':
+ np = strsep(&tok->p, " \t");
+ vp = strsep(&tok->p, " \t");
+ if (vp != NULL) {
+ v = strtol(vp, &ep, 16);
+ if (vp == ep) {
+ fprintf(stderr, "%s?\n", vp);
+ return -1;
+ }
+ } else v = words->n + VM_PROG_START;
+ l = arrayinc(labels);
+ *l = (Label){np, v};
+ break;
+ case '\0':
+ case '#':
+ break;
+ default:
+ fprintf(stderr, "%c%s?\n",
+ tok->t, tok->p);
+ }
+ }
+ return 0;
+}
+
+Label *
+getlabel(Array *labels, char *p)
+{
+ int i;
+ Label *l;
+ for (i = 0; i < labels->n; i++) {
+ l = arrayget(labels, i);
+ if (strcmp(l->p, p) == 0) return l;
+ }
+ return NULL;
+}
+
+
+int
+run2(Array *labels, Array *words, int16_t *prog)
+{
+ int i;
+ if (words->n > VM_MEM_END - VM_PROG_START) {
+ fprintf(stderr, "not enough memory\n");
+ return -1;
+ }
+ for (i = 0; i < words->n; i++) {
+ Label *l;
+ int16_t *p;
+ char **w;
+ w = arrayget(words, i);
+ p = &prog[i + VM_PROG_START];
+ l = getlabel(labels, *w);
+ if (l != NULL) {
+ *p = l->n;
+ } else {
+ char *ep;
+ int16_t n;
+ n = strtol(*w, &ep, 16);
+ if ((*w == ep)||(*ep != '\0')) {
+ fprintf(stderr, "%s?\n", *w);
+ return -1;
+ }
+ *p = n;
+ }
+ }
+ return 0;
+}
+
+int
+build(char *dat, int16_t *prog)
+{
+ int r;
+ Array *tokens;
+ Array *labels;
+ Array *words;
+
+ r = 0;
+
+ tokens = newarray(sizeof(Token));
+ labels = newarray(sizeof(Label));
+ words = newarray(sizeof(char *));
+
+ labels->n = sizeof(builtin)/sizeof(*builtin);
+ labels->p = realloc(labels->p, sizeof(builtin));
+ memcpy(labels->p, builtin, sizeof(builtin));
+
+ splittokens(dat, tokens);
+ if ((run1(tokens, labels, words) != 0) ||
+ (run2(labels, words, prog) != 0)) {
+ fprintf(stderr, "build failed\n");
+ r = -1;
+ }
+ freearray(tokens);
+ freearray(labels);
+ freearray(words);
+ return r;
+}
+
+int
+buildfile(FILE *fp, int16_t *prog)
+{
+ char *buf, *bp;
+ size_t n, s;
+ int r;
+ s = 1024;
+ buf = malloc(s);
+ bp = buf;
+ while ((n = fread(bp, 1024, 1, fp)) > 0) {
+ s += n;
+ buf = realloc(buf, s + 1024);
+ bp = buf + s;
+ }
+ if (n < 0) {
+ fprintf(stderr, "failed to read file\n");
+ return -1;
+ }
+ r = build(buf, prog);
+ free(buf);
+ return r;
+}
diff --git a/build.h b/build.h
@@ -0,0 +1,19 @@
+typedef struct Token Token;
+struct Token {
+ int t;
+ char *p;
+};
+
+typedef struct Label Label;
+struct Label {
+ char *p;
+ uint16_t n;
+};
+
+void splittokens(char *dat, Array *tokens);
+void addwords(Array *words, char *p);
+Label * getlabel(Array *labels, char *p);
+int run1(Array *tokens, Array *labels, Array *words);
+int run2(Array *labels, Array *words, int16_t *prog);
+int build(char *dat, int16_t *prog);
+int buildfile(FILE *fp, int16_t *prog);
diff --git a/buildtest.c b/buildtest.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "wavetable.h"
+#include "machine.h"
+#include "build.h"
+
+int
+main(void)
+{
+ int i;
+ int16_t *prog;
+ wt_init();
+ prog = malloc(VM_MEM_END * sizeof(int16_t));
+ buildfile(stdin, prog);
+ prog[VM_ACTIVE] = 1;
+ prog[VM_KEY] = 100;
+ vm_run(prog);
+ printf("---\n");
+ for (i = 0; i < VM_KEY_ON+1; i++) {
+ printf("%04hx ", prog[i]);
+ };
+ printf("\n%hx: ", prog[VM_SP]);
+ for (i = VM_STACK; i < VM_STACK+prog[VM_SP]; i++) {
+ printf("%04hx ", prog[i]);
+ };
+ printf("\n");
+ return 0;
+}
diff --git a/example.prg b/example.prg
@@ -0,0 +1,6 @@
+:main
+ lit VM_KEY fetch
+ 2dt
+ op
+ wave
+ halt
diff --git a/machine.c b/machine.c
@@ -22,7 +22,6 @@ void i_fetch(int16_t*, uint8_t);
void i_op(int16_t*, uint8_t);
void i_adsr(int16_t*, uint8_t);
void i_wave(int16_t*, uint8_t);
-void i_note(int16_t*, uint8_t);
void i_2dt(int16_t*, uint8_t);
void i_dup(int16_t*, uint8_t);
void i_drop(int16_t*, uint8_t);
@@ -37,7 +36,6 @@ instruction instructions[128] = {
[I_OP] = i_op,
[I_ADSR] = i_adsr,
[I_WAVE] = i_wave,
- [I_NOTE] = i_note,
[I_2DT] = i_2dt,
[I_DUP] = i_dup,
[I_DROP] = i_drop,
@@ -46,28 +44,9 @@ instruction instructions[128] = {
[I_COMB] = i_comb,
};
-/*** simple hard-coded program ***/
-
-int16_t sprog[1024*3] = {
- I_NOTE,
- I_2DT,
- I_OP|0x0000,
- I_WAVE|0x0000,
-
- //I_NOTE,
- //I_2DT,
- //I_OP|0x0000,
- //I_WAVE|0x0000,
- //I_COMB,
- //I_ADSR|0x0000,
- //I_COMB,
- I_HALT
-};
-
void
vm_set(int16_t *vm)
{
- memcpy(vm + VM_PROG_START, sprog, 1024);
vm[VM_ACTIVE] = 0;
}
@@ -84,7 +63,7 @@ vm_run(int16_t *vm)
inst = instructions[0xff & DATA(vm)];
if (inst == 0) vm_fatal(vm, "illegal instruction");
vm[VM_PC]++;
- inst(vm, DATA(vm)>>8);
+ inst(vm, 0);
}
return TOS(vm);
}
@@ -102,7 +81,8 @@ void
vm_fatal(int16_t* vm, char *errstr)
{
dprintf(2, "int16_t FATAL: %s\n", errstr);
- dprintf(2, "pc = %d\n", vm[VM_PC]);
+ dprintf(2, "pc = %hd\n", vm[VM_PC]);
+ dprintf(2, "mem = %hd\n", vm[vm[VM_PC]]);
exit(-1);
}
@@ -116,8 +96,8 @@ void
i_lit(int16_t *vm, uint8_t arg)
{
vm[VM_SP]++;
+ TOS(vm) = vm[vm[VM_PC]];
vm[VM_PC]++;
- TOS(vm) = DATA(vm);
}
void
@@ -148,13 +128,6 @@ i_wave(int16_t *vm, uint8_t arg)
}
void
-i_note(int16_t *vm, uint8_t arg)
-{
- vm[VM_SP]++;
- TOS(vm) = vm[VM_KEY];
-}
-
-void
i_2dt(int16_t *vm, uint8_t arg)
{
uint8_t note = TOS(vm);
diff --git a/machine.h b/machine.h
@@ -7,7 +7,6 @@ enum {
I_OP,
I_ADSR,
I_WAVE,
- I_NOTE,
I_2DT,
/* * * * * */
I_DUP,
diff --git a/miditest.c b/miditest.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sndio.h>
+
+/*
+ * a simple program that sends midi NOTE ON
+ * and then NOTE OFF a second later
+ */
+
+int
+main(void)
+{
+ uint8_t msg[4];
+ char *mdev;
+ msg[0] = 0x90;
+ msg[1] = 0x10;
+ msg[2] = 127;
+ mdev = "midithru/0";
+ struct mio_hdl *mh;
+ mh = mio_open(mdev, MIO_OUT, 0);
+ if (mh == 0) {
+ fprintf(stderr, " can't open midi %s\n", mdev);
+ exit(-1);
+ }
+ mio_write(mh, msg, 3);
+ sleep(1);
+ msg[0] = 0x80;
+ mio_write(mh, msg, 3);
+ return 0;
+}
diff --git a/usynth.c b/usynth.c
@@ -5,9 +5,12 @@
#include <sndio.h>
#include <string.h>
#include <assert.h>
+
+#include "util.h"
#include "midi.h"
#include "wavetable.h"
#include "machine.h"
+#include "build.h"
struct sio_hdl *sh;
size_t bs;
@@ -40,17 +43,28 @@ s_init(char *sdev)
}
int
-main(void)
+main(int argc, char **argv)
{
+ FILE *fp;
+
+ fp = stdin;
+ if (argc == 2) {
+ fp = fopen(argv[1], "r");
+ if (fp == NULL) {
+ fprintf(stderr, "failed to open file %s\n", argv[1]);
+ exit(-1);
+ }
+ }
+
s_init("default");
wt_init();
m_init("midithru/0");
m_vector.note_on = note_on;
m_vector.note_off = note_off;
- vm = malloc(4096);
-
+ vm = malloc(VM_MEM_END);
vm_set(vm);
+ buildfile(fp, vm);
while (1){
size_t n;
@@ -63,10 +77,9 @@ main(void)
void
note_on(uint8_t *m)
{
- int i;
keystack[kp] = m[2];
kp++;
- if (kp > 32) kp = 32;
+ if (kp > 31) kp = 31;
vm[VM_ACTIVE] = 1;
vm[VM_KEY] = m[2];
vm[VM_KEY_ON] = 1;
@@ -76,9 +89,9 @@ void
note_off(uint8_t *m)
{
int i;
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < kp; i++) {
if (keystack[i] == m[2]) {
- memcpy(keystack+i, keystack+i+1, 32 - i);
+ memcpy(keystack+i, keystack+i+1, kp - i);
kp--;
}
}
diff --git a/util.c b/util.c
@@ -0,0 +1,34 @@
+#include <stdlib.h>
+
+#include "util.h"
+
+Array *
+newarray(size_t s)
+{
+ Array *a;
+ a = malloc(sizeof(Array));
+ *a = (Array){NULL, s, 0};
+ return a;
+}
+
+void
+freearray(Array *a)
+{
+ free(a->p);
+ a->p = NULL;
+ free(a);
+}
+
+void *
+arrayinc(Array *v)
+{
+ v->n++;
+ v->p = realloc(v->p, v->n * v->s);
+ return v->p + (v->n - 1) * v->s;
+}
+
+void *
+arrayget(Array *v, int n)
+{
+ return v->p + n * v->s;
+}
diff --git a/util.h b/util.h
@@ -0,0 +1,11 @@
+typedef struct Array Array;
+struct Array {
+ char *p;
+ size_t s;
+ int n;
+};
+
+Array * newarray(size_t s);
+void freearray(Array *);
+void * arrayinc(Array *v);
+void * arrayget(Array *v, int n);