From: John Tsiombikas Date: Fri, 17 Jun 2022 02:50:34 +0000 (+0300) Subject: foo X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=bootcard;a=commitdiff_plain;h=2daaab5bc6aefe8ca26c29867428824fc1dd6b1c foo --- diff --git a/.gitignore b/.gitignore index 52f0c45..b239ad4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ *.swp +*.o *.img *.bin +RUN +tools/mididump/mididump +*.mid diff --git a/bootcard.asm b/bootcard.asm index e0955ed..d07c107 100644 --- a/bootcard.asm +++ b/bootcard.asm @@ -7,6 +7,9 @@ bits 16 data_start equ 7e00h +nticks equ data_start +muscur equ nticks + 4 + osc_freq equ 1193182 PIT_DATA0 equ 40h PIT_DATA2 equ 42h @@ -44,6 +47,8 @@ KB_CTRL equ 61h mov ss, ax mov sp, 7c00h + mov dword [nticks], 0 + mov dword [muscur], 0 call init_spk mov ax, 13h @@ -63,25 +68,15 @@ KB_CTRL equ 61h mov si, str2 call textout + sti + infloop: hlt jmp infloop init_spk: - xor ax, ax - mov [32], ax - mov word [34], timer_intr - - mov al, PIT_CMD_CHAN2 | PIT_CMD_HILO | PIT_CMD_SQWAVE - out PIT_CMD, al - mov ax, DIV_ROUND(osc_freq, 440) - out PIT_DATA2, al - mov al, ah - out PIT_DATA2, al - - spkon - - sti + mov word [32], timer_intr + mov word [34], 0 ret textout: @@ -96,14 +91,53 @@ textout: .done: ret timer_intr: - spkoff - mov al, 20h + mov ax, [nticks] + inc ax + mov [nticks], ax + + mov bx, [muscur] + shl bx, 2 + mov cx, [music + bx] + cmp cx, 0ffffh + jz .off + cmp ax, cx + jb .eoi + + inc dword [muscur] + mov ax, [music + 2 + bx] ; grab timeout + test ax, ax + jz .off + mov bx, ax + + mov al, PIT_CMD_CHAN2 | PIT_CMD_HILO | PIT_CMD_SQWAVE + out PIT_CMD, al + mov ax, bx + out PIT_DATA2, al + mov al, ah + out PIT_DATA2, al + spkon + jmp .eoi + +.off: spkoff + +.eoi: mov al, 20h out 20h, al ; EOI iret str1: db 'message message blah',0 str2: db 'Michael & Athina',0 +music: + dw 0, 500 + dw 10, 0 + dw 20, 2000 + dw 30, 0 + dw 40, 500 + dw 50, 0 + dw 60, 2000 + dw 70, 0 + dw 0ffffh, 0 + times 446-($-$$) db 0 dd 00212080h dd 0820280ch diff --git a/tools/mididump/Makefile b/tools/mididump/Makefile new file mode 100644 index 0000000..08b7d74 --- /dev/null +++ b/tools/mididump/Makefile @@ -0,0 +1,11 @@ +obj = mididump.o midi.o +bin = mididump + +CFLAGS = -pedantic -Wall -g + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(bin) $(obj) diff --git a/tools/mididump/midi.c b/tools/mididump/midi.c new file mode 100644 index 0000000..3acbb98 --- /dev/null +++ b/tools/mididump/midi.c @@ -0,0 +1,419 @@ +#include +#include +#include +#include +#include +#include "midi.h" + +#define USE_MMAP + +#define FMT_SINGLE 0 +#define FMT_MULTI_TRACK 1 +#define FMT_MULTI_SEQ 2 + +/* meta events */ +#define META_SEQ 0 +#define META_TEXT 1 +#define META_COPYRIGHT 2 +#define META_NAME 3 +#define META_INSTR 4 +#define META_LYRICS 5 +#define META_MARKER 6 +#define META_CUE 7 +#define META_CHANPREFIX 32 +#define META_END_TRACK 47 +#define META_TEMPO 81 +#define META_SMPTE_OFFS 84 +#define META_TMSIG 88 +#define META_KEYSIG 89 +#define META_SPECIFIC 127 + +#define CHUNK_HDR_SIZE 8 +struct chunk_hdr { + char id[4]; + uint32_t size; + unsigned char data[1]; +}; + +struct midi_hdr { + uint16_t fmt; /* 0: single, 1: multi-track, 2: multiple independent */ + uint16_t num_tracks; + uint16_t tm_div; + +} __attribute__ ((packed)); + +static void destroy_track(struct midi_track *trk); +static int read_track(struct midi *midi, struct chunk_hdr *chunk); +static long read_vardata(unsigned char **pptr); +static int read_meta_event(struct midi *midi, struct midi_track *trk, unsigned char **pptr); +static int read_sysex_event(struct midi *midi, unsigned char **pptr); +static int ischunk(struct chunk_hdr *chunk, const char *name); +static struct chunk_hdr *mkchunk(void *ptr); +static struct chunk_hdr *skip_chunk(struct chunk_hdr *chunk); +static struct midi_hdr *mkmidi(void *ptr); +static void bigend(void *ptr, int sz); +static void *map_file(const char *fname, int *size); +static void unmap_file(void *mem, int size); + +#define IS_VALID_EVTYPE(x) ((x) >= MIDI_NOTE_OFF && (x) <= MIDI_PITCH_BEND) + +/* XXX the event arity table must match the MIDI_* defines in midi.h */ +static int ev_arity[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 2, /* note off (note, velocity)*/ + 2, /* note on (note, velocity)*/ + 2, /* note aftertouch (note, aftertouch value) */ + 2, /* controller (controller number, value) */ + 1, /* prog change (prog number) */ + 1, /* channel aftertouch (aftertouch value) */ + 2 /* pitch bend (pitch LSB, pitch MSB) */ +}; + + +struct midi *midi_load(const char *fname) +{ + struct midi *midi; + char *mem; + int size; + struct chunk_hdr *chunk; + struct midi_hdr *hdr; + + if(!(mem = map_file(fname, &size))) { + return 0; + } + chunk = mkchunk(mem); + + if(!ischunk(chunk, "MThd") || chunk->size != 6) { + fprintf(stderr, "invalid or corrupted midi file: %s\n", fname); + goto err; + } + hdr = mkmidi(chunk->data); + + if(!(midi = malloc(sizeof *midi))) { + perror("failed to allocate memory"); + goto err; + } + + if((hdr->tm_div & 0x8000) == 0) { + /* division is in pulses / quarter note */ + midi->ppqn = hdr->tm_div; + midi->fps = midi->ticks_per_frame = -1; + } else { + /* division in frames / sec */ + midi->fps = (hdr->tm_div & 0x7f00) >> 8; + midi->ticks_per_frame = hdr->tm_div & 0xff; + midi->ppqn = -1; + } + + if(!(midi->tracks = malloc(hdr->num_tracks * sizeof *midi->tracks))) { + perror("failed to allocate memory"); + goto err; + } + midi->num_tracks = 0; + + while((chunk = skip_chunk(chunk)) && ((char*)chunk < mem + size)) { + if(ischunk(chunk, "MTrk")) { + if(read_track(midi, chunk) == -1) { + fprintf(stderr, "failed to read track\n"); + } + } + } + + unmap_file(mem, size); + return midi; + +err: + unmap_file(mem, size); + midi_free(midi); + return 0; +} + +void midi_free(struct midi *midi) +{ + int i; + + if(!midi) return; + + for(i=0; inum_tracks; i++) { + destroy_track(midi->tracks + i); + } + + free(midi->tracks); + free(midi); +} + +int midi_num_tracks(struct midi *midi) +{ + return midi->num_tracks; +} + +struct midi_track *midi_track(struct midi *midi, int idx) +{ + if(idx < 0 || idx >= midi->num_tracks) { + return 0; + } + return midi->tracks + idx; +} + +static void destroy_track(struct midi_track *trk) +{ + free(trk->name); + while(trk->head) { + void *tmp = trk->head; + trk->head = trk->head->next; + free(tmp); + } +} + +static int read_track(struct midi *midi, struct chunk_hdr *chunk) +{ + unsigned char *ptr; + struct midi_track trk = {0, 0, 0, 0}; + unsigned char prev_stat = 0; + int type; + struct midi_event *ev; + + if(!ischunk(chunk, "MTrk")) { + return -1; + } + + ptr = chunk->data; + while(ptr < chunk->data + chunk->size) { + long dt; + unsigned char stat; + + dt = read_vardata(&ptr); + stat = *ptr++; + + if(stat == 0xff) { + read_meta_event(midi, &trk, &ptr); + } else if(stat == 0xf0) { + read_sysex_event(midi, &ptr); + } else { + if(!(stat & 0x80)) { + /* not a status byte, assume running status */ + stat = prev_stat; + ptr--; + } + type = (stat >> 4) & 0xf; + + if(!IS_VALID_EVTYPE(type) || !(ev = malloc(sizeof *ev))) { + /* unkwown message, skip all data bytes */ + while(ptr < chunk->data + chunk->size && !(*ptr & 0x80)) { + ptr++; + } + continue; + } + + if(trk.head) { + trk.tail->next = ev; + } else { + trk.head = ev; + } + trk.tail = ev; + ev->next = 0; + trk.num_ev++; + + ev->dt = dt; + ev->type = type; + ev->channel = stat & 0xf; + + ev->arg[0] = *ptr++; + if(ev_arity[ev->type] > 1) { + ev->arg[1] = *ptr++; + } + + if(ev->type == MIDI_NOTE_ON && ev->arg[1] == 0) { + ev->type = MIDI_NOTE_OFF; + } + + prev_stat = stat; + } + } + + /* if we did actually add any events ... */ + if(trk.num_ev) { + midi->tracks[midi->num_tracks++] = trk; + /*printf("loaded track with %d events\n", trk.num_ev);*/ + } + return 0; +} + +static long read_vardata(unsigned char **pptr) +{ + int i; + long res = 0; + unsigned char *ptr = *pptr; + + for(i=0; i<4; i++) { + res |= (long)(*ptr & 0x7f) << (i * 8); + + /* if first bit is not set we're done */ + if((*ptr++ & 0x80) == 0) + break; + } + *pptr = ptr; + return res; +} + +static int read_meta_event(struct midi *midi, struct midi_track *trk, unsigned char **pptr) +{ + unsigned char *ptr = *pptr; + unsigned char type; + long size; + + type = *ptr++; + size = read_vardata(&ptr); + + switch(type) { + case META_NAME: + free(trk->name); + trk->name = malloc(size + 1); + memcpy(trk->name, ptr, size); + trk->name[size] = 0; + break; + + case META_TEMPO: + /* TODO add a tempo change event to the midi struct */ + break; + + default: + break; + } + *pptr = ptr + size; + return 0; +} + +/* ignore sysex events */ +static int read_sysex_event(struct midi *midi, unsigned char **pptr) +{ + long size = read_vardata(pptr); + *pptr += size; + return 0; +} + +static int ischunk(struct chunk_hdr *chunk, const char *name) +{ + return memcmp(chunk->id, name, 4) == 0; +} + +static struct chunk_hdr *mkchunk(void *ptr) +{ + struct chunk_hdr *chdr = ptr; + bigend(&chdr->size, sizeof chdr->size); + return chdr; +} + +static struct chunk_hdr *skip_chunk(struct chunk_hdr *chunk) +{ + return mkchunk((char*)chunk + CHUNK_HDR_SIZE + chunk->size); +} + +static struct midi_hdr *mkmidi(void *ptr) +{ + struct midi_hdr *midi = ptr; + + bigend(&midi->fmt, sizeof midi->fmt); + bigend(&midi->num_tracks, sizeof midi->num_tracks); + bigend(&midi->tm_div, sizeof midi->tm_div); + return midi; +} + +static void bigend(void *ptr, int sz) +{ + static unsigned char test[] = {0x12, 0x34}; + uint32_t val32; + uint16_t val16; + + if(sz < 2 || *(uint16_t*)test == 0x1234) { + return; + } + + switch(sz) { + case 4: + val32 = *(uint32_t*)ptr; + *(uint32_t*)ptr = (val32 << 24) | (val32 >> 24) | ((val32 & 0xff00) << 8) | + ((val32 & 0xff0000) >> 8); + break; + + case 2: + val16 = *(uint16_t*)ptr; + *(uint16_t*)ptr = (val16 >> 8) | (val16 << 8); + break; + + case 1: + default: + break; + } +} + +#if defined(__unix__) && defined(USE_MMAP) +#include +#include +#include +#include + +static void *map_file(const char *fname, int *size) +{ + int fd; + struct stat st; + void *mem; + + if((fd = open(fname, O_RDONLY)) == -1) { + fprintf(stderr, "failed to open midi file: %s: %s\n", fname, strerror(errno)); + return 0; + } + fstat(fd, &st); + + if((mem = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) == (void*)-1) { + fprintf(stderr, "failed to map midi file: %s: %s\n", fname, strerror(errno)); + close(fd); + return 0; + } + close(fd); + + *size = st.st_size; + return mem; +} + +static void unmap_file(void *mem, int size) +{ + munmap(mem, size); +} +#else +static void *map_file(const char *fname, int *size) +{ + FILE *fp; + long sz; + void *buf; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "failed to open midi file: %s: %s\n", fname, strerror(errno)); + return 0; + } + fseek(fp, 0, SEEK_END); + sz = ftell(fp); + rewind(fp); + + if(!(buf = malloc(sz))) { + fprintf(stderr, "failed to allocate space for %s in memory (%ld bytes)\n", fname, sz); + fclose(fp); + return 0; + } + if(fread(buf, 1, sz, fp) != sz) { + fprintf(stderr, "failed to load midi file: %s: %s\n", fname, strerror(errno)); + free(buf); + fclose(fp); + return 0; + } + fclose(fp); + + *size = sz; + return buf; +} + +static void unmap_file(void *mem, int size) +{ + free(mem); +} +#endif diff --git a/tools/mididump/midi.h b/tools/mididump/midi.h new file mode 100644 index 0000000..f9232ff --- /dev/null +++ b/tools/mididump/midi.h @@ -0,0 +1,54 @@ +#ifndef MIDI_H_ +#define MIDI_H_ + +#include + +struct midi { + int ppqn, fps, ticks_per_frame; + + int num_tracks; + struct midi_track *tracks; +}; + + +struct midi_track { + char *name; + struct midi_event *head, *tail; + int num_ev; +}; + +struct midi_event { + long dt; + int type; + int channel; + int arg[2]; + + struct midi_event *next; +}; + +#define MIDI_NOTE_OFF 8 +#define MIDI_NOTE_ON 9 +#define MIDI_NOTE_AFTERTOUCH 10 +#define MIDI_CONTROLLER 11 +#define MIDI_PROG_CHANGE 12 +#define MIDI_CHAN_AFTERTOUCH 13 +#define MIDI_PITCH_BEND 14 + +#define MIDI_NOTE_NUM(ev) ((ev)->arg[0]) +#define MIDI_NOTE_VEL(ev) ((ev)->arg[1]) + +#ifdef __cplusplus +extern "C" { +#endif + +struct midi *midi_load(const char *fname); +void midi_free(struct midi *midi); + +int midi_num_tracks(struct midi *midi); +struct midi_track *midi_track(struct midi *midi, int idx); + +#ifdef __cplusplus +} +#endif + +#endif /* MIDI_H_ */ diff --git a/tools/mididump/mididump.c b/tools/mididump/mididump.c new file mode 100644 index 0000000..5502ed6 --- /dev/null +++ b/tools/mididump/mididump.c @@ -0,0 +1,106 @@ +#include +#include +#include "midi.h" + +unsigned int calc_reload(int note); + +int main(int argc, char **argv) +{ + int i, chan = -1; + struct midi *midi; + struct midi_event *ev; + long ticks; + + if(!argv[1]) { + fprintf(stderr, "pass the path to a midi file\n"); + return 1; + } + if(argv[2]) { + if((chan = atoi(argv[2])) < 0 || chan > 127) { + fprintf(stderr, "invalid channel: %d\n", chan); + return 1; + } + } + + if(!(midi = midi_load(argv[1]))) { + fprintf(stderr, "failed to load midi file: %s\n", argv[1]); + return 1; + } + + if(chan < 0) { + printf("midi file: %s\n", argv[1]); + if(midi->ppqn > 0) { + printf(" pulses per quarter-note: %d\n", midi->ppqn); + } + if(midi->fps > 0) { + printf(" fps: %d (ticks per frame: %d)\n", midi->fps, midi->ticks_per_frame); + } + printf(" tracks: %d\n", midi->num_tracks); + for(i=0; inum_tracks; i++) { + if(midi->tracks[i].name) { + printf(" %d - \"%s\":", i, midi->tracks[i].name); + } else { + printf(" %d:", i); + } + printf(" %d events\n", midi->tracks[i].num_ev); + } + midi_free(midi); + return 0; + } + + if(chan >= midi->num_tracks) { + fprintf(stderr, "invalid track: %d (file has %d tracks)\n", chan, midi->num_tracks); + midi_free(midi); + return 1; + } + + ticks = 0; + ev = midi->tracks[chan].head; + while(ev) { + ticks += ev->dt; + switch(ev->type) { + case MIDI_NOTE_ON: + /*printf("%ld: %d (%d)\n", ticks, MIDI_NOTE_NUM(ev), MIDI_NOTE_VEL(ev));*/ + if(ticks >= 0) { + printf("\tdw %ld, %u\n", ticks, calc_reload(MIDI_NOTE_NUM(ev))); + } + break; + + case MIDI_NOTE_OFF: + /*printf("%ld: off\n", ticks);*/ + if(ticks >= 0) { + printf("\tdw %ld, 0\n", ticks); + } + break; + + default: + break; + } + ev = ev->next; + } + + midi_free(midi); + return 0; +} + + +static float note_freq[] = { + 27.500, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, + 48.999, 51.913, 55.000, 58.270, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, + 87.307, 92.499, 97.999, 103.83, 110.00, 116.54, 123.47, 130.81, 138.59, 146.83, + 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94, 261.63, + 277.18, 293.67, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, + 493.88, 523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, + 880.00, 932.33, 987.77, 1046.5, 1108.7, 1174.7, 1244.5, 1318.5, 1396.9, 1480.0, + 1568.0, 1661.2, 1760.0, 1864.7, 1975.5, 2093.0, 2217.5, 2349.3, 2489.0, 2637.0, + 2793.0, 2960.0, 3136.0, 3322.4, 3520.0, 3729.3, 3951.1, 4186.0 +}; + +#define OSC 1193182 + +unsigned int calc_reload(int note) +{ + if(note < 21 || note > 108) return 0; + + return (int)(OSC / note_freq[note - 21] + 0.5f); +}