commit 90ec56c54528056b5caa8b4ee98f11751063d94e
parent 5fc65fa54283cee6b1fc844c14cd22cedb23c2c3
Author: rpa <rpa@laika>
Date: Mon, 6 Feb 2023 00:19:55 +0000
wave/track: refactor cli
Diffstat:
M | src/wave/track.c | | | 406 | +++++++++++++++++++++++++++++++++++++------------------------------------------ |
1 file changed, 192 insertions(+), 214 deletions(-)
diff --git a/src/wave/track.c b/src/wave/track.c
@@ -8,10 +8,11 @@
enum {
Octave = 12,
+ MaxWT = 16,
MaxPattern = 128,
PatternLength = 64,
SeqLength = 256,
- ChanMax = 8,
+ ChanMax = 16,
BufSize = 256,
OutSize = 1024,
WTBufSize = sizeof(s16int) * WTSize * WFSize,
@@ -21,38 +22,49 @@ enum {
NoteErr = 0xff,
};
+typedef struct Track Track;
+typedef struct Editor Editor;
typedef struct Sequence Sequence;
-typedef struct Pattern Pattern;
+typedef struct SeqChan SeqChan;
typedef struct Step Step;
typedef struct Synthctl Synthctl;
struct Step {
uchar note;
uchar volume;
- s16int cmd[3];
+ u16int cmd[3];
};
-struct Pattern {
- int length;
- Step *chan[ChanMax];
+struct Sequence {
+ int cn;
+ int n;
+ SeqChan *chan;
};
-struct Sequence {
- int chn;
- int len;
+struct SeqChan {
+ // options such as volume, pan
int *p;
};
+struct Track {
+ int bpm, spb, tps;
+ s16int *wt[MaxWT];
+ Step ptrn[MaxPattern][PatternLength];
+ Sequence seq;
+};
+
+struct Editor {
+ int pattern;
+ int channel;
+};
+
struct Synthctl {
int play;
- int pattern;
int PC;
Synth synth;
Phasor phasor;
};
-Step pattern[MaxPattern][PatternLength];
-
char *notestr[Octave] = {
"C-", "C#", "D-", "D#", "E-",
"F-", "F#", "G-", "G#", "A-",
@@ -61,34 +73,36 @@ char *notestr[Octave] = {
int n;
char cbuf[BufSize], *args[64];
-s16int *wt;
+
Synthctl sctl;
-Sequence seq;
+Track track;
+Editor editor;
-void usage(void);
-void trackedit(void);
-void loadwt(char *);
-void patternedit(char *);
-void printpattern(Step *);
char * note2str(int);
-void patternset(Step *, int, char **);
int str2note(char *);
+void repl(void);
void threadsynth(void *);
-void seqedit(void);
+void usage(void);
void
threadmain(int argc, char **argv)
{
+ track.bpm = 120;
+ track.spb = 4;
+ track.tps = 3;
+ track.wt[0] = sbrk(WTBufSize);
+ memset(track.wt[0], 0, WTBufSize);
+ sctl.synth.table[0] = track.wt[0];
+ sctl.synth.mod.wtsel = 0;
+
ARGBEGIN{
default:
usage();
} ARGEND;
- wt = sbrk(WTBufSize);
- memset(wt, 0, WTBufSize);
- sctl.synth.table[0] = wt;
- sctl.synth.mod.wtsel = 0;
+ if (argc > 1) usage();
+
proccreate(threadsynth, &sctl, 64 * 1024);
- trackedit();
+ repl();
threadexitsall(nil);
}
@@ -99,127 +113,6 @@ usage(void)
threadexitsall("usage");
}
-void
-trackedit(void)
-{
- char *ps = "% ";
- memset(cbuf, 0, BufSize);
- print("%s", ps);
- while (read(0, cbuf, BufSize) > 0) {
- n = tokenize(cbuf, args, 64);
- if (n != 0) switch (args[0][0]) {
- case 's':
- if (n != 1) goto err;
- seqedit();
- break;
- case 'p':
- if (n != 2) goto err;
- patternedit(args[1]);
- break;
- case 't':
- if (n != 2) goto err;
- else loadwt(args[1]);
- break;
- case 'h':
- print("(h)elp, (q)uit, wave(t)able, (p)attern, (s)equence\n");
- break;
- case 'q':
- return;
- case 'P':
- sctl.PC = 0;
- sctl.play = 1;
- break;
- case 'S':
- sctl.play = 0;
- sctl.PC = 0;
- break;
- default:
- err:
- print("?\n");
- }
- print("%s", ps);
- memset(cbuf, 0, BufSize);
- }
-}
-
-void
-loadwt(char *path)
-{
- int fd;
- memset(wt, 0, WTBufSize);
- fd = open(path, OREAD);
- if (fd < 0) {
- fprint(2, "%r\n");
- return;
- }
- read(fd, wt, WTBufSize);
- close(fd);
- print("ok\n");
-}
-
-void
-patternedit(char *arg)
-{
- long l;
- Step *ptrn;
- char *p;
- char *ps = "p% ";
- l = strtol(arg, &p, 16);
- if (p == arg) {
- print("?\n");
- return;
- }
- if ((l < 0) || (l >= MaxPattern)) {
- print("?\n");
- return;
- }
- ptrn = pattern[l];
- memset(cbuf, 0, BufSize);
- print("%s", ps);
- while (read(0, cbuf, BufSize) > 0) {
- n = tokenize(cbuf, args, 64);
- if (n != 0) switch(args[0][0]) {
- case 'p':
- printpattern(ptrn);
- break;
- case 'h':
- print("(p)rint, (h)elp, (q)uit\n");
- break;
- case 'q':
- return;
- case 'P':
- sctl.PC = 0;
- sctl.play = 1;
- break;
- case 'S':
- sctl.play = 0;
- sctl.PC = 0;
- break;
- default:
- if (n == 1) goto err;
- patternset(ptrn, n, args);
- break;
- err:
- print("?\n");
- }
- print("%s", ps);
- memset(cbuf, 0, BufSize);
- }
-}
-
-void
-printpattern(Step *ptrn)
-{
- int i;
- for (i = 0; i < PatternLength; i++) {
- print("%02uhhx: %s ", i, note2str(ptrn[i].note));
- if (ptrn[i].volume == 0) print(".. - ");
- else print("%02uhhX - ", ptrn[i].volume -1);
- print("%04uhX %04uhX %04uhX\n",
- ptrn[i].cmd[0], ptrn[i].cmd[1], ptrn[i].cmd[2]);
- }
-}
-
char *
note2str(int note)
{
@@ -234,53 +127,6 @@ note2str(int note)
return buf;
}
-void
-patternset(Step *ptrn, int n, char **args)
-{
- long l;
- int i, a, note;
- char *p;
-
- /* Address */
- l = strtol(args[0], &p, 16);
- if (p == args[0]) goto err;
- if ((l < 0) || (l >= PatternLength)) goto err;
- a = l;
-
- /* Note */
- args++, n--;
- if (n <= 0) goto err;
- if (strcmp(args[0], "-") != 0) {
- note = str2note(args[0]);
- if (note == NoteErr) goto err;
- ptrn[a].note = note;
- }
-
- /* Volume */
- args++, n--;
- if (n <= 0) return;
- if (strcmp(args[0], "-") != 0) {
- if (strcmp(args[0], "..") == 0) l = 0;
- else {
- l = strtol(args[0], &p, 16) + 1;
- if (p == args[0]) goto err;
- }
- if ((l < 0) || (l > 0x80)) goto err;
- ptrn[a].volume = l;
- }
- for (i = 0; i < 3; i++) {
- args++, n--;
- if (n <= 0) return;
- if (strcmp(args[0], "-") == 0) continue;
- l = strtol(args[0], &p, 16);
- if (p == args[0]) goto err;
- ptrn[a].cmd[i] = l;
- }
- return;
- err:
- print("?\n");
-}
-
int
str2note(char *str)
{
@@ -325,7 +171,7 @@ threadsynth(void *v)
if (sctl->play != 0) {
if (k >= 44100 / (12)) {
- Step s = pattern[sctl->pattern][sctl->PC];
+ Step s = track.ptrn[0][sctl->PC];
switch(s.note) {
case NoteOff:
sctl->synth.mod.freq = 0;
@@ -349,33 +195,165 @@ threadsynth(void *v)
}
}
+struct Dict {
+ char *name;
+ char *help;
+ void (*func)(int n, char **args);
+};
+
+void wrd_exit(int, char **);
+void wrd_help(int, char **);
+void wrd_play(int, char **);
+void wrd_printpattern(int, char **);
+void wrd_stop(int, char **);
+void wrd_storestep(int, char **);
+void wrd_wtload(int, char **);
+
+struct Dict dict[] = {
+ {"exit", " - leave program", wrd_exit},
+ {"help", " - print help", wrd_help},
+ {"play", nil, wrd_play},
+ {"pp", " - print pattern", wrd_printpattern},
+ {"ss", " step_n note [vol] [cmd1] [cmd2] [cmd3] - store step data", wrd_storestep},
+ {"stop", nil, wrd_stop},
+ {"wtload", " path - load wavetable", wrd_wtload},
+ {nil, nil, nil},
+};
+
void
-seqedit(void)
+repl(void)
{
- char *ps = "s% ";
+ int i;
+ char *ps = "% ";
+
memset(cbuf, 0, BufSize);
+ args[0] = cbuf;
print("%s", ps);
while (read(0, cbuf, BufSize) > 0) {
n = tokenize(cbuf, args, 64);
- if (n != 0) switch (args[0][0]) {
- case 'h':
- print("(h)elp, (q)uit\n");
- break;
- case 'q':
- return;
- case 'P':
- sctl.PC = 0;
- sctl.play = 1;
- break;
- case 'S':
- sctl.play = 0;
- sctl.PC = 0;
- break;
- default:
- err:
- print("?\n");
+ for (i = 0; dict[i].name != nil; i++) {
+ if (strcmp(dict[i].name, args[0]) == 0) {
+ dict[i].func(n, args);
+ break;
+ }
}
+ if (dict[i].name == nil) print("?\n");
print("%s", ps);
memset(cbuf, 0, BufSize);
}
}
+
+void
+wrd_help(int, char **)
+{
+ int i;
+ for (i = 0; dict[i].name != nil; i++) {
+ print("%s", dict[i].name);
+ if (dict[i].help != nil) print("%s", dict[i].help);
+ print("\n");
+ }
+}
+
+void
+wrd_exit(int, char **)
+{
+ threadexitsall(nil);
+}
+
+void
+wrd_printpattern(int, char **)
+{
+ Step *ptrn = track.ptrn[editor.pattern];
+
+ int i;
+ print("Pattern %02uhhx:\n", editor.pattern);
+ for (i = 0; i < PatternLength; i++) {
+ print("%02uhhx: %s ", i, note2str(ptrn[i].note));
+ if (ptrn[i].volume == 0) print(".. - ");
+ else print("%02uhhX - ", ptrn[i].volume - 1);
+ print("%04uhX %04uhX %04uhX\n",
+ ptrn[i].cmd[0], ptrn[i].cmd[1], ptrn[i].cmd[2]);
+ }
+}
+
+void
+wrd_wtload(int n, char **args)
+{
+ if (n != 2) {
+ print("?\n");
+ return;
+ }
+ char *path = args[1];
+ int fd;
+ memset(track.wt[0], 0, WTBufSize);
+ fd = open(path, OREAD);
+ if (fd < 0) {
+ fprint(2, "%r\n");
+ print("?\n");
+ return;
+ }
+ read(fd, track.wt[0], WTBufSize);
+ close(fd);
+ print("ok\n");
+}
+
+void wrd_play(int, char **)
+{
+ sctl.play = 1;
+}
+
+void wrd_stop(int, char **)
+{
+ sctl.play = 0;
+ sctl.PC = 0;
+}
+
+void
+wrd_storestep(int n, char **args)
+{
+ long l;
+ int i, a, note;
+ char *p;
+ Step *ptrn = track.ptrn[editor.pattern];
+
+ /* Address */
+ args++, n--;
+ if (n <= 0) goto err;
+ l = strtol(args[0], &p, 16);
+ if (p == args[0]) goto err;
+ if ((l < 0) || (l >= PatternLength)) goto err;
+ a = l;
+
+ /* Note */
+ args++, n--;
+ if (n <= 0) goto err;
+ if (strcmp(args[0], "-") != 0) {
+ note = str2note(args[0]);
+ if (note == NoteErr) goto err;
+ ptrn[a].note = note;
+ }
+
+ /* Volume */
+ args++, n--;
+ if (n <= 0) return;
+ if (strcmp(args[0], "-") != 0) {
+ if (strcmp(args[0], "..") == 0) l = 0;
+ else {
+ l = strtol(args[0], &p, 16) + 1;
+ if (p == args[0]) goto err;
+ }
+ if ((l < 0) || (l > 0x80)) goto err;
+ ptrn[a].volume = l;
+ }
+ for (i = 0; i < 3; i++) {
+ args++, n--;
+ if (n <= 0) return;
+ if (strcmp(args[0], "-") == 0) continue;
+ l = strtol(args[0], &p, 16);
+ if (p == args[0]) goto err;
+ ptrn[a].cmd[i] = l;
+ }
+ return;
+ err:
+ print("?\n");
+}