struct _mdi *_WM_ParseNewXmi(uint8_t *xmi_data, uint32_t xmi_size) { struct _mdi *xmi_mdi = NULL; uint32_t xmi_tmpdata = 0; uint8_t xmi_formcnt = 0; uint32_t xmi_catlen = 0; uint32_t xmi_subformlen = 0; uint32_t i = 0; uint32_t j = 0; uint32_t xmi_evntlen = 0; uint32_t xmi_divisions = 60; uint32_t xmi_tempo = 500000; uint32_t xmi_sample_count = 0; float xmi_sample_count_f = 0; float xmi_sample_remainder = 0; float xmi_samples_per_delta_f = 0; uint8_t xmi_ch = 0; uint8_t xmi_note = 0; uint32_t *xmi_notelen = NULL; uint32_t setup_ret = 0; uint32_t xmi_delta = 0; uint32_t xmi_lowestdelta = 0; uint32_t xmi_evnt_cnt = 0; if (memcmp(xmi_data,"FORM",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_data += 4; xmi_size -= 4; // bytes until next entry xmi_tmpdata = *xmi_data++ << 24; xmi_tmpdata |= *xmi_data++ << 16; xmi_tmpdata |= *xmi_data++ << 8; xmi_tmpdata |= *xmi_data++; xmi_size -= 4; if (memcmp(xmi_data,"XDIRINFO",8)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_data += 8; xmi_size -= 8; /* 0x00 0x00 0x00 0x02 at this point are unknown so skip over them */ xmi_data += 4; xmi_size -= 4; // number of forms contained after this point xmi_formcnt = *xmi_data++; if (xmi_formcnt == 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_size--; /* at this stage unsure if remaining data in this section means anything */ xmi_tmpdata -= 13; xmi_data += xmi_tmpdata; xmi_size -= xmi_tmpdata; /* FIXME: Check: may not even need to process CAT information */ if (memcmp(xmi_data,"CAT ",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_data += 4; xmi_size -= 4; xmi_catlen = *xmi_data++ << 24; xmi_catlen |= *xmi_data++ << 16; xmi_catlen |= *xmi_data++ << 8; xmi_catlen |= *xmi_data++; xmi_size -= 4; WMIDI_UNUSED(xmi_catlen); if (memcmp(xmi_data,"XMID",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_data += 4; xmi_size -= 4; xmi_mdi = _WM_initMDI(); _WM_midi_setup_divisions(xmi_mdi, xmi_divisions); _WM_midi_setup_tempo(xmi_mdi, xmi_tempo); xmi_samples_per_delta_f = _WM_GetSamplesPerTick(xmi_divisions, xmi_tempo); xmi_notelen = (uint32_t *) malloc(sizeof(uint32_t) * 16 * 128); memset(xmi_notelen, 0, (sizeof(uint32_t) * 16 * 128)); for (i = 0; i < xmi_formcnt; i++) { if (memcmp(xmi_data,"FORM",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); goto _xmi_end; } xmi_data += 4; xmi_size -= 4; xmi_subformlen = *xmi_data++ << 24; xmi_subformlen |= *xmi_data++ << 16; xmi_subformlen |= *xmi_data++ << 8; xmi_subformlen |= *xmi_data++; xmi_size -= 4; if (memcmp(xmi_data,"XMID",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); goto _xmi_end; } xmi_data += 4; xmi_size -= 4; xmi_subformlen -= 4; // Process Subform do { if (!memcmp(xmi_data,"TIMB",4)) { // Holds patch information // FIXME: May not be needed for playback as EVNT seems to // hold patch events xmi_data += 4; xmi_tmpdata = *xmi_data++ << 24; xmi_tmpdata |= *xmi_data++ << 16; xmi_tmpdata |= *xmi_data++ << 8; xmi_tmpdata |= *xmi_data++; xmi_data += xmi_tmpdata; xmi_size -= (8 + xmi_tmpdata); xmi_subformlen -= (8 + xmi_tmpdata); } else if (!memcmp(xmi_data,"RBRN",4)) { // Unknown what this is // FIXME: May not be needed for playback xmi_data += 4; xmi_tmpdata = *xmi_data++ << 24; xmi_tmpdata |= *xmi_data++ << 16; xmi_tmpdata |= *xmi_data++ << 8; xmi_tmpdata |= *xmi_data++; xmi_data += xmi_tmpdata; xmi_size -= (8 + xmi_tmpdata); xmi_subformlen -= (8 + xmi_tmpdata); } else if (!memcmp(xmi_data,"EVNT",4)) { // EVNT is where all the MIDI music information is stored xmi_data += 4; xmi_evnt_cnt++; xmi_evntlen = *xmi_data++ << 24; xmi_evntlen |= *xmi_data++ << 16; xmi_evntlen |= *xmi_data++ << 8; xmi_evntlen |= *xmi_data++; xmi_size -= 8; xmi_subformlen -= 8; do { if (*xmi_data < 0x80) { xmi_delta = 0; if (*xmi_data > 0x7f) { while (*xmi_data > 0x7f) { xmi_delta = (xmi_delta << 7) | (*xmi_data++ & 0x7f); xmi_size--; xmi_evntlen--; xmi_subformlen--; } } xmi_delta = (xmi_delta << 7) | (*xmi_data++ & 0x7f); xmi_size--; xmi_evntlen--; xmi_subformlen--; do { // determine delta till next event if ((xmi_lowestdelta != 0) && (xmi_lowestdelta <= xmi_delta)) { xmi_tmpdata = xmi_lowestdelta; } else { xmi_tmpdata = xmi_delta; } xmi_sample_count_f= (((float) xmi_tmpdata * xmi_samples_per_delta_f) + xmi_sample_remainder); xmi_sample_count = (uint32_t) xmi_sample_count_f; xmi_sample_remainder = xmi_sample_count_f - (float) xmi_sample_count; xmi_mdi->events[xmi_mdi->event_count - 1].samples_to_next += xmi_sample_count; xmi_mdi->extra_info.approx_total_samples += xmi_sample_count; xmi_lowestdelta = 0; // scan through on notes for (j = 0; j < (16*128); j++) { // only want notes that are on if (xmi_notelen[j] == 0) continue; // remove delta to next event from on notes xmi_notelen[j] -= xmi_tmpdata; // Check if we need to turn note off if (xmi_notelen[j] == 0) { xmi_ch = j / 128; xmi_note = j - (xmi_ch * 128); _WM_midi_setup_noteoff(xmi_mdi, xmi_ch, xmi_note, 0); } else { // otherwise work out new lowest delta if ((xmi_lowestdelta == 0) || (xmi_lowestdelta > xmi_notelen[j])) { xmi_lowestdelta = xmi_notelen[j]; } } } xmi_delta -= xmi_tmpdata; } while (xmi_delta); } else { if ((xmi_data[0] == 0xff) && (xmi_data[1] == 0x51) && (xmi_data[2] == 0x03)) { // Ignore tempo events setup_ret = 6; goto _XMI_Next_Event; } if ((setup_ret = _WM_SetupMidiEvent(xmi_mdi,xmi_data, xmi_size, 0)) == 0) { goto _xmi_end; } if ((*xmi_data & 0xf0) == 0x90) { // Note on has extra data stating note length xmi_ch = *xmi_data & 0x0f; xmi_note = xmi_data[1]; xmi_data += setup_ret; xmi_size -= setup_ret; xmi_evntlen -= setup_ret; xmi_subformlen -= setup_ret; xmi_tmpdata = 0; if (*xmi_data > 0x7f) { while (*xmi_data > 0x7f) { xmi_tmpdata = (xmi_tmpdata << 7) | (*xmi_data++ & 0x7f); xmi_size--; xmi_evntlen--; xmi_subformlen--; } } xmi_tmpdata = (xmi_tmpdata << 7) | (*xmi_data++ & 0x7f); xmi_size--; xmi_evntlen--; xmi_subformlen--; // store length xmi_notelen[128 * xmi_ch + xmi_note] = xmi_tmpdata; if ((xmi_tmpdata > 0) && ((xmi_lowestdelta == 0) || (xmi_tmpdata < xmi_lowestdelta))) { xmi_lowestdelta = xmi_tmpdata; } } else { _XMI_Next_Event: xmi_data += setup_ret; xmi_size -= setup_ret; xmi_evntlen -= setup_ret; xmi_subformlen -= setup_ret; } } } while (xmi_evntlen); } else { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); goto _xmi_end; } } while (xmi_subformlen); } // Finalise mdi structure if ((xmi_mdi->reverb = _WM_init_reverb(_WM_SampleRate, _WM_reverb_room_width, _WM_reverb_room_length, _WM_reverb_listen_posx, _WM_reverb_listen_posy)) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); goto _xmi_end; } xmi_mdi->extra_info.current_sample = 0; xmi_mdi->current_event = &xmi_mdi->events[0]; xmi_mdi->samples_to_mix = 0; xmi_mdi->note = NULL; /* More than 1 event form in XMI means treat as type 2 */ if (xmi_evnt_cnt > 1) { xmi_mdi->is_type2 = 1; } _WM_ResetToStart(xmi_mdi); _xmi_end: if (xmi_notelen) free(xmi_notelen); if (xmi_mdi->reverb) return (xmi_mdi); _WM_freeMDI(xmi_mdi); return NULL; }
/* Turns hmp file data into an event stream */ struct _mdi * _WM_ParseNewHmi(uint8_t *hmi_data, uint32_t hmi_size) { uint32_t hmi_tmp = 0; uint8_t *hmi_base = hmi_data; uint16_t hmi_bpm = 0; uint16_t hmi_division = 0; // uint32_t hmi_duration_secs = 0; uint32_t hmi_track_cnt = 0; uint32_t *hmi_track_offset = NULL; uint32_t i = 0; uint32_t j = 0; uint8_t *hmi_addr = NULL; uint32_t *hmi_track_header_length = NULL; struct _mdi *hmi_mdi = NULL; uint32_t tempo_f = 5000000.0; uint32_t *hmi_track_end = NULL; uint8_t hmi_tracks_ended = 0; uint8_t *hmi_running_event = NULL; uint32_t setup_ret = 0; uint32_t *hmi_delta = NULL; uint32_t smallest_delta = 0; uint32_t subtract_delta = 0; uint32_t sample_count = 0; float sample_count_f = 0; float sample_remainder = 0; float samples_per_delta_f = 0.0; struct _note { uint32_t length; uint8_t channel; } *note; //FIXME: This needs to be used for sanity check. UNUSED(hmi_size); if (memcmp(hmi_data, "HMI-MIDISONG061595", 18)) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_NOT_HMI, NULL, 0); return NULL; } //FIXME: Unsure if this is correct but it seems to be the only offset that plays the files at what appears to be the right speed. hmi_bpm = hmi_data[212]; hmi_division = 60; hmi_track_cnt = hmi_data[228]; hmi_mdi = _WM_initMDI(); _WM_midi_setup_divisions(hmi_mdi, hmi_division); if ((_WM_MixerOptions & WM_MO_ROUNDTEMPO)) { tempo_f = (float) (60000000 / hmi_bpm) + 0.5f; } else { tempo_f = (float) (60000000 / hmi_bpm); } samples_per_delta_f = _WM_GetSamplesPerTick(hmi_division, (uint32_t)tempo_f); _WM_midi_setup_tempo(hmi_mdi, (uint32_t)tempo_f); hmi_track_offset = (uint32_t *)malloc(sizeof(uint32_t) * hmi_track_cnt); hmi_track_header_length = malloc(sizeof(uint32_t) * hmi_track_cnt); hmi_track_end = malloc(sizeof(uint32_t) * hmi_track_cnt); hmi_delta = malloc(sizeof(uint32_t) * hmi_track_cnt); note = malloc(sizeof(struct _note) * 128 * hmi_track_cnt); hmi_running_event = malloc(sizeof(uint8_t) * 128 * hmi_track_cnt); hmi_data += 370; smallest_delta = 0xffffffff; if (hmi_size < (370 + (hmi_track_cnt * 17))) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0); goto _hmi_end; } hmi_track_offset[0] = *hmi_data; // To keep Xcode happy for (i = 0; i < hmi_track_cnt; i++) { hmi_track_offset[i] = *hmi_data++; hmi_track_offset[i] += (*hmi_data++ << 8); hmi_track_offset[i] += (*hmi_data++ << 16); hmi_track_offset[i] += (*hmi_data++ << 24); if (hmi_size < (hmi_track_offset[i] + 0x5a + 4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0); goto _hmi_end; } hmi_addr = hmi_base + hmi_track_offset[i]; if (memcmp(hmi_addr, "HMI-MIDITRACK", 13)) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_NOT_HMI, NULL, 0); goto _hmi_end; } hmi_track_header_length[i] = hmi_addr[0x57]; hmi_track_header_length[i] += (hmi_addr[0x58] << 8); hmi_track_header_length[i] += (hmi_addr[0x59] << 16); hmi_track_header_length[i] += (hmi_addr[0x5a] << 24); hmi_addr += hmi_track_header_length[i]; hmi_track_offset[i] += hmi_track_header_length[i]; // Get tracks initial delta and set its samples_till_next; hmi_delta[i] = 0; if (*hmi_addr > 0x7f) { do { hmi_delta[i] = (hmi_delta[i] << 7) + (*hmi_addr & 0x7f); hmi_addr++; hmi_track_offset[i]++; } while (*hmi_addr > 0x7f); } hmi_delta[i] = (hmi_delta[i] << 7) + (*hmi_addr & 0x7f); hmi_track_offset[i]++; hmi_addr++; // Find smallest delta to work with if (hmi_delta[i] < smallest_delta) { smallest_delta = hmi_delta[i]; } hmi_track_end[i] = 0; hmi_running_event[i] = 0; for (j = 0; j < 128; j++) { hmi_tmp = (128 * i) + j; note[hmi_tmp].length = 0; note[hmi_tmp].channel = 0; } } subtract_delta = smallest_delta; sample_count_f= (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; hmi_mdi->events[hmi_mdi->event_count - 1].samples_to_next += sample_count; hmi_mdi->extra_info.approx_total_samples += sample_count; while (hmi_tracks_ended < hmi_track_cnt) { smallest_delta = 0; for (i = 0; i < hmi_track_cnt; i++) { if (hmi_track_end[i]) continue; // first check to see if any active notes need turning off. for (j = 0; j < 128; j++) { hmi_tmp = (128 * i) + j; if (note[hmi_tmp].length) { note[hmi_tmp].length -= subtract_delta; if (note[hmi_tmp].length) { if ((!smallest_delta) || (smallest_delta > note[hmi_tmp].length)) { smallest_delta = note[hmi_tmp].length; } } else { _WM_midi_setup_noteoff(hmi_mdi, note[hmi_tmp].channel, j, 0); } } } if (hmi_delta[i]) { hmi_delta[i] -= subtract_delta; if (hmi_delta[i]) { if ((!smallest_delta) || (smallest_delta > hmi_delta[i])) { smallest_delta = hmi_delta[i]; } continue; } } do { hmi_data = hmi_base + hmi_track_offset[i]; hmi_delta[i] = 0; if (hmi_data[0] == 0xfe) { // HMI only event of some sort. if (hmi_data[1] == 0x10) { hmi_tmp = (hmi_data[4] + 5); hmi_data += hmi_tmp; hmi_track_offset[i] += hmi_tmp; } else if (hmi_data[1] == 0x15) { hmi_data += 4; hmi_track_offset[i] += 4; } hmi_data += 4; hmi_track_offset[i] += 4; } else { if ((setup_ret = _WM_SetupMidiEvent(hmi_mdi,hmi_data,hmi_running_event[i])) == 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_CORUPT, "(missing event)", 0); goto _hmi_end; } if ((hmi_data[0] == 0xff) && (hmi_data[1] == 0x2f) && (hmi_data[2] == 0x00)) { hmi_track_end[i] = 1; hmi_tracks_ended++; for(j = 0; j < 128; j++) { hmi_tmp = (128 * i) + j; if (note[hmi_tmp].length) { _WM_midi_setup_noteoff(hmi_mdi, note[hmi_tmp].channel, j, 0); note[hmi_tmp].length = 0; } } goto _hmi_next_track; } // Running event // 0xff does not alter running event if ((*hmi_data == 0xF0) || (*hmi_data == 0xF7)) { // Sysex resets running event data hmi_running_event[i] = 0; } else if (*hmi_data < 0xF0) { // MIDI events 0x80 to 0xEF set running event if (*hmi_data >= 0x80) { hmi_running_event[i] = *hmi_data; } } if ((hmi_running_event[i] & 0xf0) == 0x90) { // note on has extra data to specify how long the note is. if (*hmi_data > 127) { hmi_tmp = hmi_data[1]; } else { hmi_tmp = *hmi_data; } hmi_tmp += (i * 128); note[hmi_tmp].channel = hmi_running_event[i] & 0xf; hmi_data += setup_ret; hmi_track_offset[i] += setup_ret; note[hmi_tmp].length = 0; if (*hmi_data > 0x7f) { do { note[hmi_tmp].length = (note[hmi_tmp].length << 7) | (*hmi_data & 0x7F); hmi_data++; hmi_track_offset[i]++; } while (*hmi_data > 0x7F); } note[hmi_tmp].length = (note[hmi_tmp].length << 7) | (*hmi_data & 0x7F); hmi_data++; hmi_track_offset[i]++; if (note[hmi_tmp].length) { if ((!smallest_delta) || (smallest_delta > note[hmi_tmp].length)) { smallest_delta = note[hmi_tmp].length; } } else { _WM_midi_setup_noteoff(hmi_mdi, note[hmi_tmp].channel, j, 0); } } else { hmi_data += setup_ret; hmi_track_offset[i] += setup_ret; } } // get track delta // hmi_delta[i] = 0; // set at start of loop if (*hmi_data > 0x7f) { do { hmi_delta[i] = (hmi_delta[i] << 7) | (*hmi_data & 0x7F); hmi_data++; hmi_track_offset[i]++; } while (*hmi_data > 0x7F); } hmi_delta[i] = (hmi_delta[i] << 7) | (*hmi_data & 0x7F); hmi_data++; hmi_track_offset[i]++; } while (!hmi_delta[i]); if ((!smallest_delta) || (smallest_delta > hmi_delta[i])) { smallest_delta = hmi_delta[i]; } _hmi_next_track: hmi_tmp = 0; UNUSED(hmi_tmp); } // convert smallest delta to samples till next subtract_delta = smallest_delta; sample_count_f= (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; hmi_mdi->events[hmi_mdi->event_count - 1].samples_to_next += sample_count; hmi_mdi->extra_info.approx_total_samples += sample_count; } if ((hmi_mdi->reverb = _WM_init_reverb(_WM_SampleRate, _WM_reverb_room_width, _WM_reverb_room_length, _WM_reverb_listen_posx, _WM_reverb_listen_posy)) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_MEM, "to init reverb", 0); goto _hmi_end; } hmi_mdi->extra_info.current_sample = 0; hmi_mdi->current_event = &hmi_mdi->events[0]; hmi_mdi->samples_to_mix = 0; hmi_mdi->note = NULL; _WM_ResetToStart(hmi_mdi); _hmi_end: free(hmi_track_offset); free(hmi_track_header_length); free(hmi_track_end); free(hmi_delta); free(note); free(hmi_running_event); if (hmi_mdi->reverb) return (hmi_mdi); _WM_freeMDI(hmi_mdi); return 0; }
/* Turns hmp file data into an event stream */ struct _mdi * _WM_ParseNewHmp(uint8_t *hmp_data, uint32_t hmp_size) { uint8_t is_hmp2 = 0; uint32_t zero_cnt = 0; uint32_t i = 0; uint32_t hmp_file_length = 0; uint32_t hmp_chunks = 0; uint32_t hmp_divisions = 0; uint32_t hmp_unknown = 0; uint32_t hmp_bpm = 0; uint32_t hmp_song_time = 0; struct _mdi *hmp_mdi; uint8_t **hmp_chunk; uint32_t *chunk_length; uint32_t *chunk_ofs; uint32_t *chunk_delta; uint8_t *chunk_end; uint32_t chunk_num = 0; uint32_t hmp_track = 0; // uint32_t j = 0; uint32_t smallest_delta = 0; uint32_t subtract_delta = 0; // uint32_t chunks_finished = 0; uint32_t end_of_chunks = 0; uint32_t var_len_shift = 0; float tempo_f = 500000.0; float samples_per_delta_f = 0.0; // uint8_t hmp_event = 0; // uint8_t hmp_channel = 0; uint32_t sample_count = 0; float sample_count_f = 0; float sample_remainder = 0; if (memcmp(hmp_data, "HMIMIDIP", 8)) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_NOT_HMP, NULL, 0); return NULL; } hmp_data += 8; hmp_size -= 8; if (!memcmp(hmp_data, "013195", 6)) { hmp_data += 6; hmp_size -= 6; is_hmp2 = 1; } // should be a bunch of \0's if (is_hmp2) { zero_cnt = 18; } else { zero_cnt = 24; } for (i = 0; i < zero_cnt; i++) { if (hmp_data[i] != 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_NOT_HMP, NULL, 0); return NULL; } } hmp_data += zero_cnt; hmp_size -= zero_cnt; hmp_file_length = *hmp_data++; hmp_file_length += (*hmp_data++ << 8); hmp_file_length += (*hmp_data++ << 16); hmp_file_length += (*hmp_data++ << 24); hmp_size -= 4; UNUSED(hmp_file_length); // Next 12 bytes are normally \0 so skipping over them hmp_data += 12; hmp_size -= 12; hmp_chunks = *hmp_data++; hmp_chunks += (*hmp_data++ << 8); hmp_chunks += (*hmp_data++ << 16); hmp_chunks += (*hmp_data++ << 24); hmp_size -= 4; // Still decyphering what this is hmp_unknown = *hmp_data++; hmp_unknown += (*hmp_data++ << 8); hmp_unknown += (*hmp_data++ << 16); hmp_unknown += (*hmp_data++ << 24); hmp_size -= 4; UNUSED(hmp_unknown); // Defaulting: experimenting has found this to be the ideal value hmp_divisions = 60; // Beats per minute hmp_bpm = *hmp_data++; hmp_bpm += (*hmp_data++ << 8); hmp_bpm += (*hmp_data++ << 16); hmp_bpm += (*hmp_data++ << 24); hmp_size -= 4; /* Slow but needed for accuracy */ if ((_WM_MixerOptions & WM_MO_ROUNDTEMPO)) { tempo_f = (float) (60000000 / hmp_bpm) + 0.5f; } else { tempo_f = (float) (60000000 / hmp_bpm); } samples_per_delta_f = _WM_GetSamplesPerTick(hmp_divisions, tempo_f); //DEBUG //fprintf(stderr, "DEBUG: Samples Per Delta Tick: %f\r\n",samples_per_delta_f); // FIXME: This value is incorrect hmp_song_time = *hmp_data++; hmp_song_time += (*hmp_data++ << 8); hmp_song_time += (*hmp_data++ << 16); hmp_song_time += (*hmp_data++ << 24); hmp_size -= 4; // DEBUG //fprintf(stderr,"DEBUG: ??DIVISIONS??: %u, BPM: %u, ??SONG TIME??: %u:%.2u\r\n",hmp_divisions, hmp_bpm, (hmp_song_time / 60), (hmp_song_time % 60)); UNUSED(hmp_song_time); if (is_hmp2) { hmp_data += 840; hmp_size -= 840; } else { hmp_data += 712; hmp_size -= 712; } hmp_mdi = _WM_initMDI(); _WM_midi_setup_divisions(hmp_mdi, hmp_divisions); _WM_midi_setup_tempo(hmp_mdi, (uint32_t)tempo_f); hmp_chunk = malloc(sizeof(uint8_t *) * hmp_chunks); chunk_length = malloc(sizeof(uint32_t) * hmp_chunks); chunk_delta = malloc(sizeof(uint32_t) * hmp_chunks); chunk_ofs = malloc(sizeof(uint32_t) * hmp_chunks); chunk_end = malloc(sizeof(uint8_t) * hmp_chunks); smallest_delta = 0xffffffff; // store chunk info for use, and check chunk lengths for (i = 0; i < hmp_chunks; i++) { hmp_chunk[i] = hmp_data; chunk_ofs[i] = 0; chunk_num = *hmp_data++; chunk_num += (*hmp_data++ << 8); chunk_num += (*hmp_data++ << 16); chunk_num += (*hmp_data++ << 24); chunk_ofs[i] += 4; UNUSED(chunk_num); chunk_length[i] = *hmp_data++; chunk_length[i] += (*hmp_data++ << 8); chunk_length[i] += (*hmp_data++ << 16); chunk_length[i] += (*hmp_data++ << 24); chunk_ofs[i] += 4; if (chunk_length[i] > hmp_size) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_NOT_HMP, "file too short", 0); goto _hmp_end; } hmp_size -= chunk_length[i]; hmp_track = *hmp_data++; hmp_track += (*hmp_data++ << 8); hmp_track += (*hmp_data++ << 16); hmp_track += (*hmp_data++ << 24); chunk_ofs[i] += 4; UNUSED(hmp_track); // Start of Midi Data chunk_delta[i] = 0; var_len_shift = 0; if (*hmp_data < 0x80) { do { chunk_delta[i] = chunk_delta[i] | ((*hmp_data++ & 0x7F) << var_len_shift); var_len_shift += 7; chunk_ofs[i]++; } while (*hmp_data < 0x80); } chunk_delta[i] = chunk_delta[i] | ((*hmp_data++ & 0x7F) << var_len_shift); chunk_ofs[i]++; if (chunk_delta[i] < smallest_delta) { smallest_delta = chunk_delta[i]; } // goto start of next chunk hmp_data = hmp_chunk[i] + chunk_length[i]; hmp_chunk[i] += chunk_ofs[i]++; chunk_end[i] = 0; } subtract_delta = smallest_delta; sample_count_f = (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; hmp_mdi->events[hmp_mdi->event_count - 1].samples_to_next += sample_count; hmp_mdi->extra_info.approx_total_samples += sample_count; while (end_of_chunks < hmp_chunks) { smallest_delta = 0; // DEBUG // fprintf(stderr,"DEBUG: Delta Ticks: %u\r\n",subtract_delta); for (i = 0; i < hmp_chunks; i++) { if (chunk_end[i]) continue; if (chunk_delta[i]) { chunk_delta[i] -= subtract_delta; if (chunk_delta[i]) { if ((!smallest_delta) || (smallest_delta > chunk_delta[i])) { smallest_delta = chunk_delta[i]; } continue; } } do { if (((hmp_chunk[i][0] & 0xf0) == 0xb0 ) && ((hmp_chunk[i][1] == 110) || (hmp_chunk[i][1] == 111)) && (hmp_chunk[i][2] > 0x7f)) { // Reserved for loop markers // TODO: still deciding what to do about these hmp_chunk[i] += 3; } else { uint32_t setup_ret = 0; if ((setup_ret = _WM_SetupMidiEvent(hmp_mdi, hmp_chunk[i], 0)) == 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_CORUPT, "(missing event)", 0); goto _hmp_end; } if ((hmp_chunk[i][0] == 0xff) && (hmp_chunk[i][1] == 0x2f) && (hmp_chunk[i][2] == 0x00)) { /* End of Chunk */ end_of_chunks++; chunk_end[i] = 1; hmp_chunk[i] += 3; goto NEXT_CHUNK; } else if ((hmp_chunk[i][0] == 0xff) && (hmp_chunk[i][1] == 0x51) && (hmp_chunk[i][2] == 0x03)) { /* Tempo */ tempo_f = (float)((hmp_chunk[i][3] << 16) + (hmp_chunk[i][4] << 8)+ hmp_chunk[i][5]); if (tempo_f == 0.0) tempo_f = 500000.0; // DEBUG fprintf(stderr,"DEBUG: Tempo change %f\r\n", tempo_f); } hmp_chunk[i] += setup_ret; } var_len_shift = 0; chunk_delta[i] = 0; if (*hmp_chunk[i] < 0x80) { do { chunk_delta[i] = chunk_delta[i] + ((*hmp_chunk[i] & 0x7F) << var_len_shift); var_len_shift += 7; hmp_chunk[i]++; } while (*hmp_chunk[i] < 0x80); } chunk_delta[i] = chunk_delta[i] + ((*hmp_chunk[i] & 0x7F) << var_len_shift); hmp_chunk[i]++; } while (!chunk_delta[i]); if ((!smallest_delta) || (smallest_delta > chunk_delta[i])) { smallest_delta = chunk_delta[i]; } NEXT_CHUNK: continue; } subtract_delta = smallest_delta; sample_count_f= (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; hmp_mdi->events[hmp_mdi->event_count - 1].samples_to_next += sample_count; hmp_mdi->extra_info.approx_total_samples += sample_count; // DEBUG // fprintf(stderr,"DEBUG: Sample Count %u\r\n",sample_count); } if ((hmp_mdi->reverb = _WM_init_reverb(_WM_SampleRate, _WM_reverb_room_width, _WM_reverb_room_length, _WM_reverb_listen_posx, _WM_reverb_listen_posy)) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __FILE__, __LINE__, WM_ERR_MEM, "to init reverb", 0); goto _hmp_end; } hmp_mdi->extra_info.current_sample = 0; hmp_mdi->current_event = &hmp_mdi->events[0]; hmp_mdi->samples_to_mix = 0; hmp_mdi->note = NULL; _WM_ResetToStart(hmp_mdi); _hmp_end: free(hmp_chunk); free(chunk_length); free(chunk_delta); free(chunk_ofs); free(chunk_end); if (hmp_mdi->reverb) return (hmp_mdi); _WM_freeMDI(hmp_mdi); return NULL; }