commit 34b341144e9e63e1ad92d5937c32cd45669d9471
parent 9cd0007204972fc84ee36857ae82e1c4eed72749
Author: rpa <rpa@laika>
Date: Mon, 12 Dec 2022 01:28:00 +0000
mu: trk improvements
Diffstat:
3 files changed, 158 insertions(+), 51 deletions(-)
diff --git a/src/mu/mubox.c b/src/mu/mubox.c
@@ -1,7 +1,10 @@
-/* simplistic audio synth,
+/*
+ Primitive audio synth
+
- 6-voice polyphony, 1 noise channel, 1 kick channel
- only triangle osc, only freq, vol and decay ctls
- - controlled via stdin */
+ - controlled via stdin
+*/
#include <u.h>
#include <libc.h>
diff --git a/src/mu/tplay b/src/mu/tplay
@@ -1,3 +1,3 @@
#!/bin/rc
rfork e
-6.trk | 6.mubox -r > /dev/audio
+6.trk $* | 6.mubox -r > /dev/audio
diff --git a/src/mu/trk.c b/src/mu/trk.c
@@ -1,72 +1,176 @@
-/* read lines from stdin and print them at specified rate */
+/*
+ Primitive sequencer / music-tracker
+
+ reads lines from stdin and prints them at controllable rate
+*/
#include <u.h>
#include <libc.h>
#include <bio.h>
typedef struct List List;
+
struct List {
void *v;
List *next;
};
-List start;
+List *list;
+char *file;
+vlong t, dt;
long bpm = 120, steps = 1;
-vlong dt;
-int
-cmd(char *s)
+List * loadlist(char *);
+void clearlist(List *);
+
+void pause(void);
+
+#define CMD(X) void X(List **, int , char **)
+CMD(cmdbpm);
+CMD(cmdpause);
+CMD(cmdjump);
+CMD(cmdret);
+CMD(cmdreload);
+
+struct Cmds {
+ char *name;
+ void (*func)(List **, int, char **);
+} cmds[] = {
+ { "#", nil }, /* comment */
+ { ".bpm", cmdbpm }, /* update bpm to new value */
+ { "----", cmdpause },
+ { ".rld", cmdreload }, /* reload file and start from the beginning */
+};
+
+void
+cmdbpm(List **, int n, char **args)
{
- if (s[0] == '.') {
- int argc; char *argv[32];
- argc = tokenize(s, argv, 32);
- if (strcmp(argv[0], ".") == 0) {
- int i;
- for (i = 0; i < argc; i++) print("%s ", argv[i]);
- print("\n");
- return 1;
- }
- if (strcmp(argv[0], ".bpm") == 0) {
- long x = 0;
- if (argc > 1) x = strtol(argv[1], nil, 10);
- if (x != 0) bpm = x;
- if (argc > 2) x = strtol(argv[2], nil, 10);
- if (x != 0) steps = x;
- dt = 60000000000 / (bpm * steps);
- return 0;
- }
- if (strcmp(argv[0], ".end") == 0) {
-
- }
- } else if (s[0] == ':') return 0;
- print("%s\n", s);
- return 0;
+ switch(n){
+ case 0: /* what */
+ case 1:
+ fprint(2, ".bpm: not enough arguments\n");
+ break;
+ default:
+ fprint(2, ".bpm: too much arguments\n");
+ case 2:
+ case 3:
+ bpm = strtol(args[1], nil, 10);
+ if (n == 3) steps = strtol(args[2], nil, 10);
+ }
+ if (bpm <= 0) {
+ fprint(2, "bpm is nonsence (%ld), restoring to 120\n", bpm);
+ bpm = 120;
+ }
+ if (steps <= 0) {
+ fprint(2, "steps is nonsence (%ld), restoring to 1\n", steps);
+ steps = 1;
+ }
+ dt = 60000000000 / (bpm * steps);
}
void
-main(void)
+cmdpause(List **, int, char **)
{
- Biobuf *in = Bfdopen(0, OREAD);
- vlong t = nsec();
- List *lp = &start;
+ pause();
+}
+
+void
+cmdreload(List **lp, int, char **)
+{
+ clearlist(list);
+ list = loadlist(file);
+ *lp = list;
+}
+
+List *
+loadlist(char *file)
+{
+ List start, *lp;
char *s;
- dt = 60000000000 / (bpm * steps);
- while ((s = Brdstr(in, '\n', 1)) != nil) {
- while((s[0] == ' ') || (s[0] == '\t')) s++;
- if ((s[0] == '\0') || (s[0] == '#')) {
- free(s);
- } else {
- lp->v = s;
- lp->next = sbrk(sizeof(List));
- lp = lp->next;
- lp->next = nil, lp->v = nil;
- }
+ Biobuf *in = Bopen(file, OREAD);
+ if (in == nil) sysfatal("%r");
+ lp = &start;
+ while((s = Brdstr(in, '\n', 1)) != nil) {
+ lp->next = mallocz(sizeof(List), 1);
+ lp = lp->next;
+ lp->v = s;
}
- for (lp = &start, s = lp->v; s!= nil; lp = lp->next, s = lp->v) {
- if (cmd(s) != 0) {
- t += dt;
- sleep((t - nsec()) / 1000000);
+ Bterm(in);
+ return start.next;
+}
+
+void
+clearlist(List *lp)
+{
+ while (lp != nil) {
+ free(lp->v);
+ List *next = lp->next;
+ free(lp);
+ lp = next;
+ }
+}
+
+void
+pause(void)
+{
+ t += dt;
+ sleep((t - nsec()) / 1000000);
+}
+
+void
+trkstep(List **lp)
+{
+ char *s = (char *)(*lp)->v;
+ *lp = (*lp)->next;
+ int i;
+ for (i = 0; i < sizeof(cmds) / sizeof(struct Cmds); i++) {
+ if (strlen(s) == 0) return;
+ if (strncmp(s, cmds[i].name, strlen(cmds[i].name)) == 0) {
+ if (cmds[i].func != nil) {
+ char *dup = strdup(s);
+ char *args[64];
+ int n = tokenize(dup, args, 64);
+ cmds[i].func(lp, n, args);
+ free(dup);
+ }
+ return;
}
}
+ if (i >= sizeof(cmds) / sizeof(struct Cmds)) {
+ print("%s\n", s);
+ pause();
+ }
+}
+
+void
+trkexec(List *start)
+{
+ List *lp = start;
+ while (lp != nil) trkstep(&lp);
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s file\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ ARGBEGIN {
+ default:
+ usage();
+ } ARGEND;
+ if (argc != 1) usage();
+ file = argv[0];
+ list = loadlist(file);
+
+ t = nsec();
+ dt = 60000000000 / (bpm * steps);
+
+ trkexec(list);
+ clearlist(list);
}