diff options
author | James McKenzie <root@ka-ata-killa.panaceas.james.local> | 2023-01-16 08:14:09 +0000 |
---|---|---|
committer | James McKenzie <root@ka-ata-killa.panaceas.james.local> | 2023-01-16 08:14:09 +0000 |
commit | 3d1eae53e8efd24f9331bfc973c0951981512d7c (patch) | |
tree | a87c3f881adb62b8a65d7d473e18a963fc440cd0 | |
download | fugue21-master.tar.gz fugue21-master.tar.bz2 fugue21-master.zip |
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | fugue21.mid | bin | 0 -> 8542 bytes | |||
-rw-r--r-- | midi.c | 247 |
4 files changed, 267 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..19edf2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +midi +midi.o +fugue21.raw +fugue21.wav diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a96b685 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +LIBS=-lm + +default: fugue21.wav + +fugue21.wav: fugue21.raw Makefile + sox -v 1.0 -t raw -r 44100 -c 1 -b 8 -e signed-integer $< -t wav -b 16 $@ + + +fugue21.raw: fugue21.mid midi + ./midi + + +OBJS=midi.o + +midi:${OBJS} + ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} diff --git a/fugue21.mid b/fugue21.mid Binary files differnew file mode 100644 index 0000000..46d6dff --- /dev/null +++ b/fugue21.mid @@ -0,0 +1,247 @@ +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <byteswap.h> +#include <string.h> +#include <math.h> + + +#define MAX_CH 4 +#define MAX_TICK 100000 +#define SAMPLE_RATE 44100 +#define SAMPLES_PER_TICK 50 + +#define MAX_SAMPLE (SAMPLES_PER_TICK*MAX_TICK) + +uint8_t active_note[MAX_CH][MAX_TICK]; + +double periods[128]; + + +double +freq (int n) +{ + return 440. * pow (2., ((double) (n - 69)) / 12.); +} + + +void +calc_freqs (void) +{ + unsigned i; + + for (i = 0; i < 128; ++i) + periods[i] = ((double) SAMPLE_RATE) / freq (i); +} + + + + +void +on (unsigned t, unsigned ch, unsigned n) +{ + memset (&active_note[ch][t], n, MAX_TICK - t); +} + +void +off (unsigned t, unsigned ch, unsigned n) +{ + memset (&active_note[ch][t], 0, MAX_TICK - t); +} + + +void +mtrk (FILE *f, long pos, long end) +{ + + uint32_t t = 0, v, m, dt; + uint8_t k; + + end += pos; + + + while (pos < end) { + + fseek (f, pos, SEEK_SET); + + dt = 0; + + do { + fread (&v, 1, 1, f); + pos++; + dt <<= 7; + dt |= v & 0x7f; + } while (v & 0x80); + + + t += dt; + + fread (&v, 1, 1, f); + + if (v & 0x80) { + m = v; + pos++; + } else + fseek (f, pos, SEEK_SET); + + + switch (m & 0xf0) { + case 0x80: + fread (&k, 1, 1, f); + fread (&v, 1, 1, f); + pos += 2; + off (t, m & 0xf, k); + //printf ("%d: OFF %d %d %d\n", t,m &0xf, k, v); + break; + + case 0x90: + fread (&k, 1, 1, f); + fread (&v, 1, 1, f); + pos += 2; + //printf ("%d: ON %d %d %d\n", t, m&0xf,k, v); + on (t, m & 0xf, k); + break; + + case 0xf0: + switch (m) { + case 0xff: + fread (&v, 1, 1, f); + pos++; + + switch (v) { + case 0x3: + fread (&k, 1, 1, f); + pos++; + pos += k; + break; + + case 0x54: + pos += 6; + break; + + case 0x51: + pos += 4; + break; + + case 0x58: + pos += 5; + break; + + case 0x2f: + pos++; + break; + + default: + printf ("?2 FF %x\n", v); + exit (0); + break; + } + + break; + + default: + printf ("?1 %x\n", m); + exit (0); + } + + break; + + default: + printf ("?0 %x\n", m); + exit (0); + + + } + } +} + + + + + +int +parse_chunk (FILE *f) +{ + char fcc[5] = { 0 }; + uint32_t len; + long o; + + if (fread (fcc, 4, 1, f) != 1) + return -1; + + if (fread (&len, 4, 1, f) != 1) + return -1; + + len = bswap_32 (len); + + o = ftell (f); + + printf ("%s for %d bytes at %d\n", fcc, (int) len, (int) o); + + if (!strcmp (fcc, "MTrk")) + mtrk (f, o, len); + + fseek (f, o + len, SEEK_SET); + + return 0; +} + + +void +play (FILE *f) +{ + unsigned s, c, t; + int8_t v; + double d; + + + calc_freqs(); + + + for (s = 0; s < MAX_SAMPLE; ++s) { + t = s / SAMPLES_PER_TICK; + v = 0; + + for (c = 0; c < MAX_CH; ++c) { + if (active_note[c][t]) { + d = ((double) s) / periods[active_note[c][t]]; + d = fmod (d, 1.0); + + if (d < 0.5) + v--; + else + v++; + } + } + + + v += (s % 3) * 2; + v -= 2; + + if (v < 0) v = -120; + else v = 120; + + fwrite (&v, 1, 1, f); + } +} + +int +main (int argc, char *argv[]) +{ + FILE *f; + + f = fopen ("fugue21.mid", "rb"); + + while (!parse_chunk (f)); + + fclose (f); + + f = fopen ("fugue21.raw", "wb"); + play (f); + fclose (f); + + + + return 0; +} |