Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdint.h>
- #include <byteswap.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #define DEBUG
- enum error_type {
- UNKNOWN,
- SUCCESS,
- NO_FILE,
- NO_PERM,
- END_OF_FILE
- };
- struct header_chunk {
- char type[4];
- uint32_t length;
- uint16_t format;
- uint16_t ntrks;
- uint16_t division;
- /*
- union {
- int8_t smpte;
- int8_t ticks_per_frame;
- int16_t ticks_per_quater_note;
- };*/
- } __attribute__((__packed__));
- struct track_event {
- uint32_t delta_time;
- uint8_t event_type;
- struct {
- uint8_t type;
- uint32_t length;
- } meta;
- };
- struct track_chunk {
- char type[4];
- uint32_t length;
- struct track_event *events;
- size_t events_maxsize;
- uint32_t events_size;
- } __attribute__((__packed__));
- struct list_track_chunk {
- struct track_chunk *tracks;
- size_t maxsize;
- uint32_t size;
- };
- void debug_header_chunk(struct header_chunk hdr) {
- #ifdef DEBUG
- printf("HEADER CHUNK\n");
- printf("\tType: %s\n\tLength: %d\n\tFormat: %d\n\tNtrks: %d\n\tDivision: %d\n", hdr.type, hdr.length, hdr.format, hdr.ntrks, hdr.division);
- #endif
- }
- void debug_track_chunck(struct track_chunk trc) {
- #ifdef DEBUG
- printf("TRACK CHUNK\n");
- printf("\tType: %s\n\tLength: %d\n", trc.type, trc.length);
- #endif
- }
- void debug_track_event(struct track_event tre) {
- #ifdef DEBUG
- printf("\n\tTRACK EVENT\n");
- printf("\t\tDelta time: %d\n\t\tEvent type: %#2X", tre.delta_time, tre.event_type);
- #endif
- }
- void format_header_chunk(struct header_chunk *hdr) {
- /* if((hdr->division & (1 << 15)) == 1) {
- hdr->smpte = (hdr->division & 0b0111111100000000);
- hdr->ticks_per_frame = hdr->division & 0b0000000011111111;
- hdr->smpte = __bswap_16(hdr->smpte);
- hdr->ticks_per_frame = __bswap_16(hdr->ticks_per_frame);
- printf("%d %d\n\n", hdr->smpte, hdr->ticks_per_frame);
- }
- */
- hdr->length = __bswap_32(hdr->length);
- hdr->format = __bswap_16(hdr->format);
- hdr->ntrks = __bswap_16(hdr->ntrks);
- hdr->division = __bswap_16(hdr->division);
- }
- void format_track_chunk(struct track_chunk *trc) {
- trc->length = __bswap_32(trc->length);
- }
- void format_track_event(struct track_event *tre) {
- tre->delta_time = __bswap_32(tre->delta_time);
- }
- enum error_type read_data(int fd, void *data, size_t size, uint32_t *total_byte_reads) {
- int bytes_read = read(fd, data, size);
- total_byte_reads += size;
- if(bytes_read == 0)
- return END_OF_FILE;
- return SUCCESS;
- }
- uint32_t read_variable_length(int fd, uint32_t *total_byte_reads) {
- uint8_t byte;
- uint32_t pos_cmptr = 0;
- uint32_t val;
- read_data(fd, &val, sizeof(uint8_t), total_byte_reads);
- if(val & 0x80) {
- int8_t c;
- val &= 0x7F;
- //val = (val << 7) + (c & 0x7F);
- do {
- read_data(fd, &c, sizeof(int8_t), total_byte_reads);
- val = (val << 7) + (c & 0x7F);
- } while(c & 0x80);
- }
- val = __bswap_32(val);
- return val;
- }
- void skip_bytes_file(int fd, uint32_t n) {
- lseek(fd, n, SEEK_CUR);
- }
- enum error_type manage_meta_events(int fd, struct track_event *tre, uint32_t *total_byte_reads) {
- enum error_type err = SUCCESS;
- err = read_data(fd, &tre->meta.type, sizeof(uint8_t), total_byte_reads);
- if(err != SUCCESS) return err;
- err = read_data(fd, &tre->meta.length, sizeof(uint8_t), total_byte_reads);
- if(err != SUCCESS) return err;
- switch(tre->meta.type) {
- case 0x00:
- break;
- case 0x20:
- break;
- case 0x2F:
- skip_bytes_file(fd, tre->meta.length);
- *total_byte_reads += tre->meta.length;
- break;
- case 0x51:
- skip_bytes_file(fd, tre->meta.length);
- *total_byte_reads += tre->meta.length;
- break;
- case 0x58:
- skip_bytes_file(fd, tre->meta.length);
- *total_byte_reads += tre->meta.length;
- break;
- default:
- skip_bytes_file(fd, tre->meta.length);
- *total_byte_reads += tre->meta.length;
- break;
- }
- return err;
- }
- enum error_type read_track_chunk(int fd, struct track_chunk *trc) {
- enum error_type err = SUCCESS;
- uint32_t total_byte_reads = 0;
- trc->events_maxsize = 20;
- trc->events_size = 0;
- trc->events = malloc(trc->events_maxsize * sizeof(struct track_event));
- while(total_byte_reads < trc->length) {
- struct track_event tre;
- tre.delta_time = read_variable_length(fd, &total_byte_reads);
- err = read_data(fd, &tre.event_type, sizeof(tre.event_type), &total_byte_reads);
- if(err != SUCCESS) return err;
- format_track_event(&tre);
- if(tre.event_type == 0xFF) {
- err = manage_meta_events(fd, &tre, &total_byte_reads);
- if(err != SUCCESS) return err;
- }
- else if(tre.event_type == 0xF0) {
- uint32_t l;
- l = read_variable_length(fd, &total_byte_reads);
- skip_bytes_file(fd, l);
- }
- else if(tre.event_type == 0xF7) {
- uint32_t l;
- l = read_variable_length(fd, &total_byte_reads);
- skip_bytes_file(fd, l);
- }
- trc->events[trc->events_size++] = tre;
- if(trc->events_size >= trc->events_maxsize) {
- trc->events_maxsize *= 2;
- trc->events = realloc(trc->events, trc->events_maxsize);
- }
- }
- #ifdef DEBUG
- printf("\tEvents read: %d\n\n", trc->events_size);
- #endif
- return SUCCESS;
- }
- int main(void) {
- enum error_type err = SUCCESS;
- struct header_chunk hdr;
- int fd;
- fd = open("riverflowsinyou.mid", O_RDONLY);
- if(fd > 0) {
- uint32_t total_byte_reads = 0;
- struct list_track_chunk list_tracks;
- list_tracks.maxsize = 5;
- list_tracks.size = 0;
- list_tracks.tracks = malloc(list_tracks.maxsize * sizeof(struct track_chunk));
- read_data(fd, &hdr, sizeof(struct header_chunk), &total_byte_reads);
- format_header_chunk(&hdr);
- debug_header_chunk(hdr);
- while(err != END_OF_FILE) {
- struct track_chunk trc;
- err = read_data(fd, &trc, 8, &total_byte_reads);
- if(err != SUCCESS) return err;
- format_track_chunk(&trc);
- debug_track_chunck(trc);
- total_byte_reads = 0;
- err = read_track_chunk(fd, &trc);
- if(err != SUCCESS) {printf("ok"); break;}
- list_tracks.tracks[list_tracks.size] = trc;
- if(list_tracks.size >= list_tracks.maxsize) {
- list_tracks.maxsize *= 2;
- list_tracks.tracks = realloc(list_tracks.tracks, list_tracks.maxsize * sizeof(struct track_chunk));
- }
- }
- for(int i = 0; i < list_tracks.size; ++i) {
- free(list_tracks.tracks[i].events);
- }
- free(list_tracks.tracks);
- }
- else {
- err = NO_FILE;
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement