stew

a monorepo of some sort
git clone git://git.nsmpr.xyz/stew.git
Log | Files | Refs

seq.c (3409B)


      1 /*
      2 	Primitive sequencer / music-tracker
      3 	reads lines from stdin and prints them at controllable rate
      4 */
      5 
      6 #include <u.h>
      7 #include <libc.h>
      8 #include <bio.h>
      9 
     10 typedef struct List List;
     11 
     12 struct List {
     13 	void *v;
     14 	List *next;
     15 };
     16 
     17 List *list, *rstack[64], **rp = rstack;
     18 char *file;
     19 vlong t, dt;
     20 long bpm = 120, steps = 1;
     21 
     22 
     23 List * loadlist(char *);
     24 void clearlist(List *);
     25 
     26 void pause(void);
     27 
     28 #define CMD(X) void X(List **, int , char **)
     29 CMD(cmdbpm);
     30 CMD(cmdpause);
     31 CMD(cmdjump);
     32 CMD(cmdret);
     33 CMD(cmdreload);
     34 
     35 struct Cmds {
     36 	char *name;
     37 	void (*func)(List **, int, char **);
     38 } cmds[] = {
     39 	{ "#",    nil       }, /* comment */
     40 	{ ":",    nil       }, /* label */
     41 	{ ".bpm", cmdbpm    }, /* update bpm to new value */
     42 //	{ "----", cmdpause  },
     43 	{ ".jmp", cmdjump   },
     44 	{ ".ret", cmdret    },
     45 	{ ".rld", cmdreload }, /* reload file and start from the beginning */
     46 };
     47 
     48 void
     49 cmdbpm(List **, int n, char **args)
     50 {
     51 	switch(n){
     52 	case 0: /* what */
     53 	case 1:
     54 		fprint(2, ".bpm: not enough arguments\n");
     55 		break;
     56 	default:
     57 		fprint(2, ".bpm: too much arguments\n");
     58 	case 2:
     59 	case 3:
     60 		bpm = strtol(args[1], nil, 10);
     61 		if (n == 3) steps = strtol(args[2], nil, 10);
     62 	}
     63 	if (bpm <= 0) {
     64 		fprint(2, "bpm is nonsence (%ld), restoring to 120\n", bpm);
     65 		bpm = 120;
     66 	}
     67 	if (steps <= 0) {
     68 		fprint(2, "steps is nonsence (%ld), restoring to 1\n", steps);
     69 		steps = 1;
     70 	}
     71 	dt = 60000000000 / (bpm * steps);
     72 }
     73 
     74 void
     75 cmdpause(List **, int, char **)
     76 {
     77 	pause();
     78 }
     79 
     80 void
     81 cmdjump(List **lp, int n, char **args)
     82 {
     83 	if (n != 2) {
     84 		fprint(2, "cmdjump: wrong argument count %d\n", n);
     85 		return;
     86 	}
     87 	List *jp = list;
     88 	while (strcmp(args[1], (char *)jp->v) != 0) {
     89 		jp = jp->next;
     90 		if (jp == nil) return;
     91 	}
     92 	*rp = (*lp);
     93 	rp ++;
     94 	if (rp > rstack + 64) exits("rstack overflow");
     95 	*lp = jp->next;
     96 }
     97 
     98 void
     99 cmdret(List **lp, int n, char **)
    100 {
    101 	if (n != 1) {
    102 		fprint(2, "cmdret: too much arguments\n");
    103 	};
    104 	rp --;
    105 	if (rp < rstack) exits("rstack underflow");
    106 	*lp = (*rp);
    107 }
    108 
    109 void
    110 cmdreload(List **lp, int, char **)
    111 {
    112 	clearlist(list);
    113 	list = loadlist(file);
    114 	*lp = list;
    115 }
    116 
    117 List *
    118 loadlist(char *file)
    119 {
    120 	List start, *lp;
    121 	char *s;
    122 	Biobuf *in = Bopen(file, OREAD);
    123 	if (in == nil) sysfatal("%r");
    124 	lp = &start;
    125 	while((s = Brdstr(in, '\n', 1)) != nil) {
    126 		lp->next = mallocz(sizeof(List), 1);
    127 		lp = lp->next;
    128 		lp->v = s;
    129 	}
    130 	Bterm(in);
    131 	return start.next;
    132 }
    133 
    134 void
    135 clearlist(List *lp)
    136 {
    137 	while (lp != nil) {
    138 		free(lp->v);
    139 		List *next = lp->next;
    140 		free(lp);
    141 		lp = next;
    142 	}
    143 }
    144 
    145 void
    146 pause(void)
    147 {
    148 	t += dt;
    149 	sleep((t - nsec()) / 1000000);
    150 }
    151 
    152 void
    153 trkstep(List **lp)
    154 {
    155 	char *s = (char *)(*lp)->v;
    156 	*lp = (*lp)->next;
    157 	int i;
    158 	for (i = 0; i < sizeof(cmds) / sizeof(struct Cmds); i++) {
    159 		if (strlen(s) == 0) return;
    160 		if (strncmp(s, cmds[i].name, strlen(cmds[i].name)) == 0) {
    161 			if (cmds[i].func != nil) {
    162 				char *dup = strdup(s);
    163 				char *args[64];
    164 				int n = tokenize(dup, args, 64);
    165 				cmds[i].func(lp, n, args);
    166 				free(dup);
    167 			}
    168 			return;
    169 		}
    170 	}
    171 	if (i >= sizeof(cmds) / sizeof(struct Cmds)) {
    172 		print("%s\n", s);
    173 		pause();
    174 	}
    175 }
    176 
    177 void
    178 trkexec(List *start)
    179 {
    180 	List *lp = start;
    181 	while (lp != nil) trkstep(&lp);
    182 }
    183 
    184 void
    185 usage(void)
    186 {
    187 	fprint(2, "usage: %s file\n", argv0);
    188 	exits("usage");
    189 }
    190 
    191 void
    192 main(int argc, char **argv)
    193 {
    194 	ARGBEGIN {
    195 	default:
    196 		usage();
    197 	} ARGEND;
    198 	if (argc != 1) usage();
    199 	file = argv[0];
    200 	list = loadlist(file);
    201 
    202 	t = nsec();
    203 	dt = 60000000000 / (bpm * steps);
    204 
    205 	trkexec(list);
    206 	clearlist(list);
    207 }