10 unsigned char fgetuc(FILE *in)
12 return((unsigned char)fgetc(in));
17 return((fgetuc(in) << 24) |
25 return((fgetuc(in) << 8) | fgetuc(in));
30 return((fgetuc(in) << 16) | (fgetuc(in) << 8) | fgetuc(in));
33 int fgetv(FILE *in, int *nb)
38 for(ret = 0, c = 0x80, *nb = 0; (c & 0x80); ret = (ret << 7) | (c & 0x7f)) {
42 fprintf(stderr, "miditool: reading too many bytes from a variant number\n");
49 void fputl(uint32_t val, FILE *out)
53 for(i = 24; i >= 0; i -= 8)
54 fputc((val & (0xff << i)) >> i, out);
57 void fputus(uint16_t val, FILE *out)
61 for(i = 8; i >= 0; i -= 8)
62 fputc((val & (0xff << i)) >> i, out);
65 void fskip(FILE *in, int bytes)
69 dummy = malloc(bytes);
70 fread(dummy, 1, bytes, in);
74 void dumphead(FILE *in, FILE *out)
80 tickres = res = fgetus(in);
81 fprintf(out, "header %i %i %i\n", type, ntrk, res);
82 fprintf(out, "# Type: %i ", type);
84 fprintf(out, "(Single track)\n");
86 fprintf(out, "(Simultaneous tracks)\n");
88 fprintf(out, "(Sequential tracks)\n");
90 fprintf(out, "(Unknown)\n");
91 fprintf(out, "# Number of tracks: %i\n", ntrk);
92 fprintf(out, "# Resolution: %i ticks/qn\n", res);
95 int dumptrack(FILE *in, FILE *out, ssize_t len)
97 int nb, dt, cmd, pcmd, mlen, llen;
98 int chan, note, val, id;
101 fprintf(out, "track\n");
102 fprintf(out, "# Number %i\n", trackno++);
103 fprintf(out, "# Length: %zi bytes\n", len);
117 fprintf(stderr, "miditool: illegal command (< 0x80)\n");
125 fprintf(out, "ev %i %i ", tick, chan);
132 fprintf(out, "%s %i %i", (cmd == 9)?"on":"off", note, val);
137 fprintf(out, "poly %i", val);
143 fprintf(out, "ctrl %i %i", id, val);
148 fprintf(out, "prgm %i", val);
153 fprintf(out, "mono %i", val);
156 val = fgetus(in) - 8192;
158 fprintf(out, "bend %i", val);
163 fprintf(out, "msg0 ");
164 mlen = fgetv(in, &nb);
166 for(; mlen > 0; mlen--) {
167 fprintf(out, "%02x", fgetuc(in));
175 fprintf(out, "msg7 ");
176 mlen = fgetv(in, &nb);
178 for(; mlen > 0; mlen--) {
179 fprintf(out, "%02x", fgetuc(in));
189 mlen = fgetv(in, &nb);
194 fprintf(out, "text %i ", id);
195 for(llen = 0; llen < mlen; llen++) {
197 if((val >= 20) && (val <= 126)) {
200 fprintf(out, "\\%03o", val);
206 fprintf(out, "end\n");
211 fprintf(out, "tempo %i\n", val);
212 fprintf(out, "# (%i us/qn) / (%i ticks/qn) = (%i us/tick)\n", val, tickres, val / tickres);
215 fprintf(out, "meta %i ", id);
216 for(; mlen > 0; mlen--) {
217 fprintf(out, "%02x", fgetuc(in));
223 fprintf(stderr, "miditool: warning: unknown midi meta event %i\n", id);
232 fskip(in, mlen - llen);
234 fprintf(stderr, "miditool: warning: too little data read from meta event %i (%i < %i)\n", id, llen, mlen);
235 } else if(llen > mlen) {
236 fprintf(stderr, "miditool: too much data read from meta event %i (%i > %i)\n", id, llen, mlen);
243 fprintf(stderr, "miditool: unknown midi special event %i\n", chan);
253 fprintf(stderr, "miditool: read %i bytes too much from track from track\n", -len);
259 int dumpchunk(FILE *in, FILE *out)
264 if((fread(id, 1, 4, in)) == 0)
267 if(!memcmp(id, "MThd", 4)) {
269 fprintf(stderr, "miditool: invalid header chunk of length %zi\n", len);
273 } else if(!memcmp(id, "MTrk", 4)) {
274 if(dumptrack(in, out, len))
277 fprintf(out, "# Unknown chunk type (%.4s) of length %zi\n", id, len);
283 char *constrack(FILE *in, int *len)
291 void putv(int v, int c) {
294 *(bp++) = (c?0x80:0) | (v & 0x7f);
296 void putb(int v, int n) {
302 buf = malloc(sz = 65536);
303 bp = (unsigned char *)buf;
305 while(fgets(line, sizeof(line), in) != NULL) {
306 if(((char *)bp - buf) < 32768)
307 buf = realloc(buf, sz += 65536);
308 p = strtok(line, " ");
309 if((p == NULL) || (p[0] == '#'))
311 if(!strcmp(p, "ev")) {
312 if((p = strtok(NULL, " ")) == NULL) {
313 fprintf(stderr, "miditool: truncated ev line\n");
316 putv(atoi(p) - ltime, 0);
318 if((p = strtok(NULL, " ")) == NULL) {
319 fprintf(stderr, "miditool: truncated ev line\n");
323 if((p = strtok(NULL, " ")) == NULL) {
324 fprintf(stderr, "miditool: truncated ev line\n");
327 if(!strcmp(p, "on")) {
328 *(bp++) = 0x90 | chan;
329 if((p = strtok(NULL, " ")) == NULL) {
330 fprintf(stderr, "miditool: truncated ev on line\n");
334 if((p = strtok(NULL, " ")) == NULL) {
335 fprintf(stderr, "miditool: truncated ev on line\n");
339 } else if(!strcmp(p, "off")) {
340 *(bp++) = 0x80 | chan;
341 if((p = strtok(NULL, " ")) == NULL) {
342 fprintf(stderr, "miditool: truncated ev on line\n");
346 if((p = strtok(NULL, " ")) == NULL) {
347 fprintf(stderr, "miditool: truncated ev on line\n");
352 fprintf(stderr, "miditool: ignoring unknown event %s\n", p);
354 } else if(!strcmp(p, "tempo")) {
358 if((p = strtok(NULL, " ")) == NULL) {
359 fprintf(stderr, "miditool: tempo line without tempo\n");
363 } else if(!strcmp(p, "text")) {
364 } else if(!strcmp(p, "end")) {
369 fprintf(stderr, "miditool: ignoring unknown command %s\n", p);
379 int main(int argc, char **argv)
385 fprintf(stderr, "usage: miditool command (see `miditool help' for a list of commands)\n");
390 if(!strcmp(cmd, "help")) {
391 printf("commands:\n");
392 printf("\tdump\tDumps a MIDI file to text format\n");
393 printf("\tconsh\tConstructs a header chunk\n");
394 } else if(!strcmp(cmd, "consh")) {
396 fprintf(stderr, "usage: miditool consh TYPE NTRACKS RES\n");
402 fputus(atoi(argv[1]), out);
403 fputus(atoi(argv[2]), out);
404 fputus(atoi(argv[3]), out);
405 } else if(!strcmp(cmd, "dump")) {
408 if((in = fopen(argv[1], "r")) == NULL) {
414 dumpchunk(in, stdout);