/* * Allegro Sound library support routines * Arne de Bruijn */ #include #include #include #include #include "cfile.h" #include "internal.h" #include #include "error.h" #include "timer.h" #include "d_io.h" extern int digi_timer_rate; int retrace_count; char allegro_error[80]=""; #define TIMERS_PER_SECOND 1193181L #define MSEC_TO_TIMER(x) ((long)(x) * (TIMERS_PER_SECOND / 1000)) #define MAX_TIMERS 16 static struct { /* list of active callbacks */ void ((*proc)()); long speed; long counter; } my_int_queue[MAX_TIMERS]; static int find_timer_slot(void (*proc)()) { int x; for (x=0; x= MAX_TIMERS) return -1; waiting_list[waiting_list_size].proc = proc; waiting_list[waiting_list_size].speed = speed; waiting_list_size++; return 0; } #endif x = find_timer_slot(proc); /* find the handler position */ if (x < 0) /* if not there, find free slot */ x = find_timer_slot(NULL); if (x < 0) /* are there any free slots? */ return -1; if (proc != my_int_queue[x].proc) { /* add new entry */ my_int_queue[x].counter = speed; my_int_queue[x].proc = proc; } else { /* alter speed of existing entry */ my_int_queue[x].counter -= my_int_queue[x].speed; my_int_queue[x].counter += speed; } my_int_queue[x].speed = speed; return 0; } int install_int(void (*proc)(), long speed) { return install_int_ex(proc, MSEC_TO_TIMER(speed)); } void remove_int(void (*proc)()) { int x = find_timer_slot(proc); if (x >= 0) { my_int_queue[x].proc = NULL; my_int_queue[x].speed = 0; my_int_queue[x].counter = 0; } } void allg_snd_timer() { int x; for (x=0; x 0) || (shift == 0)) { *(--p) = (delta & 127) | shift; delta >>= 7; shift = 128; } return data; } /* * read a MIDI type variabele length number */ static unsigned char *read_var(unsigned char *data, unsigned char *dataend, unsigned long *value) { unsigned long v = 0; while ((data < dataend) && (*data & 0x80)) v = (v << 7) + (*(data++) & 0x7f); if (data == dataend) return NULL; v = (v << 7) + *(data++); if (value) *value = v; return data; } static int trans_data(unsigned char *data, int size) { static int cmdlen[7]={3,3,3,3,2,2,3}; unsigned char *dataend = data + size; unsigned long v; while (data < dataend) { if (!(data = conv_delta(data, dataend))) return 1; if (data == dataend) return 1; /* need something after delta */ if (*data < 0x80) return 1; /* invalid command */ if (*data < 0xf0) { data += cmdlen[((*data) >> 4) - 8]; } else if (*data == 0xff) { data += 2; if (data >= dataend) return 1; if (!(data = read_var(data, dataend, &v))) return 1; data += v; } else /* sysex -> error */ return 1; } return (data != dataend); /* processed as many as received? */ } /* * load HMP file into Allegro MIDI structure by translating the deltas * and adding tempo information */ MIDI *load_hmp(char *filename) { static unsigned char hmp_tempo[7] = {0x00, 0xff, 0x51, 0x03, 0x0f, 0x42, 0x40}; int c; char buf[256]; long data; CFILE *fp; MIDI *midi; int num_tracks; unsigned char *p; // try .mid first removeext(filename, buf); strcat(buf, ".mid"); if ((midi = load_midi(buf))) return midi; if (!(fp = cfopen(filename, "rb"))) return NULL; midi = malloc(sizeof(MIDI)); /* get some memory */ if (!midi) { cfclose(fp); return NULL; } for (c=0; ctrack[c].data = NULL; midi->track[c].len = 0; } if ((cfread(buf, 1, 8, fp) != 8) || (memcmp(buf, "HMIMIDIP", 8))) goto err; if (cfseek(fp, 0x30, SEEK_SET)) goto err; if (cfread(&num_tracks, 4, 1, fp) != 1) goto err; if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS)) goto err; midi->divisions = 120; if (cfseek(fp, 0x308, SEEK_SET)) goto err; for (c=0; ctrack[c].len = data; if (!(p = midi->track[c].data = malloc(data))) /* allocate memory */ goto err; if (c == 0) { /* track 0: add tempo */ memcpy(p, hmp_tempo, sizeof(hmp_tempo)); p += sizeof(hmp_tempo); data -= sizeof(hmp_tempo); } /* finally, read track data */ if ((cfseek(fp, 4, SEEK_CUR)) || (cfread(p, data, 1, fp) != 1)) goto err; if (trans_data(p, data)) /* translate deltas hmp -> midi */ goto err; } cfclose(fp); lock_midi(midi); return midi; err: cfclose(fp); destroy_midi(midi); return NULL; } char *pack_fgets(char *p, int max, PACKFILE *f) { int c; if (pack_feof(f)) { p[0] = 0; return NULL; } for (c=0; c=p) && (*(p-1)!='/') && (*(p-1)!='\\') && (*(p-1)!=':')) { *(p++)='/'; *p=0;} } void allg_snd_init() { if (LOCK_VARIABLE(my_int_queue) || LOCK_VARIABLE(digi_timer_rate) || LOCK_VARIABLE(retrace_count) || LOCK_FUNCTION(allg_snd_timer)) Error("Error locking sound timer"); timer_set_function(allg_snd_timer); } // return true if using the digmid driver int allegro_using_digmid() { return get_config_int("sound", "midi_card", MIDI_AUTODETECT) == MIDI_DIGMID; }