Commit message: Fix bug #175:

CVE-2017-11661, CVE-2017-11662, CVE-2017-11663, CVE-2017-11664:
Add a new size parameter to _WM_SetupMidiEvent() so that it
knows where to stop reading, and adjust its clients properly.
CVE: CVE-2017-11664
CWE: CWE-125
Vulnerability description: The _WM_SetupMidiEvent function in internal_midi.c:2122 in WildMIDI 0.4.2 can cause a denial of service (invalid memory read and application crash) via a crafted mid file.

Project: wildmidi
File: internal_midi.c

void _WM_do_control_registered_param_fine(struct _mdi *mdi,
                                          struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);
    mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x3F80)
                                | data->data.value;
    mdi->channel[ch].reg_non = 0;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_channel_balance(struct _mdi *mdi,
                                       struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    mdi->channel[ch].balance = data->data.value;
    _WM_AdjustChannelVolumes(mdi, ch);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_instrumentname(struct _mdi *mdi, char * text) {
    MIDI_EVENT_SDEBUG(__FUNCTION__,0, text);
    strip_text(text);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_instrumentname;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.string = text;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_patch(struct _mdi *mdi, uint8_t channel, uint8_t patch) {
    MIDI_EVENT_DEBUG(__FUNCTION__,channel, patch);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_patch;
    mdi->events[mdi->event_count].event_data.channel = channel;
    mdi->events[mdi->event_count].event_data.data.value = patch;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;

    if (mdi->channel[channel].isdrum) {
        mdi->channel[channel].bank = patch;
    } else {
        _WM_load_patch(mdi, ((mdi->channel[channel].bank << 8) | patch));
        mdi->channel[channel].patch = _WM_get_patch_data(mdi,
                                                     ((mdi->channel[channel].bank << 8) | patch));
    }
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data) {
    int i;

    if (data != NULL) {
        MIDI_EVENT_DEBUG(__FUNCTION__,data->channel, data->data.value);
    } else {
        MIDI_EVENT_DEBUG(__FUNCTION__,0, 0);
    }

    for (i = 0; i < 16; i++) {
        mdi->channel[i].bank = 0;
        if (i != 9) {
            mdi->channel[i].patch = _WM_get_patch_data(mdi, 0);
        } else {
            mdi->channel[i].patch = NULL;
        }
        mdi->channel[i].hold = 0;
        mdi->channel[i].volume = 100;
        mdi->channel[i].pressure = 127;
        mdi->channel[i].expression = 127;
        mdi->channel[i].balance = 64;
        mdi->channel[i].pan = 64;
        mdi->channel[i].pitch = 0;
        mdi->channel[i].pitch_range = 200;
        mdi->channel[i].reg_data = 0xFFFF;
        mdi->channel[i].isdrum = 0;
    }
    /* I would not expect notes to be active when this event
     triggers but we'll adjust active notes as well just in case */
    _WM_AdjustChannelVolumes(mdi,16); // A setting > 15 adjusts all channels

    mdi->channel[9].isdrum = 1;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_data_increment(struct _mdi *mdi,
                                      struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if ((mdi->channel[ch].reg_non == 0)
        && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */
        if (mdi->channel[ch].pitch_range < 0x3FFF)
            mdi->channel[ch].pitch_range++;
    }
}

Project: wildmidi
File: f_midi.c

_WM_ParseNewMidi(uint8_t *midi_data, uint32_t midi_size) {
    struct _mdi *mdi;

    uint32_t tmp_val;
    uint32_t midi_type;
    uint8_t **tracks;
    uint32_t *track_size;
    uint32_t end_of_tracks = 0;
    uint32_t no_tracks;
    uint32_t i;
    uint32_t divisions = 96;
    uint32_t tempo = 500000;
    float samples_per_delta_f = 0.0;

    uint32_t sample_count = 0;
    float sample_count_f = 0.0;
    float sample_remainder = 0.0;
    uint8_t *sysex_store = NULL;

    uint32_t *track_delta;
    uint8_t *track_end;
    uint32_t smallest_delta = 0;
    uint32_t subtract_delta = 0;
    uint8_t *running_event;
    uint32_t setup_ret = 0;

    if (midi_size < 14) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
        return (NULL);
    }

    if (!memcmp(midi_data, "RIFF", 4)) {
        if (midi_size < 34) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
            return (NULL);
        }
        midi_data += 20;
        midi_size -= 20;
    }

    if (memcmp(midi_data, "MThd", 4)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MIDI, NULL, 0);
        return (NULL);
    }
    midi_data += 4;
    midi_size -= 4;

    /*
     * Get Midi Header Size - must always be 6
     */
    tmp_val = *midi_data++ << 24;
    tmp_val |= *midi_data++ << 16;
    tmp_val |= *midi_data++ << 8;
    tmp_val |= *midi_data++;
    midi_size -= 4;
    if (tmp_val != 6) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, NULL, 0);
        return (NULL);
    }

    /*
     * Get Midi Format - we only support 0, 1 & 2
     */
    tmp_val = *midi_data++ << 8;
    tmp_val |= *midi_data++;
    midi_size -= 2;
    if (tmp_val > 2) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0);
        return (NULL);
    }
    midi_type = tmp_val;

    /*
     * Get No. of Tracks
     */
    tmp_val = *midi_data++ << 8;
    tmp_val |= *midi_data++;
    midi_size -= 2;
    if (tmp_val < 1) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(no tracks)", 0);
        return (NULL);
    }
    no_tracks = tmp_val;

    /*
     * Check that type 0 midi file has only 1 track
     */
    if ((midi_type == 0) && (no_tracks > 1)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(expected 1 track for type 0 midi file, found more)", 0);
        return (NULL);
    }

    /*
     * Get Divisions
     */
    divisions = *midi_data++ << 8;
    divisions |= *midi_data++;
    midi_size -= 2;
    if (divisions & 0x00008000) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0);
        return (NULL);
    }

    samples_per_delta_f = _WM_GetSamplesPerTick(divisions, tempo);

    mdi = _WM_initMDI();
    _WM_midi_setup_divisions(mdi,divisions);

    tracks = malloc(sizeof(uint8_t *) * no_tracks);
    track_size = malloc(sizeof(uint32_t) * no_tracks);
    track_delta = malloc(sizeof(uint32_t) * no_tracks);
    track_end = malloc(sizeof(uint8_t) * no_tracks);
    running_event = malloc(sizeof(uint8_t) * no_tracks);

    smallest_delta = 0xffffffff;
    for (i = 0; i < no_tracks; i++) {
        if (midi_size < 8) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
            goto _end;
        }
        if (memcmp(midi_data, "MTrk", 4) != 0) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing track header)", 0);
            goto _end;
        }
        midi_data += 4;
        midi_size -= 4;

        /* track size */
        tmp_val = *midi_data++ << 24;
        tmp_val |= *midi_data++ << 16;
        tmp_val |= *midi_data++ << 8;
        tmp_val |= *midi_data++;
        midi_size -= 4;
        if (midi_size < tmp_val) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
            goto _end;
        }
        if (tmp_val < 3) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(bad track size)", 0);
            goto _end;
        }
        if ((midi_data[tmp_val - 3] != 0xFF)
                || (midi_data[tmp_val - 2] != 0x2F)
                || (midi_data[tmp_val - 1] != 0x00)) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing EOT)", 0);
            goto _end;
        }
        tracks[i] = midi_data;
        track_size[i] = tmp_val;
        midi_data += tmp_val;
        midi_size -= tmp_val;
        track_end[i] = 0;
        running_event[i] = 0;
        track_delta[i] = 0;

        while (*tracks[i] > 0x7F) {
            track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F);
            tracks[i]++;
            track_size[i]--;
        }
        track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F);
        tracks[i]++;
        track_size[i]--;

        if (midi_type == 1 ) {
            if (track_delta[i] < smallest_delta) {
                smallest_delta = track_delta[i];
            }
        } else {
            /*
             * Type 0 & 2 midi only needs delta from 1st track
             * for initial sample calculations.
             */
            if (i == 0) smallest_delta = track_delta[i];
        }
    }

    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;

    mdi->events[mdi->event_count - 1].samples_to_next += sample_count;
    mdi->extra_info.approx_total_samples += sample_count;

    /*
     * Handle type 0 & 2 the same, but type 1 differently
     */
    if (midi_type == 1) {
        /* Type 1 */
        while (end_of_tracks != no_tracks) {
            smallest_delta = 0;
            for (i = 0; i < no_tracks; i++) {
                if (track_end[i])
                    continue;
                if (track_delta[i]) {
                    track_delta[i] -= subtract_delta;
                    if (track_delta[i]) {
                        if ((!smallest_delta)
                             || (smallest_delta > track_delta[i])) {
                            smallest_delta = track_delta[i];
                        }
                        continue;
                    }
                }
                do {
                    setup_ret = _WM_SetupMidiEvent(mdi, tracks[i], track_size[i], running_event[i]);
                    if (setup_ret == 0) {
                        goto _end;
                    }
                    if (tracks[i][0] > 0x7f) {
                        if (tracks[i][0] < 0xf0) {
                            /* Events 0x80 - 0xef set running event */
                            running_event[i] = tracks[i][0];
                        } else if ((tracks[i][0] == 0xf0) || (tracks[i][0] == 0xf7)) {
                            /* Sysex resets running event */
                            running_event[i] = 0;
                        } else if ((tracks[i][0] == 0xff) && (tracks[i][1] == 0x2f) && (tracks[i][2] == 0x00)) {
                            /* End of Track */
                            end_of_tracks++;
                            track_end[i] = 1;
                            tracks[i] += 3;
                            track_size[i] -= 3;
                            goto NEXT_TRACK;
                        } else if ((tracks[i][0] == 0xff) && (tracks[i][1] == 0x51) && (tracks[i][2] == 0x03)) {
                            /* Tempo */
                            tempo = (tracks[i][3] << 16) + (tracks[i][4] << 8)+ tracks[i][5];
                            if (!tempo)
                                tempo = 500000;

                            samples_per_delta_f = _WM_GetSamplesPerTick(divisions, tempo);
                        }
                    }
                    tracks[i] += setup_ret;
                    track_size[i] -= setup_ret;

                    if (*tracks[i] > 0x7f) {
                        do {
                            if (!track_size[i]) break;
                            track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F);
                            tracks[i]++;
                            track_size[i]--;
                        } while (*tracks[i] > 0x7f);
                    }
                    if (!track_size[i]) {
                        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
                        goto _end;
                    }
                    track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F);
                    tracks[i]++;
                    track_size[i]--;
                } while (!track_delta[i]);
                if ((!smallest_delta) || (smallest_delta > track_delta[i])) {
                    smallest_delta = track_delta[i];
                }
            NEXT_TRACK: 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;

            mdi->events[mdi->event_count - 1].samples_to_next += sample_count;
            mdi->extra_info.approx_total_samples += sample_count;
        }
    } else {
        /* Type 0 & 2 */
        if (midi_type == 2) {
            mdi->is_type2 = 1;
        }
        sample_remainder = 0.0;
        for (i = 0; i < no_tracks; i++) {
            running_event[i] = 0;
            do {
                setup_ret = _WM_SetupMidiEvent(mdi, tracks[i], track_size[i], running_event[i]);
                if (setup_ret == 0) {
                    goto _end;
                }
                if (tracks[i][0] > 0x7f) {
                    if (tracks[i][0] < 0xf0) {
                        /* Events 0x80 - 0xef set running event */
                        running_event[i] = tracks[i][0];
                    } else if ((tracks[i][0] == 0xf0) || (tracks[i][0] == 0xf7)) {
                        /* Sysex resets running event */
                        running_event[i] = 0;
                    } else if ((tracks[i][0] == 0xff) && (tracks[i][1] == 0x2f) && (tracks[i][2] == 0x00)) {
                        /* End of Track */
                        track_end[i] = 1;
                        goto NEXT_TRACK2;
                    } else if ((tracks[i][0] == 0xff) && (tracks[i][1] == 0x51) && (tracks[i][2] == 0x03)) {
                        /* Tempo */
                        tempo = (tracks[i][3] << 16) + (tracks[i][4] << 8)+ tracks[i][5];
                        if (!tempo)
                            tempo = 500000;

                        samples_per_delta_f = _WM_GetSamplesPerTick(divisions, tempo);
                    }
                }
                tracks[i] += setup_ret;
                track_size[i] -= setup_ret;

                track_delta[i] = 0;
                if (*tracks[i] > 0x7f) {
                    do {
                        if (!track_size[i]) break;
                        track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F);
                        tracks[i]++;
                        track_size[i]--;
                    } while (*tracks[i] > 0x7f);
                }
                if (!track_size[i]) {
                    _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
                    goto _end;
                }
                track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F);
                tracks[i]++;
                track_size[i]--;

                sample_count_f = (((float) track_delta[i] * samples_per_delta_f)
                                  + sample_remainder);
                sample_count = (uint32_t) sample_count_f;
                sample_remainder = sample_count_f - (float) sample_count;
                mdi->events[mdi->event_count - 1].samples_to_next += sample_count;
                mdi->extra_info.approx_total_samples += sample_count;
            NEXT_TRACK2:
                smallest_delta = track_delta[i]; /* Added just to keep Xcode happy */
                UNUSED(smallest_delta); /* Added to just keep clang happy */
            } while (track_end[i] == 0);
        }
    }

    if ((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 _end;
    }

    mdi->extra_info.current_sample = 0;
    mdi->current_event = &mdi->events[0];
    mdi->samples_to_mix = 0;
    mdi->note = NULL;

    _WM_ResetToStart(mdi);

_end:   free(sysex_store);
    free(track_end);
    free(track_delta);
    free(running_event);
    free(tracks);
    free(track_size);
    if (mdi->reverb) return (mdi);
    _WM_freeMDI(mdi);
    return (NULL);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_sysex_roland_drum_track(struct _mdi *mdi, struct _event_data *data) {
    uint8_t ch = data->channel;

    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if (data->data.value > 0) {
        mdi->channel[ch].isdrum = 1;
        mdi->channel[ch].patch = NULL;
    } else {
        mdi->channel[ch].isdrum = 0;
        mdi->channel[ch].patch = _WM_get_patch_data(mdi, 0);
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_ResetToStart(struct _mdi *mdi) {
    struct _event * event = NULL;

    mdi->current_event = mdi->events;
    mdi->samples_to_mix = 0;
    mdi->extra_info.current_sample = 0;

    _WM_do_sysex_gm_reset(mdi, NULL);

    /* Ensure last event is NULL */
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = NULL;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = 0;
    mdi->events[mdi->event_count].samples_to_next = 0;

    if (_WM_MixerOptions & WM_MO_STRIPSILENCE) {
        event = mdi->events;
        /* Scan for first note on removing any samples as we go */
        if (event->do_event != *_WM_do_note_on) {
            do {
                if (event->samples_to_next != 0) {
                    mdi->extra_info.approx_total_samples -= event->samples_to_next;
                    event->samples_to_next = 0;
                }
                event++;
                if (event == NULL) break;
            } while (event->do_event != *_WM_do_note_on);
        }

        /* Reverse scan for last note off removing any samples as we go */
        event = &mdi->events[mdi->event_count - 1];
        if (event->do_event != *_WM_do_note_off) {
            do {
                mdi->extra_info.approx_total_samples -= event->samples_to_next;
                event->samples_to_next = 0;
                if (event == mdi->events) break; /* just to be safe */
                event--;
            } while (event->do_event != *_WM_do_note_off);
        }
        mdi->extra_info.approx_total_samples -= event->samples_to_next;
        event->samples_to_next = 0;
    }
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_sysex_yamaha_reset(struct _mdi *mdi) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0,0);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_sysex_roland_reset;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = 0;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_sysex_gm_reset(struct _mdi *mdi) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0,0);

    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_sysex_roland_reset;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = 0;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_sysex_roland_drum_track(struct _mdi *mdi,
                                              uint8_t channel, uint16_t setting) {
    MIDI_EVENT_DEBUG(__FUNCTION__,channel, setting);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = _WM_do_sysex_roland_drum_track;
    mdi->events[mdi->event_count].event_data.channel = channel;
    mdi->events[mdi->event_count].event_data.data.value = setting;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;

    if (setting > 0) {
        mdi->channel[channel].isdrum = 1;
    } else {
        mdi->channel[channel].isdrum = 0;
    }
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_channel_sound_off(struct _mdi *mdi,
                                      struct _event_data *data) {
    struct _note *note_data = mdi->note;
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if (note_data) {
        do {
            if ((note_data->noteid >> 8) == ch) {
                note_data->active = 0;
                if (note_data->replay) {
                    note_data->replay = NULL;
                }
            }
            note_data = note_data->next;
        } while (note_data);
    }
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_sysex_roland_reset(struct _mdi *mdi) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0,0);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_sysex_roland_reset;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = 0;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_timesignature(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_trackname(struct _mdi *mdi, char * text) {
    MIDI_EVENT_SDEBUG(__FUNCTION__,0, text);
    strip_text(text);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_trackname;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.string = text;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_instrumentname(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

int _WM_midi_setup_tempo(struct _mdi *mdi, uint32_t setting) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0,setting);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_tempo;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = setting;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_non_registered_param_fine(struct _mdi *mdi,
                                            struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);
    mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x3F80)
                                | data->data.value;
    mdi->channel[ch].reg_non = 1;
}

Project: wildmidi
File: internal_midi.c

static void _WM_CheckEventMemoryPool(struct _mdi *mdi) {
    if ((mdi->event_count + 1) >= mdi->events_size) {
        mdi->events_size += MEM_CHUNK;
        mdi->events = realloc(mdi->events,
                              (mdi->events_size * sizeof(struct _event)));
    }
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_sequenceno(struct _mdi *mdi, uint32_t setting) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0, setting);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_sequenceno;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = setting;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static void strip_text(char * text) {
    char * ch_loc = NULL;

    ch_loc = strrchr(text, '\n');
    while (ch_loc != NULL) {
        *ch_loc = ' ';
        ch_loc = strrchr(text, '\n');
    }
    ch_loc = strrchr(text, '\r');
    while (ch_loc != NULL) {
        *ch_loc = ' ';
        ch_loc = strrchr(text, '\r');
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_channel_volume(struct _mdi *mdi,
                                      struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    mdi->channel[ch].volume = data->data.value;
    _WM_AdjustChannelVolumes(mdi, ch);
}

Project: wildmidi
File: internal_midi.c

void _WM_AdjustChannelVolumes(struct _mdi *mdi, uint8_t ch) {
    struct _note *nte = mdi->note;
    if (nte != NULL) {
        do {
            if (ch <= 15) {
                if ((nte->noteid >> 8) == ch) {
                    goto _DO_ADJUST;
                }
            } else {
            _DO_ADJUST:
                if (!nte->ignore_chan_events) {
                    _WM_AdjustNoteVolumes(mdi, ch, nte);
                    if (nte->replay) _WM_AdjustNoteVolumes(mdi, ch, nte->replay);
                }
            }
            nte = nte->next;
        } while (nte != NULL);
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_text(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string);
#endif
    if (mdi->extra_info.mixer_options & WM_MO_TEXTASLYRIC) {
        mdi->lyric = data->data.string;
    }

    return;
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_aftertouch(struct _mdi *mdi, uint8_t channel,
                                 uint8_t note, uint8_t pressure) {
    MIDI_EVENT_DEBUG(__FUNCTION__,channel, note);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_aftertouch;
    mdi->events[mdi->event_count].event_data.channel = channel;
    mdi->events[mdi->event_count].event_data.data.value = (note << 8) | pressure;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_channel_expression(struct _mdi *mdi,
                                          struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    mdi->channel[ch].expression = data->data.value;
    _WM_AdjustChannelVolumes(mdi, ch);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_data_entry_course(struct _mdi *mdi,
                                         struct _event_data *data) {
    uint8_t ch = data->channel;
    int data_tmp;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if ((mdi->channel[ch].reg_non == 0)
        && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */
        data_tmp = mdi->channel[ch].pitch_range % 100;
        mdi->channel[ch].pitch_range = data->data.value * 100 + data_tmp;
    /*  printf("Data Entry Course: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/
    /*  printf("Data Entry Course: data %li\n\r",data->data.value);*/
    }
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_marker(struct _mdi *mdi, char * text) {
    MIDI_EVENT_SDEBUG(__FUNCTION__,0, text);
    strip_text(text);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_marker;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.string = text;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_data_decrement(struct _mdi *mdi,
                                      struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if ((mdi->channel[ch].reg_non == 0)
        && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */
        if (mdi->channel[ch].pitch_range > 0)
            mdi->channel[ch].pitch_range--;
    }
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_copyright(struct _mdi *mdi, char * text) {
    MIDI_EVENT_SDEBUG(__FUNCTION__,0, text);
    strip_text(text);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_copyright;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.string = text;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_channel_pan(struct _mdi *mdi, struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    mdi->channel[ch].pan = data->data.value;
    _WM_AdjustChannelVolumes(mdi, ch);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_control(struct _mdi *mdi, uint8_t channel,
                              uint8_t controller, uint8_t setting) {
    void (*tmp_event)(struct _mdi *mdi, struct _event_data *data) = NULL;
    MIDI_EVENT_DEBUG(__FUNCTION__,channel, controller);

    switch (controller) {
        /*
         **********************************************************************
         FIXME: Need to add dummy events for MIDI events we don't support.
         There is no reason not to store unsupported events in light of our
         out to midi option.
         **********************************************************************
         */
        case 0:
            tmp_event = *_WM_do_control_bank_select;
            mdi->channel[channel].bank = setting;
            break;
        case 6:
            tmp_event = *_WM_do_control_data_entry_course;
            break;
        case 7:
            tmp_event = *_WM_do_control_channel_volume;
            mdi->channel[channel].volume = setting;
            break;
        case 8:
            tmp_event = *_WM_do_control_channel_balance;
            break;
        case 10:
            tmp_event = *_WM_do_control_channel_pan;
            break;
        case 11:
            tmp_event = *_WM_do_control_channel_expression;
            break;
        case 38:
            tmp_event = *_WM_do_control_data_entry_fine;
            break;
        case 64:
            tmp_event = *_WM_do_control_channel_hold;
            break;
        case 96:
            tmp_event = *_WM_do_control_data_increment;
            break;
        case 97:
            tmp_event = *_WM_do_control_data_decrement;
            break;
        case 98:
            tmp_event = *_WM_do_control_non_registered_param_fine;
            break;
        case 99:
            tmp_event = *_WM_do_control_non_registered_param_course;
            break;
        case 100:
            tmp_event = *_WM_do_control_registered_param_fine;
            break;
        case 101:
            tmp_event = *_WM_do_control_registered_param_course;
            break;
        case 120:
            tmp_event = *_WM_do_control_channel_sound_off;
            break;
        case 121:
            tmp_event = *_WM_do_control_channel_controllers_off;
            break;
        case 123:
            tmp_event = *_WM_do_control_channel_notes_off;
            break;
        default:
            tmp_event = *_WM_do_control_dummy;
            break;
    }

    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = tmp_event;
    mdi->events[mdi->event_count].event_data.channel = channel;
    if (tmp_event != *_WM_do_control_dummy) {
        mdi->events[mdi->event_count].event_data.data.value = setting;
    } else {
        mdi->events[mdi->event_count].event_data.data.value = (controller << 8) | setting;
    }
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_registered_param_course(struct _mdi *mdi,
                                            struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);
    mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x7F)
                                | (data->data.value << 7);
    mdi->channel[ch].reg_non = 0;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) {
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    _WM_do_sysex_gm_reset(mdi,data);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_endoftrack(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record eot in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif

    _WM_Release_Allowance(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

void _WM_AdjustNoteVolumes(struct _mdi *mdi, uint8_t ch, struct _note *nte) {
    float premix_dBm;
    float premix_lin;
    uint8_t pan_ofs;
    float premix_dBm_left;
    float premix_dBm_right;
    float premix_left;
    float premix_right;
    float volume_adj;
    uint32_t vol_ofs;

    /*
     Pointless CPU heating checks to shoosh up a compiler
     */
    if (ch > 0x0f) ch = 0x0f;

    if (nte->ignore_chan_events) return;

    pan_ofs = mdi->channel[ch].balance + mdi->channel[ch].pan - 64;

    vol_ofs = (nte->velocity * ((mdi->channel[ch].expression * mdi->channel[ch].volume) / 127)) / 127;

    /*
     This value is to reduce the chance of clipping.
     Higher value means lower overall volume,
     Lower value means higher overall volume.
     NOTE: The lower the value the higher the chance of clipping.
     FIXME: Still needs tuning. Clipping heard at a value of 3.75
     */
#define VOL_DIVISOR 4.0
    volume_adj = ((float)_WM_MasterVolume / 1024.0) / VOL_DIVISOR;

    MIDI_EVENT_DEBUG(__FUNCTION__,ch, 0);

    if (pan_ofs > 127) pan_ofs = 127;
    premix_dBm_left = dBm_pan_volume[(127-pan_ofs)];
    premix_dBm_right = dBm_pan_volume[pan_ofs];

    if (mdi->extra_info.mixer_options & WM_MO_LOG_VOLUME) {
        premix_dBm = dBm_volume[vol_ofs];

        premix_dBm_left += premix_dBm;
        premix_dBm_right += premix_dBm;

        premix_left = (powf(10.0,(premix_dBm_left / 20.0))) * volume_adj;
        premix_right = (powf(10.0,(premix_dBm_right / 20.0))) * volume_adj;
    } else {
        premix_lin = (float)(_WM_lin_volume[vol_ofs]) / 1024.0;

        premix_left = premix_lin * powf(10.0, (premix_dBm_left / 20)) * volume_adj;
        premix_right = premix_lin * powf(10.0, (premix_dBm_right / 20)) * volume_adj;
    }
    nte->left_mix_volume = (int32_t)(premix_left * 1024.0);
    nte->right_mix_volume = (int32_t)(premix_right * 1024.0);
}

Project: wildmidi
File: f_mus.c

_WM_ParseNewMus(uint8_t *mus_data, uint32_t mus_size) {
    uint8_t mus_hdr[] = { 'M', 'U', 'S', 0x1A };
    uint32_t mus_song_ofs = 0;
    uint32_t mus_song_len = 0;
    uint16_t mus_ch_cnt1 = 0;
    uint16_t mus_ch_cnt2 = 0;
    uint16_t mus_no_instr = 0;
    uint32_t mus_data_ofs = 0;
    uint16_t * mus_mid_instr = NULL;
    uint16_t mus_instr_cnt = 0;
    struct _mdi *mus_mdi;
    uint32_t mus_divisions = 60;
    float tempo_f = 0.0;
    uint16_t mus_freq = 0;
    float samples_per_tick_f = 0.0;
#define MUS_SZ 4
    uint8_t mus_event[MUS_SZ] = { 0, 0, 0, 0 };
    uint8_t mus_event_size = 0;
    uint8_t mus_prev_vol[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    uint32_t setup_ret = 0;
    uint32_t mus_ticks = 0;
    uint32_t sample_count = 0;
    float sample_count_f = 0.0;
    float sample_remainder = 0.0;
    uint16_t pitchbend_tmp = 0;

    if (mus_size < 17) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, "File too short", 0);
        return NULL;
    }

    if (memcmp(mus_data, mus_hdr, 4)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, NULL, 0);
        return NULL;
    }

    // Get Song Length
    mus_song_len = (mus_data[5] << 8) | mus_data[4];
    // Get Song Offset
    mus_song_ofs = (mus_data[7] << 8) | mus_data[6];

    // Have yet to determine what this actually is.
    mus_ch_cnt1 = (mus_data[9] << 8) | mus_data[8];
    mus_ch_cnt2 = (mus_data[11] << 8) | mus_data[10];

    UNUSED(mus_ch_cnt1);
    UNUSED(mus_ch_cnt2);

    // Number of instruments defined
    mus_no_instr = (mus_data[13] << 8) | mus_data[12];

    // Skip next 2 data bytes
    mus_data_ofs = 16;

    // Check that we have enough data to check the rest
    if (mus_size < (mus_data_ofs + (mus_no_instr << 1) + mus_song_len)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, "File too short", 0);
        return NULL;
    }

    // Instrument definition
    mus_mid_instr = malloc(mus_no_instr * sizeof(uint16_t));
    for (mus_instr_cnt = 0; mus_instr_cnt < mus_no_instr; mus_instr_cnt++) {
        mus_mid_instr[mus_instr_cnt] = (mus_data[mus_data_ofs + 1] << 8) | mus_data[mus_data_ofs];
        mus_data_ofs += 2;
    }

    // make sure we are at song offset
    mus_data_ofs = mus_song_ofs;

    // do some calculations so we know how many samples per mus tick
    mus_freq = _cvt_get_option(WM_CO_FREQUENCY);
    if (mus_freq == 0) mus_freq = 140;

    if ((_WM_MixerOptions & WM_MO_ROUNDTEMPO)) {
        tempo_f = (float) (60000000 / mus_freq) + 0.5f;
    } else {
        tempo_f = (float) (60000000 / mus_freq);
    }

    samples_per_tick_f = _WM_GetSamplesPerTick(mus_divisions, (uint32_t)tempo_f);

    // initialise the mdi structure
    mus_mdi = _WM_initMDI();
    _WM_midi_setup_divisions(mus_mdi, mus_divisions);
    _WM_midi_setup_tempo(mus_mdi, (uint32_t)tempo_f);

    // lets do this
    do {
        // Build the event
    _mus_build_event:
#if 1
        // Mus drums happen on channel 15, swap channel 9 & 15
        // DEBUG
        MUS_EVENT_DEBUG("Before", mus_data[mus_data_ofs], 0);

        if ((mus_data[mus_data_ofs] & 0x0f) == 0x0f) {
            mus_data[mus_data_ofs] = (mus_data[mus_data_ofs] & 0xf0) | 0x09;
        } else if ((mus_data[mus_data_ofs] & 0x0f) == 0x09) {
            mus_data[mus_data_ofs] = (mus_data[mus_data_ofs] & 0xf0) | 0x0f;
        }
        // DEBUG
        MUS_EVENT_DEBUG("After", mus_data[mus_data_ofs], 0);
#endif
        switch ((mus_data[mus_data_ofs] >> 4) & 0x07) {
            case 0: // Note Off
                mus_event_size = 2;
                mus_event[0] = 0x80 | (mus_data[mus_data_ofs] & 0x0f);
                mus_event[1] = mus_data[mus_data_ofs + 1];
                mus_event[2] = 0;
                mus_event[3] = 0;
                break;
            case 1: // Note On
                if (mus_data[mus_data_ofs + 1] & 0x80) {
                    mus_event_size = 3;
                    mus_event[0] = 0x90 | (mus_data[mus_data_ofs] & 0x0f);
                    mus_event[1] = mus_data[mus_data_ofs + 1] & 0x7f;
                    mus_event[2] = mus_data[mus_data_ofs + 2];
                    mus_event[3] = 0;
                    mus_prev_vol[mus_data[mus_data_ofs] & 0x0f] = mus_event[2];
                } else {
                    mus_event_size = 2;
                    mus_event[0] = 0x90 | (mus_data[mus_data_ofs] & 0x0f);
                    mus_event[1] = mus_data[mus_data_ofs + 1];
                    mus_event[2] = mus_prev_vol[mus_data[mus_data_ofs] & 0x0f];
                    mus_event[3] = 0;
                }
                break;
            case 2: // Pitch Bend
                mus_event_size = 2;
                mus_event[0] = 0xe0 | (mus_data[mus_data_ofs] & 0x0f);

                pitchbend_tmp = mus_data[mus_data_ofs + 1] << 6;
                mus_event[1] = pitchbend_tmp & 0x7f;
                mus_event[2] = (pitchbend_tmp >> 7) & 0x7f;
                mus_event[3] = 0;
                break;
            case 3:
                mus_event_size = 2;
                switch (mus_data[mus_data_ofs + 1]) {
                    case 10: // All Sounds Off
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 120;
                        mus_event[2] = 0;
                        mus_event[3] = 0;
                        break;
                    case 11: // All Notes Off
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 123;
                        mus_event[2] = 0;
                        mus_event[3] = 0;
                        break;
                    case 12: // Mono (Not supported by WildMIDI)
                        /*
                         **************************
                         FIXME: Add dummy mdi event
                         **************************
                         */
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 126;
                        mus_event[2] = 0;
                        mus_event[3] = 0;
                        break;
                    case 13: // Poly (Not supported by WildMIDI)
                        /*
                         **************************
                         FIXME: Add dummy mdi event
                         **************************
                         */
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 127;
                        mus_event[2] = 0;
                        mus_event[3] = 0;
                        break;
                    case 14: // Reset All Controllers
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 121;
                        mus_event[2] = 0;
                        mus_event[3] = 0;
                        break;
                    default: // Unsupported
                        goto _mus_next_data;
                }
                break;
            case 4:
                mus_event_size = 3;
                switch (mus_data[mus_data_ofs + 1]) {
                    case 0: // Patch
                        /*
                         *************************************************
                         FIXME: Check if setting is MIDI or MUS instrument
                         *************************************************
                         */
                        mus_event[0] = 0xc0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = mus_data[mus_data_ofs + 2];
                        mus_event[2] = 0;
                        mus_event[3] = 0;
                        break;
                    case 1: // Bank Select
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 0;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    case 2: // Modulation (Not supported by WildMidi)
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 1;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    case 3: // Volume
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 7;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    case 4: // Pan
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 10;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    case 5: // Expression
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 11;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    case 6: // Reverb (Not supported by WildMidi)
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 91;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    case 7: // Chorus (Not supported by WildMidi)
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 93;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    case 8: // Sustain
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 64;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    case 9: // Soft Peddle (Not supported by WildMidi)
                        mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f);
                        mus_event[1] = 67;
                        mus_event[2] = mus_data[mus_data_ofs + 2];
                        mus_event[3] = 0;
                        break;
                    default: // Unsupported
                        goto _mus_next_data;
                }
                break;
            case 5:
                mus_event_size = 1;
                goto _mus_next_data;
                break;
            case 6:
                goto _mus_end_of_song;
                break;
            case 7:
                mus_event_size = 1;
                goto _mus_next_data;
                break;
        }

        setup_ret = _WM_SetupMidiEvent(mus_mdi, (uint8_t *)mus_event, MUS_SZ, 0);
        if (setup_ret == 0) {
            goto _mus_end;
        }

    _mus_next_data:
        if (!(mus_data[mus_data_ofs] & 0x80)) {
            mus_data_ofs += mus_event_size;
            goto _mus_build_event;

        }
        mus_data_ofs += mus_event_size;

        mus_ticks = 0;
        do {
            mus_ticks = (mus_ticks << 7) | (mus_data[mus_data_ofs++] & 0x7f);
        } while (mus_data[mus_data_ofs - 1] & 0x80);

        sample_count_f = ((float)mus_ticks * samples_per_tick_f) + sample_remainder;
        sample_count = (uint32_t)sample_count_f;
        sample_remainder = sample_count_f - (float)sample_count;

        mus_mdi->events[mus_mdi->event_count - 1].samples_to_next = sample_count;
        mus_mdi->extra_info.approx_total_samples += sample_count;

    } while (mus_data_ofs < mus_size);

_mus_end_of_song:
    // Finalise mdi structure
    if ((mus_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 _mus_end;
    }
    _WM_midi_setup_endoftrack(mus_mdi);
    mus_mdi->extra_info.current_sample = 0;
    mus_mdi->current_event = &mus_mdi->events[0];
    mus_mdi->samples_to_mix = 0;
    mus_mdi->note = NULL;

    _WM_ResetToStart(mus_mdi);

_mus_end:
    free(mus_mid_instr);
    if (mus_mdi->reverb) return (mus_mdi);
    _WM_freeMDI(mus_mdi);
    return NULL;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_channel_controllers_off(struct _mdi *mdi,
                                            struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    mdi->channel[ch].expression = 127;
    mdi->channel[ch].pressure = 127;
    mdi->channel[ch].reg_data = 0xffff;
    mdi->channel[ch].pitch_range = 200;
    mdi->channel[ch].pitch = 0;
    mdi->channel[ch].pitch_adjust = 0;
    mdi->channel[ch].hold = 0;

    _WM_AdjustChannelVolumes(mdi, ch);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_note_on(struct _mdi *mdi, struct _event_data *data) {
    struct _note *nte;
    struct _note *prev_nte;
    struct _note *nte_array;
    uint32_t freq = 0;
    struct _patch *patch;
    struct _sample *sample;
    uint8_t ch = data->channel;
    uint8_t note = (data->data.value >> 8);
    uint8_t velocity = (data->data.value & 0xFF);

    if (velocity == 0x00) {
        _WM_do_note_off(mdi, data);
        return;
    }

    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if (!mdi->channel[ch].isdrum) {
        patch = mdi->channel[ch].patch;
        if (patch == NULL) {
            return;
        }
        freq = _WM_freq_table[(note % 12) * 100] >> (10 - (note / 12));
    } else {
        patch = _WM_get_patch_data(mdi,
                               ((mdi->channel[ch].bank << 8) | note | 0x80));
        if (patch == NULL) {
            return;
        }
        if (patch->note) {
            freq = _WM_freq_table[(patch->note % 12) * 100]
            >> (10 - (patch->note / 12));
        } else {
            freq = _WM_freq_table[(note % 12) * 100] >> (10 - (note / 12));
        }
    }

    sample = _WM_get_sample_data(patch, (freq / 100));
    if (sample == NULL) {
        return;
    }

    nte = &mdi->note_table[0][ch][note];

    if (nte->active) {
        if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3)
            && (!(nte->hold & HOLD_OFF)))
            return;
        nte->replay = &mdi->note_table[1][ch][note];
        nte->env = 6;
        nte->env_inc = -nte->sample->env_rate[6];
        nte = nte->replay;
    } else {
        if (mdi->note_table[1][ch][note].active) {
            if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3)
                && (!(nte->hold & HOLD_OFF)))
                return;
            mdi->note_table[1][ch][note].replay = nte;
            mdi->note_table[1][ch][note].env = 6;
            mdi->note_table[1][ch][note].env_inc =
            -mdi->note_table[1][ch][note].sample->env_rate[6];
        } else {
            nte_array = mdi->note;
            if (nte_array == NULL) {
                mdi->note = nte;
            } else {
                do {
                    prev_nte = nte_array;
                    nte_array = nte_array->next;
                } while (nte_array);
                prev_nte->next = nte;
            }
            nte->active = 1;
            nte->next = NULL;
        }
    }
    nte->noteid = (ch << 8) | note;
    nte->patch = patch;
    nte->sample = sample;
    nte->sample_pos = 0;
    nte->sample_inc = get_inc(mdi, nte);
    nte->velocity = velocity;
    nte->env = 0;
    nte->env_inc = nte->sample->env_rate[0];
    nte->env_level = 0;
    nte->modes = sample->modes;
    nte->hold = mdi->channel[ch].hold;
    nte->replay = NULL;
    nte->is_off = 0;
    nte->ignore_chan_events = 0;
    _WM_AdjustNoteVolumes(mdi, ch, nte);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_midi_divisions(struct _mdi *mdi, struct _event_data *data) {
    // placeholder function so we can record divisions in the event stream
    // for conversion function _WM_Event2Midi()
    UNUSED(mdi);
    UNUSED(data);
    return;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_note_off(struct _mdi *mdi, struct _event_data *data) {
    struct _note *nte;
    uint8_t ch = data->channel;

    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    nte = &mdi->note_table[0][ch][(data->data.value >> 8)];
    if (!nte->active) {
        nte = &mdi->note_table[1][ch][(data->data.value >> 8)];
        if (!nte->active) {
            return;
        }
    }

    if ((mdi->channel[ch].isdrum) && (!(nte->modes & SAMPLE_LOOP))) {
        return;
    }

    if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env == 0)) {
        // This is a fix for notes that end before the
        // initial step of the envelope has completed
        // making it impossible to hear them at times.
        nte->is_off = 1;
    } else {
        _WM_do_note_off_extra(nte);
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_tempo(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_marker(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

int _WM_midi_setup_divisions(struct _mdi *mdi, uint32_t divisions) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0,0);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_midi_divisions;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = divisions;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

uint32_t _WM_SetupMidiEvent(struct _mdi *mdi, uint8_t * event_data, uint32_t siz, uint8_t running_event) {
    /*
     Only add standard MIDI and Sysex events in here.
     Non-standard events need to be handled by calling function
     to avoid compatibility issues.

     TODO:
     Add value limit checks
     */
    uint32_t ret_cnt = 0;
    uint8_t command = 0;
    uint8_t channel = 0;
    uint8_t data_1 = 0;
    uint8_t data_2 = 0;
    char *text = NULL;

    if (!siz) goto shortbuf;

    if (event_data[0] >= 0x80) {
        command = *event_data & 0xf0;
        channel = *event_data++ & 0x0f;
        ret_cnt++;
        if (--siz == 0) goto shortbuf;
    } else {
        command = running_event & 0xf0;
        channel = running_event & 0x0f;
    }

    switch(command) {
        case 0x80:
        _SETUP_NOTEOFF:
            if (siz < 2) goto shortbuf;
            data_1 = *event_data++;
            data_2 = *event_data++;
            _WM_midi_setup_noteoff(mdi, channel, data_1, data_2);
            ret_cnt += 2;
            break;
        case 0x90:
            if (event_data[1] == 0) goto _SETUP_NOTEOFF; /* A velocity of 0 in a note on is actually a note off */
            if (siz < 2) goto shortbuf;
            data_1 = *event_data++;
            data_2 = *event_data++;
            midi_setup_noteon(mdi, channel, data_1, data_2);
            ret_cnt += 2;
            break;
        case 0xa0:
            if (siz < 2) goto shortbuf;
            data_1 = *event_data++;
            data_2 = *event_data++;
            midi_setup_aftertouch(mdi, channel, data_1, data_2);
            ret_cnt += 2;
            break;
        case 0xb0:
            if (siz < 2) goto shortbuf;
            data_1 = *event_data++;
            data_2 = *event_data++;
            midi_setup_control(mdi, channel, data_1, data_2);
            ret_cnt += 2;
            break;
        case 0xc0:
            data_1 = *event_data++;
            midi_setup_patch(mdi, channel, data_1);
            ret_cnt++;
            break;
        case 0xd0:
            data_1 = *event_data++;
            midi_setup_channel_pressure(mdi, channel, data_1);
            ret_cnt++;
            break;
        case 0xe0:
            if (siz < 2) goto shortbuf;
            data_1 = *event_data++;
            data_2 = *event_data++;
            midi_setup_pitch(mdi, channel, ((data_2 << 7) | (data_1 & 0x7f)));
            ret_cnt += 2;
            break;
        case 0xf0:
            if (channel == 0x0f) {
                /*
                 MIDI Meta Events
                 */
                uint32_t tmp_length = 0;
                if ((event_data[0] == 0x00) && (event_data[1] == 0x02)) {
                    /*
                     Sequence Number
                     We only setting this up here for WM_Event2Midi function
                     */
                    if (siz < 4) goto shortbuf;
                    midi_setup_sequenceno(mdi, ((event_data[2] << 8) + event_data[3]));
                    ret_cnt += 4;
                } else if (event_data[0] == 0x01) {
                    /* Text Event */
                    /* Get Length */
                    event_data++;
                    ret_cnt++;
                    if (--siz && *event_data > 0x7f) {
                        do {
                            if (!siz) break;
                            tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                            event_data++;
                            siz--;
                            ret_cnt++;
                        } while (*event_data > 0x7f);
                    }
                    if (!siz) goto shortbuf;
                    tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                    event_data++;
                    ret_cnt++;
                    if (--siz < tmp_length) goto shortbuf;
                    if (!tmp_length) break; /* bad file? */

                    text = malloc(tmp_length + 1);
                    memcpy(text, event_data, tmp_length);
                    text[tmp_length] = '\0';
                    midi_setup_text(mdi, text);

                    ret_cnt += tmp_length;

                } else if (event_data[0] == 0x02) {
                    /* Copyright Event */
                    /* Get Length */
                    event_data++;
                    ret_cnt++;
                    if (--siz && *event_data > 0x7f) {
                        do {
                            if (!siz) break;
                            tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                            event_data++;
                            siz--;
                            ret_cnt++;
                        } while (*event_data > 0x7f);
                    }
                    if (!siz) goto shortbuf;
                    tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                    event_data++;
                    ret_cnt++;
                    if (--siz < tmp_length) goto shortbuf;
                    if (!tmp_length) break; /* bad file? */

                    /* Copy copyright info in the getinfo struct */
                    if (mdi->extra_info.copyright) {
                        mdi->extra_info.copyright = realloc(mdi->extra_info.copyright,(strlen(mdi->extra_info.copyright) + 1 + tmp_length + 1));
                        memcpy(&mdi->extra_info.copyright[strlen(mdi->extra_info.copyright) + 1], event_data, tmp_length);
                        mdi->extra_info.copyright[strlen(mdi->extra_info.copyright) + 1 + tmp_length] = '\0';
                        mdi->extra_info.copyright[strlen(mdi->extra_info.copyright)] = '\n';
                    } else {
                        mdi->extra_info.copyright = malloc(tmp_length + 1);
                        memcpy(mdi->extra_info.copyright, event_data, tmp_length);
                        mdi->extra_info.copyright[tmp_length] = '\0';
                    }

                    /* NOTE: free'd when events are cleared during closure of mdi */
                    text = malloc(tmp_length + 1);
                    memcpy(text, event_data, tmp_length);
                    text[tmp_length] = '\0';
                    midi_setup_copyright(mdi, text);

                    ret_cnt += tmp_length;

                } else if (event_data[0] == 0x03) {
                    /* Track Name Event */
                    /* Get Length */
                    event_data++;
                    ret_cnt++;
                    if (--siz && *event_data > 0x7f) {
                        do {
                            if (!siz) break;
                            tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                            event_data++;
                            siz--;
                            ret_cnt++;
                        } while (*event_data > 0x7f);
                    }
                    if (!siz) goto shortbuf;
                    tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                    event_data++;
                    ret_cnt++;
                    if (--siz < tmp_length) goto shortbuf;
                    if (!tmp_length) break; /* bad file? */

                    text = malloc(tmp_length + 1);
                    memcpy(text, event_data, tmp_length);
                    text[tmp_length] = '\0';
                    midi_setup_trackname(mdi, text);

                    ret_cnt += tmp_length;

                } else if (event_data[0] == 0x04) {
                    /* Instrument Name Event */
                    /* Get Length */
                    event_data++;
                    ret_cnt++;
                    if (--siz && *event_data > 0x7f) {
                        do {
                            if (!siz) break;
                            tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                            event_data++;
                            siz--;
                            ret_cnt++;
                        } while (*event_data > 0x7f);
                    }
                    if (!siz) goto shortbuf;
                    tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                    event_data++;
                    ret_cnt++;
                    if (--siz < tmp_length) goto shortbuf;
                    if (!tmp_length) break; /* bad file? */

                    text = malloc(tmp_length + 1);
                    memcpy(text, event_data, tmp_length);
                    text[tmp_length] = '\0';
                    midi_setup_instrumentname(mdi, text);

                    ret_cnt += tmp_length;

                } else if (event_data[0] == 0x05) {
                    /* Lyric Event */
                    /* Get Length */
                    event_data++;
                    ret_cnt++;
                    if (--siz && *event_data > 0x7f) {
                        do {
                            if (!siz) break;
                            tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                            event_data++;
                            siz--;
                            ret_cnt++;
                        } while (*event_data > 0x7f);
                    }
                    if (!siz) goto shortbuf;
                    tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                    event_data++;
                    ret_cnt++;
                    if (--siz < tmp_length) goto shortbuf;
                    if (!tmp_length) break; /* bad file? */

                    text = malloc(tmp_length + 1);
                    memcpy(text, event_data, tmp_length);
                    text[tmp_length] = '\0';
                    midi_setup_lyric(mdi, text);

                    ret_cnt += tmp_length;

                } else if (event_data[0] == 0x06) {
                    /* Marker Event */
                    /* Get Length */
                    event_data++;
                    ret_cnt++;
                    if (--siz && *event_data > 0x7f) {
                        do {
                            if (!siz) break;
                            tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                            event_data++;
                            siz--;
                            ret_cnt++;
                        } while (*event_data > 0x7f);
                    }
                    if (!siz) goto shortbuf;
                    tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                    event_data++;
                    ret_cnt++;
                    if (--siz < tmp_length) goto shortbuf;
                    if (!tmp_length) break; /* bad file? */

                    text = malloc(tmp_length + 1);
                    memcpy(text, event_data, tmp_length);
                    text[tmp_length] = '\0';
                    midi_setup_marker(mdi, text);

                    ret_cnt += tmp_length;

                } else if (event_data[0] == 0x07) {
                    /* Cue Point Event */
                    /* Get Length */
                    event_data++;
                    ret_cnt++;
                    if (--siz && *event_data > 0x7f) {
                        do {
                            if (!siz) break;
                            tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                            event_data++;
                            siz--;
                            ret_cnt++;
                        } while (*event_data > 0x7f);
                    }
                    if (!siz) goto shortbuf;
                    tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                    event_data++;
                    ret_cnt++;
                    if (--siz < tmp_length) goto shortbuf;
                    if (!tmp_length) break; /* bad file? */

                    text = malloc(tmp_length + 1);
                    memcpy(text, event_data, tmp_length);
                    text[tmp_length] = '\0';
                    midi_setup_cuepoint(mdi, text);

                    ret_cnt += tmp_length;

                } else if ((event_data[0] == 0x20) && (event_data[1] == 0x01)) {
                    /*
                     Channel Prefix
                     We only setting this up here for WM_Event2Midi function
                     */
                    if (siz < 3) goto shortbuf;
                    midi_setup_channelprefix(mdi, event_data[2]);
                    ret_cnt += 3;
                } else if ((event_data[0] == 0x21) && (event_data[1] == 0x01)) {
                    /*
                     Port Prefix
                     We only setting this up here for WM_Event2Midi function
                     */
                    if (siz < 3) goto shortbuf;
                    midi_setup_portprefix(mdi, event_data[2]);
                    ret_cnt += 3;
                } else if ((event_data[0] == 0x2F) && (event_data[1] == 0x00)) {
                    /*
                     End of Track
                     Deal with this inside calling function
                     We only setting this up here for _WM_Event2Midi function
                     */
                    if (siz < 2) goto shortbuf;
                    _WM_midi_setup_endoftrack(mdi);
                    ret_cnt += 2;
                } else if ((event_data[0] == 0x51) && (event_data[1] == 0x03)) {
                    /*
                     Tempo
                     Deal with this inside calling function.
                     We only setting this up here for _WM_Event2Midi function
                     */
                    if (siz < 5) goto shortbuf;
                    _WM_midi_setup_tempo(mdi, ((event_data[2] << 16) + (event_data[3] << 8) + event_data[4]));
                    ret_cnt += 5;
                } else if ((event_data[0] == 0x54) && (event_data[1] == 0x05)) {
                    if (siz < 7) goto shortbuf;
                    /*
                     SMPTE Offset
                     We only setting this up here for WM_Event2Midi function
                     */
                    midi_setup_smpteoffset(mdi, ((event_data[3] << 24) + (event_data[4] << 16) + (event_data[5] << 8) + event_data[6]));

                    /*
                     Because this has 5 bytes of data we gonna "hack" it a little
                     */
                    mdi->events[mdi->events_size - 1].event_data.channel = event_data[2];

                    ret_cnt += 7;
                } else if ((event_data[0] == 0x58) && (event_data[1] == 0x04)) {
                    /*
                     Time Signature
                     We only setting this up here for WM_Event2Midi function
                     */
                    if (siz < 6) goto shortbuf;
                    midi_setup_timesignature(mdi, ((event_data[2] << 24) + (event_data[3] << 16) + (event_data[4] << 8) + event_data[5]));
                    ret_cnt += 6;
                } else if ((event_data[0] == 0x59) && (event_data[1] == 0x02)) {
                    /*
                     Key Signature
                     We only setting this up here for WM_Event2Midi function
                     */
                    if (siz < 4) goto shortbuf;
                    midi_setup_keysignature(mdi, ((event_data[2] << 8) + event_data[3]));
                    ret_cnt += 4;
                } else {
                    /*
                     Unsupported Meta Event
                     */
                    event_data++;
                    ret_cnt++;
                    if (--siz && *event_data > 0x7f) {
                        do {
                            if (!siz) break;
                            tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                            event_data++;
                            siz--;
                            ret_cnt++;
                        } while (*event_data > 0x7f);
                    }
                    if (!siz) goto shortbuf;
                    tmp_length = (tmp_length << 7) + (*event_data & 0x7f);
                    ret_cnt++;
                    ret_cnt += tmp_length;
                    if (--siz < tmp_length) goto shortbuf;
                }

            } else if ((channel == 0) || (channel == 7)) {
                /*
                 Sysex Events
                 */
                uint32_t sysex_len = 0;
                uint8_t *sysex_store = NULL;

                if (*event_data > 0x7f) {
                    do {
                        if (!siz) break;
                        sysex_len = (sysex_len << 7) + (*event_data & 0x7F);
                        event_data++;
                        siz--;
                        ret_cnt++;
                    } while (*event_data > 0x7f);
                }
                if (!siz) goto shortbuf;
                sysex_len = (sysex_len << 7) + (*event_data & 0x7F);
                event_data++;
                ret_cnt++;
                if (--siz < sysex_len) goto shortbuf;
                if (!sysex_len) break; /* bad file? */

                sysex_store = malloc(sizeof(uint8_t) * sysex_len);
                memcpy(sysex_store, event_data, sysex_len);

                if (sysex_store[sysex_len - 1] == 0xF7) {
                    uint8_t rolandsysexid[] = { 0x41, 0x10, 0x42, 0x12 };
                    if (memcmp(rolandsysexid, sysex_store, 4) == 0) {
                        /* For Roland Sysex Messages */
                        /* checksum */
                        uint8_t sysex_cs = 0;
                        uint32_t sysex_ofs = 4;
                        do {
                            sysex_cs += sysex_store[sysex_ofs];
                            if (sysex_cs > 0x7F) {
                                sysex_cs -= 0x80;
                            }
                            sysex_ofs++;
                        } while (sysex_store[sysex_ofs + 1] != 0xf7);
                        sysex_cs = 128 - sysex_cs;
                        /* is roland sysex message valid */
                        if (sysex_cs == sysex_store[sysex_ofs]) {
                            /* process roland sysex event */
                            if (sysex_store[4] == 0x40) {
                                if (((sysex_store[5] & 0xf0) == 0x10) && (sysex_store[6] == 0x15)) {
                                    /* Roland Drum Track Setting */
                                    uint8_t sysex_ch = 0x0f & sysex_store[5];
                                    if (sysex_ch == 0x00) {
                                        sysex_ch = 0x09;
                                    } else if (sysex_ch <= 0x09) {
                                        sysex_ch -= 1;
                                    }
                                    midi_setup_sysex_roland_drum_track(mdi, sysex_ch, sysex_store[7]);
                                } else if ((sysex_store[5] == 0x00) && (sysex_store[6] == 0x7F) && (sysex_store[7] == 0x00)) {
                                    /* Roland GS Reset */
                                    midi_setup_sysex_roland_reset(mdi);
                                }
                            }
                        }
                    } else {
                        /* For non-Roland Sysex Messages */
                        uint8_t gm_reset[] = {0x7e, 0x7f, 0x09, 0x01, 0xf7};
                        uint8_t yamaha_reset[] = {0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7};

                        if (memcmp(gm_reset, sysex_store, 5) == 0) {
                            /* GM Reset */
                            midi_setup_sysex_gm_reset(mdi);
                        } else if (memcmp(yamaha_reset,sysex_store,8) == 0) {
                            /* Yamaha Reset */
                            midi_setup_sysex_yamaha_reset(mdi);
                        }
                    }
                }
                free(sysex_store);
                sysex_store = NULL;
                /*
                event_data += sysex_len;
                */
                ret_cnt += sysex_len;
            } else {
                _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized meta type event)", 0);
                return 0;
            }
            break;

        default: /* Should NEVER get here */
            ret_cnt = 0;
            break;
    }
    if (ret_cnt == 0)
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing event)", 0);
    return ret_cnt;

shortbuf:
    _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(input too short)", 0);
    return 0;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_sysex_yamaha_reset(struct _mdi *mdi, struct _event_data *data) {
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    _WM_do_sysex_gm_reset(mdi,data);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_keysignature(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_keysignature(struct _mdi *mdi, uint32_t setting) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0, setting);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_keysignature;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = setting;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: f_hmi.c

_WM_ParseNewHmi(uint8_t *hmi_data, uint32_t hmi_size) {
    uint32_t hmi_tmp = 0;
    uint8_t *hmi_base = hmi_data;
    uint32_t data_siz;
    uint16_t hmi_bpm = 0;
    uint16_t hmi_division = 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;


    if (memcmp(hmi_data, "HMI-MIDISONG061595", 18)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __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__, __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__, __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__, __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_track_offset[i] >= hmi_size) {
                    _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0);
                    goto _hmi_end;
                }
                data_siz = hmi_size - hmi_track_offset[i];

                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;
                        hmi_tmp += 4;
                    } else if (hmi_data[1] == 0x15) {
                        hmi_data += 4;
                        hmi_track_offset[i] += 4;
                        hmi_tmp = 8;
                    } else {
                        hmi_tmp = 4;
                    }
                    hmi_data += 4;
                    hmi_track_offset[i] += 4;
                    if (hmi_tmp > data_siz) {
                        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0);
                        goto _hmi_end;
                    }
                    data_siz -= hmi_tmp;
                } else {
                    if ((setup_ret = _WM_SetupMidiEvent(hmi_mdi,hmi_data,data_siz,hmi_running_event[i])) == 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;
                        data_siz -= setup_ret;

                        note[hmi_tmp].length = 0;
                        if (data_siz && *hmi_data > 0x7f) {
                            do {
                                if (!data_siz) break;
                                note[hmi_tmp].length = (note[hmi_tmp].length << 7) | (*hmi_data & 0x7F);
                                hmi_data++;
                                data_siz--;
                                hmi_track_offset[i]++;
                            } while (*hmi_data > 0x7F);
                        }
                        if (!data_siz) {
                            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0);
                            goto _hmi_end;
                        }
                        note[hmi_tmp].length = (note[hmi_tmp].length << 7) | (*hmi_data & 0x7F);
                        hmi_data++;
                        data_siz--;
                        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;
                        data_siz -= setup_ret;
                    }
                }

                // get track delta
                // hmi_delta[i] = 0; // set at start of loop
                if (data_siz && *hmi_data > 0x7f) {
                    do {
                        if (!data_siz) break;
                        hmi_delta[i] = (hmi_delta[i] << 7) | (*hmi_data & 0x7F);
                        hmi_data++;
                        data_siz--;
                        hmi_track_offset[i]++;
                    } while (*hmi_data > 0x7F);
                }
                if (!data_siz) {
                    _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0);
                    goto _hmi_end;
                }
                hmi_delta[i] = (hmi_delta[i] << 7) | (*hmi_data & 0x7F);
                hmi_data++;
                data_siz--;
                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__, __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;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_bank_select(struct _mdi *mdi, struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);
    mdi->channel[ch].bank = data->data.value;
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_timesignature(struct _mdi *mdi, uint32_t setting) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0, setting);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_timesignature;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = setting;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_lyric(struct _mdi *mdi, char * text) {
    MIDI_EVENT_SDEBUG(__FUNCTION__,0, text);
    strip_text(text);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_lyric;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.string = text;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_data_entry_fine(struct _mdi *mdi,
                                       struct _event_data *data) {
    uint8_t ch = data->channel;
    int data_tmp;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if ((mdi->channel[ch].reg_non == 0)
      && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */
        data_tmp = mdi->channel[ch].pitch_range / 100;
        mdi->channel[ch].pitch_range = (data_tmp * 100) + data->data.value;
    /*  printf("Data Entry Fine: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/
    /*  printf("Data Entry Fine: data: %li\n\r", data->data.value);*/
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_portprefix(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_portprefix(struct _mdi *mdi, uint32_t setting) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0, setting);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_portprefix;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = setting;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_pitch(struct _mdi *mdi, uint8_t channel, uint16_t pitch) {
    MIDI_EVENT_DEBUG(__FUNCTION__,channel, pitch);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_pitch;
    mdi->events[mdi->event_count].event_data.channel = channel;
    mdi->events[mdi->event_count].event_data.data.value = pitch;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_cuepoint(struct _mdi *mdi, char * text) {
    MIDI_EVENT_SDEBUG(__FUNCTION__,0, text);
    strip_text(text);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_cuepoint;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.string = text;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_channel_hold(struct _mdi *mdi, struct _event_data *data) {
    struct _note *note_data = mdi->note;
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if (data->data.value > 63) {
        mdi->channel[ch].hold = 1;
    } else {
        mdi->channel[ch].hold = 0;
        if (note_data) {
            do {
                if ((note_data->noteid >> 8) == ch) {
                    if (note_data->hold & HOLD_OFF) {
                        if (note_data->modes & SAMPLE_ENVELOPE) {
                            if (note_data->modes & SAMPLE_CLAMPED) {
                                if (note_data->env < 5) {
                                    note_data->env = 5;
                                    if (note_data->env_level
                                        > note_data->sample->env_target[5]) {
                                        note_data->env_inc =
                                        -note_data->sample->env_rate[5];
                                    } else {
                                        note_data->env_inc =
                                        note_data->sample->env_rate[5];
                                    }
                                }
                            /*
                            } else if (note_data->modes & SAMPLE_SUSTAIN) {
                                if (note_data->env < 3) {
                                    note_data->env = 3;
                                    if (note_data->env_level
                                        > note_data->sample->env_target[3]) {
                                        note_data->env_inc =
                                        -note_data->sample->env_rate[3];
                                    } else {
                                        note_data->env_inc =
                                        note_data->sample->env_rate[3];
                                    }
                                }
                             */
                             } else if (note_data->env < 3) {
                                note_data->env = 3;
                                if (note_data->env_level
                                    > note_data->sample->env_target[3]) {
                                    note_data->env_inc =
                                    -note_data->sample->env_rate[3];
                                } else {
                                    note_data->env_inc =
                                    note_data->sample->env_rate[3];
                                }
                            }
                        } else {
                            if (note_data->modes & SAMPLE_LOOP) {
                                note_data->modes ^= SAMPLE_LOOP;
                            }
                            note_data->env_inc = 0;
                        }
                    }
                    note_data->hold = 0x00;
                }
                note_data = note_data->next;
            } while (note_data);
        }
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_do_note_off_extra(struct _note *nte) {

    MIDI_EVENT_DEBUG(__FUNCTION__,0, 0);
    nte->is_off = 0;
        {
        if (!(nte->modes & SAMPLE_ENVELOPE)) {
            if (nte->modes & SAMPLE_LOOP) {
                nte->modes ^= SAMPLE_LOOP;
            }
            nte->env_inc = 0;

        } else if (nte->hold) {
            nte->hold |= HOLD_OFF;
/*
        } else if (nte->modes & SAMPLE_SUSTAIN) {
            if (nte->env < 3) {
                nte->env = 3;
                if (nte->env_level > nte->sample->env_target[3]) {
                    nte->env_inc = -nte->sample->env_rate[3];
                } else {
                    nte->env_inc = nte->sample->env_rate[3];
                }
            }
*/
        } else if (nte->modes & SAMPLE_CLAMPED) {
            if (nte->env < 5) {
                nte->env = 5;
                if (nte->env_level > nte->sample->env_target[5]) {
                    nte->env_inc = -nte->sample->env_rate[5];
                } else {
                    nte->env_inc = nte->sample->env_rate[5];
                }
            }
        } else if (nte->env < 3) {
            nte->env = 3;
            if (nte->env_level > nte->sample->env_target[3]) {
                nte->env_inc = -nte->sample->env_rate[3];
            } else {
                nte->env_inc = nte->sample->env_rate[3];
            }
        }
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_do_channel_pressure(struct _mdi *mdi, struct _event_data *data) {
    uint8_t ch = data->channel;
    struct _note *note_data = mdi->note;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    mdi->channel[ch].pressure = data->data.value;

    while (note_data) {
        if (!note_data->ignore_chan_events) {
            if ((note_data->noteid >> 8) == ch) {
                note_data->velocity = data->data.value & 0xff;
                _WM_AdjustNoteVolumes(mdi, ch, note_data);
                if (note_data->replay) {
                    note_data->replay->velocity = data->data.value & 0xff;
                    _WM_AdjustNoteVolumes(mdi, ch, note_data->replay);
                }
            }
        }
        note_data = note_data->next;
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_lyric(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string);
#endif
    if (!(mdi->extra_info.mixer_options & WM_MO_TEXTASLYRIC)) {
        mdi->lyric = data->data.string;
    }
    return;
}

Project: wildmidi
File: internal_midi.c

_WM_initMDI(void) {
    struct _mdi *mdi;

    mdi = malloc(sizeof(struct _mdi));
    memset(mdi, 0, (sizeof(struct _mdi)));

    mdi->extra_info.copyright = NULL;
    mdi->extra_info.mixer_options = _WM_MixerOptions;

    _WM_load_patch(mdi, 0x0000);

    mdi->events_size = MEM_CHUNK;
    mdi->events = malloc(mdi->events_size * sizeof(struct _event));
    mdi->event_count = 0;
    mdi->current_event = mdi->events;

    mdi->samples_to_mix = 0;
    mdi->extra_info.current_sample = 0;
    mdi->extra_info.total_midi_time = 0;
    mdi->extra_info.approx_total_samples = 0;

    mdi->dyn_vol = 1.0;
    mdi->dyn_vol_adjust = 0.0;
    mdi->dyn_vol_peak = 0;
    mdi->dyn_vol_to_reach = 1.0;

    mdi->is_type2 = 0;

    mdi->lyric = NULL;

    _WM_do_sysex_gm_reset(mdi, NULL);

    return (mdi);
}

Project: wildmidi
File: internal_midi.c

static inline uint32_t get_inc(struct _mdi *mdi, struct _note *nte) {
    int ch = nte->noteid >> 8;
    int32_t note_f;
    uint32_t freq;

    if (__builtin_expect((nte->patch->note != 0), 0)) {
        note_f = nte->patch->note * 100;
    } else {
        note_f = (nte->noteid & 0x7f) * 100;
    }
    note_f += mdi->channel[ch].pitch_adjust;
    if (__builtin_expect((note_f < 0), 0)) {
        note_f = 0;
    } else if (__builtin_expect((note_f > 12700), 0)) {
        note_f = 12700;
    }
    freq = _WM_freq_table[(note_f % 1200)] >> (10 - (note_f / 1200));
    return (((freq / ((_WM_SampleRate * 100) / 1024)) * 1024
             / nte->sample->inc_div));
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_non_registered_param_course(struct _mdi *mdi,
                                     struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);
    mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x7F)
                                | (data->data.value << 7);
    mdi->channel[ch].reg_non = 1;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_copyright(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_aftertouch(struct _mdi *mdi, struct _event_data *data) {
    struct _note *nte;
    uint8_t ch = data->channel;

    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    nte = &mdi->note_table[0][ch][(data->data.value >> 8)];
    if (!nte->active) {
        nte = &mdi->note_table[1][ch][(data->data.value >> 8)];
        if (!nte->active) {
            return;
        }
    }

    nte->velocity = data->data.value & 0xff;
    _WM_AdjustNoteVolumes(mdi, ch, nte);
    if (nte->replay) {
        nte->replay->velocity = data->data.value & 0xff;
        _WM_AdjustNoteVolumes(mdi, ch, nte->replay);
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_DynamicVolumeAdjust(struct _mdi *mdi, int32_t *tmp_buffer, uint32_t buffer_used) {

    uint32_t i = 0;
    uint32_t j = 0;

    int8_t peak_set = 0;
    int32_t prev_val = 0;
    uint32_t peak_ofs = 0;
    int32_t peak = mdi->dyn_vol_peak;

    double volume_to_reach = mdi->dyn_vol_to_reach;
    double volume = mdi->dyn_vol;
    double volume_adjust = mdi->dyn_vol_adjust;
    double tmp_output = 0.0;

#define MAX_DYN_VOL 1.0

    for (i = 0; i < buffer_used; i++) {
        if ((i == 0) || (i > peak_ofs)) {
            // Find Next Peak/Troff
            peak_set = 0;
            prev_val = peak;
            peak_ofs = 0;
            for (j = i; j < buffer_used; j++) {
                if (peak_set == 0) {
                    // find what direction the data is going
                    if (prev_val > tmp_buffer[j]) {
                        // Going Down
                        peak_set = -1;
                    } else if (prev_val < tmp_buffer[j]) {
                        // Doing Up
                        peak_set = 1;
                    } else {
                        // No direction, keep looking
                        prev_val = tmp_buffer[j];
                        continue;
                    }
                }

                if (peak_set == 1) {
                    // Data is going up
                    if (peak < tmp_buffer[j]) {
                        peak = tmp_buffer[j];
                        peak_ofs = j;
                    } else if (peak > tmp_buffer[j]) {
                        // Data is starting to go down, we found the peak
                        break;
                    }
                } else { // assume peak_set == -1
                    // Data is going down
                    if (peak > tmp_buffer[j]) {
                        peak = tmp_buffer[j];
                        peak_ofs = j;
                    } else if (peak < tmp_buffer[j]) {
                        // Data is starting to go up, we found the troff
                        break;
                    }
                }

                prev_val = tmp_buffer[j];
            }

            if (peak_set != 0) {
                if (peak_set == 1) {
                    if (peak > 32767) {
                        volume_to_reach = 32767.0 / (double)peak;
                    } else {
                        volume_to_reach = MAX_DYN_VOL;
                    }
                } else { // assume peak_set == -1
                    if (peak < -32768) {
                        volume_to_reach = -32768.0 / (double)peak;
                    } else {
                        volume_to_reach = MAX_DYN_VOL;
                    }
                }
            } else {
                // No peak found, set volume we want to normal
                volume_to_reach = MAX_DYN_VOL;
            }

            if (volume != volume_to_reach) {
                if (volume_to_reach == MAX_DYN_VOL) {
                    // if we want normal volume then adjust to it slower
                    volume_adjust = (volume_to_reach - volume) / ((double)_WM_SampleRate * 0.1);
                } else {
                    // if we want to clamp the volume then adjust quickly
                    volume_adjust = (volume_to_reach - volume) / ((double)_WM_SampleRate * 0.0001);
                }
            }
        }

        // First do we need to do volume adjustments
        if ((volume_adjust != 0.0) && (volume != volume_to_reach)) {
                volume += volume_adjust;
                if (volume_adjust > 0.0) {
                    // if increasing the volume
                    if (volume >= MAX_DYN_VOL) {
                        // we dont boost volume
                        volume = MAX_DYN_VOL;
                        volume_adjust = 0.0;
                    } else if (volume > volume_to_reach) {
                        // we dont want to go above the level we wanted
                        volume = volume_to_reach;
                        volume_adjust = 0.0;
                    }
                } else {
                    // decreasing the volume
                    if (volume < volume_to_reach) {
                        // we dont want to go below the level we wanted
                        volume = volume_to_reach;
                        volume_adjust = 0.0;
                    }
                }
            }

        // adjust buffer volume
        tmp_output = (double)tmp_buffer[i] * volume;
        tmp_buffer[i] = (int32_t)tmp_output;
    }

    // store required values
    mdi->dyn_vol_adjust = volume_adjust;
    mdi->dyn_vol_peak = peak;
    mdi->dyn_vol = volume;
    mdi->dyn_vol_to_reach = volume_to_reach;
}

Project: wildmidi
File: internal_midi.c

void _WM_Release_Allowance(struct _mdi *mdi) {
    uint32_t release = 0;
    uint32_t longest_release = 0;
    
    struct _note *note = mdi->note;
    
    while (note != NULL) {
        
        if (note->modes & SAMPLE_ENVELOPE) {
            //ensure envelope isin a release state
            if (note->env < 4) {
                note->env = 4;
            }
        
            // make sure this is set
            note->env_inc = -note->sample->env_rate[note->env];
        
            release = note->env_level / -note->env_inc;
        } else {
            // Sample release
            if (note->modes & SAMPLE_LOOP) {
                note->modes ^= SAMPLE_LOOP;
            }
            release = note->sample->data_length - note->sample_pos;
        }
        
        if (release > longest_release) longest_release = release;
        note->replay = NULL;
        note = note->next;
    }
    
    mdi->samples_to_mix = longest_release;
    
    return;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_dummy(struct _mdi *mdi, struct _event_data *data) {
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
}

Project: wildmidi
File: internal_midi.c

int _WM_midi_setup_noteoff(struct _mdi *mdi, uint8_t channel,
                           uint8_t note, uint8_t velocity) {
    MIDI_EVENT_DEBUG(__FUNCTION__,channel, note);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_note_off;
    mdi->events[mdi->event_count].event_data.channel = channel;
    mdi->events[mdi->event_count].event_data.data.value = (note << 8) | velocity;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_text(struct _mdi *mdi, char * text) {
    MIDI_EVENT_SDEBUG(__FUNCTION__,0, text);
    strip_text(text);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_text;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.string = text;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: f_hmp.c

_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__, __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__, __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__, __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];
        chunk_length[i] -= chunk_ofs[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;
                    chunk_length[i] -= 3;
                } else {
                    uint32_t setup_ret = 0;

                    if ((setup_ret = _WM_SetupMidiEvent(hmp_mdi, hmp_chunk[i], chunk_length[i], 0)) == 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;
                        chunk_length[i] -= 3;
                        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;
                    chunk_length[i] -= setup_ret;
                }
                var_len_shift = 0;
                chunk_delta[i] = 0;
                if (chunk_length[i] && *hmp_chunk[i] < 0x80) {
                    do {
                        if (! chunk_length[i]) break;
                        chunk_delta[i] = chunk_delta[i] + ((*hmp_chunk[i] & 0x7F) << var_len_shift);
                        var_len_shift += 7;
                        hmp_chunk[i]++;
                        chunk_length[i]--;
                    } while (*hmp_chunk[i] < 0x80);
                }
                if (! chunk_length[i]) {
                    _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMP, "file too short", 0);
                    goto _hmp_end;
                }
                chunk_delta[i] = chunk_delta[i] + ((*hmp_chunk[i] & 0x7F) << var_len_shift);
                hmp_chunk[i]++;
                chunk_length[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__, __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;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_channelprefix(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_patch(struct _mdi *mdi, struct _event_data *data) {
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);
    if (!mdi->channel[ch].isdrum) {
        mdi->channel[ch].patch = _WM_get_patch_data(mdi,
                                                ((mdi->channel[ch].bank << 8) | data->data.value));
    } else {
        mdi->channel[ch].bank = data->data.value;
    }
}

Project: wildmidi
File: f_xmidi.c

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.0;
    float xmi_sample_remainder = 0.0;
    float xmi_samples_per_delta_f = 0.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;

    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 = 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 != NULL) free(xmi_notelen);
    if (xmi_mdi->reverb) return (xmi_mdi);
    _WM_freeMDI(xmi_mdi);
    return NULL;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_sequenceno(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: f_midi.c

_WM_Event2Midi(struct _mdi *mdi, uint8_t **out, uint32_t *outsize) {
    uint32_t out_ofs = 0;
    uint8_t running_event = 0;
    uint32_t divisions = 96;
    uint32_t tempo = 500000;
    float samples_per_tick = 0.0;
    uint32_t value = 0;
    float value_f = 0.0;
    struct _event *event = mdi->events;
    uint32_t track_size = 0;
    uint32_t track_start = 0;
    uint32_t track_count = 0;

    if (!mdi->event_count) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CONVERT, "(No events to convert)", 0);
        return -1;
    }

    samples_per_tick = _WM_GetSamplesPerTick(divisions, tempo);

    /*
     Note: This isn't accurate but will allow enough space for
            events plus delta values.
     */
    (*out) = malloc (sizeof(uint8_t) * (mdi->event_count * 12));

    /* Midi Header */
    (*out)[0] = 'M';
    (*out)[1] = 'T';
    (*out)[2] = 'h';
    (*out)[3] = 'd';
    (*out)[4] = 0x00;
    (*out)[5] = 0x00;
    (*out)[6] = 0x00;
    (*out)[7] = 0x06;
    if ((!(_WM_MixerOptions & WM_MO_SAVEASTYPE0)) && (mdi->is_type2)) {
        /* Type 2 */
        (*out)[8] = 0x00;
        (*out)[9] = 0x02;
    } else {
        /* Type 0 */
        (*out)[8] = 0x00;
        (*out)[9] = 0x00;
    }
    /* No. of tracks stored in 10-11 *** See below */
    /* Division stored in 12-13 *** See below */
    /* Track Header */
    (*out)[14] = 'M';
    (*out)[15] = 'T';
    (*out)[16] = 'r';
    (*out)[17] = 'k';
    /* Track size stored in 18-21 *** see below */
    out_ofs = 22;
    track_start = out_ofs;
    track_count++;

    do {
        /* TODO Is there a better way? */
        if (event->do_event == _WM_do_midi_divisions) {
            // DEBUG
            // fprintf(stderr,"Division: %u\r\n",event->event_data.data);
            divisions = event->event_data.data.value;
            (*out)[12] = (divisions >> 8) & 0xff;
            (*out)[13] = divisions & 0xff;
            samples_per_tick = _WM_GetSamplesPerTick(divisions, tempo);
        } else if (event->do_event == _WM_do_note_off) {
            // DEBUG
            // fprintf(stderr,"Note Off: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0x80 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0x80 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = (event->event_data.data.value >> 8) & 0xff;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_note_on) {
            // DEBUG
            // fprintf(stderr,"Note On: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0x90 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0x90 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = (event->event_data.data.value >> 8) & 0xff;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_aftertouch) {
            // DEBUG
            // fprintf(stderr,"Aftertouch: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xa0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xa0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = (event->event_data.data.value >> 8) & 0xff;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_bank_select) {
            // DEBUG
            // fprintf(stderr,"Control Bank Select: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 0;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_data_entry_course) {
            // DEBUG
            // fprintf(stderr,"Control Data Entry Course: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 6;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_channel_volume) {
            // DEBUG
            // fprintf(stderr,"Control Channel Volume: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 7;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_channel_balance) {
            // DEBUG
            // fprintf(stderr,"Control Channel Balance: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 8;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_channel_pan) {
            // DEBUG
            // fprintf(stderr,"Control Channel Pan: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 10;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_channel_expression) {
            // DEBUG
            // fprintf(stderr,"Control Channel Expression: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 11;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_data_entry_fine) {
            // DEBUG
            // fprintf(stderr,"Control Data Entry Fine: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 38;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_channel_hold) {
            // DEBUG
            // fprintf(stderr,"Control Channel Hold: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 64;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_data_increment) {
            // DEBUG
            // fprintf(stderr,"Control Data Increment: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 96;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_data_decrement) {
            // DEBUG
            //fprintf(stderr,"Control Data Decrement: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 97;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_non_registered_param_fine) {
            // DEBUG
            // fprintf(stderr,"Control Non Registered Param: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 98;
            (*out)[out_ofs++] = event->event_data.data.value & 0x7f;
        } else if (event->do_event == _WM_do_control_non_registered_param_course) {
            // DEBUG
            // fprintf(stderr,"Control Non Registered Param: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 99;
            (*out)[out_ofs++] = (event->event_data.data.value >> 7) & 0x7f;
        } else if (event->do_event == _WM_do_control_registered_param_fine) {
            // DEBUG
            // fprintf(stderr,"Control Registered Param Fine: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 100;
            (*out)[out_ofs++] = event->event_data.data.value & 0x7f;
        } else if (event->do_event == _WM_do_control_registered_param_course) {
            // DEBUG
            // fprintf(stderr,"Control Registered Param Course: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 101;
            (*out)[out_ofs++] = (event->event_data.data.value >> 7) & 0x7f;
        } else if (event->do_event == _WM_do_control_channel_sound_off) {
            // DEBUG
            // fprintf(stderr,"Control Channel Sound Off: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 120;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_channel_controllers_off) {
            // DEBUG
            // fprintf(stderr,"Control Channel Controllers Off: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 121;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_channel_notes_off) {
            // DEBUG
            // fprintf(stderr,"Control Channel Notes Off: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = 123;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_control_dummy) {
            // DEBUG
            // fprintf(stderr,"Control Dummy Event: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xb0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xb0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = (event->event_data.data.value >> 8) & 0xff;
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_patch) {
            // DEBUG
            // fprintf(stderr,"Patch: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xc0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xc0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_channel_pressure) {
            // DEBUG
            // fprintf(stderr,"Channel Pressure: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xd0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xd0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = event->event_data.data.value & 0xff;
        } else if (event->do_event == _WM_do_pitch) {
            // DEBUG
            // fprintf(stderr,"Pitch: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            if (running_event != (0xe0 | event->event_data.channel)) {
                (*out)[out_ofs++] = 0xe0 | event->event_data.channel;
                running_event = (*out)[out_ofs - 1];
            }
            (*out)[out_ofs++] = event->event_data.data.value & 0x7f;
            (*out)[out_ofs++] = (event->event_data.data.value >> 7) & 0x7f;
        } else if (event->do_event == _WM_do_sysex_roland_drum_track) {
            // DEBUG
            // fprintf(stderr,"Sysex Roland Drum Track: %u %.4x\r\n",event->event_data.channel, event->event_data.data);
            uint8_t foo[] = {0xf0, 0x09, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x15, 0x00, 0xf7};
            uint8_t foo_ch = event->event_data.channel;
            if (foo_ch == 9) {
                foo_ch = 0;
            } else if (foo_ch < 9) {
                foo_ch++;
            }
            foo[7] = 0x10 | foo_ch;
            foo[9] = event->event_data.data.value;
            memcpy(&((*out)[out_ofs]),foo,11);
            out_ofs += 11;
            running_event = 0;
        } else if (event->do_event == _WM_do_sysex_gm_reset) {
            // DEBUG
            // fprintf(stderr,"Sysex GM Reset\r\n");
            uint8_t foo[] = {0xf0, 0x05, 0x7e, 0x7f, 0x09, 0x01, 0xf7};
            memcpy(&((*out)[out_ofs]),foo,7);
            out_ofs += 7;
            running_event = 0;
        } else if (event->do_event == _WM_do_sysex_roland_reset) {
            // DEBUG
            // fprintf(stderr,"Sysex Roland Reset\r\n");
            uint8_t foo[] = {0xf0, 0x0a, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7};
            memcpy(&((*out)[out_ofs]),foo,12);
            out_ofs += 12;
            running_event = 0;
        } else if (event->do_event == _WM_do_sysex_yamaha_reset) {
            // DEBUG
            // fprintf(stderr,"Sysex Yamaha Reset\r\n");
            uint8_t foo[] = {0xf0, 0x08, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7};
            memcpy(&((*out)[out_ofs]),foo,10);
            out_ofs += 10;
            running_event = 0;
        } else if (event->do_event == _WM_do_meta_endoftrack) {
            // DEBUG
            // fprintf(stderr,"End Of Track\r\n");
            if ((!(_WM_MixerOptions & WM_MO_SAVEASTYPE0)) && (mdi->is_type2)) {
                /* Write end of track marker */
                (*out)[out_ofs++] = 0xff;
                (*out)[out_ofs++] = 0x2f;
                (*out)[out_ofs++] = 0x00;
                track_size = out_ofs - track_start;
                (*out)[track_start - 4] = (track_size >> 24) & 0xff;
                (*out)[track_start - 3] = (track_size >> 16) & 0xff;
                (*out)[track_start - 2] = (track_size >> 8) & 0xff;
                (*out)[track_start - 1] = track_size & 0xff;

                if (event[1].do_event != NULL) {
                    (*out)[out_ofs++] = 'M';
                    (*out)[out_ofs++] = 'T';
                    (*out)[out_ofs++] = 'r';
                    (*out)[out_ofs++] = 'k';
                    track_count++;
                    out_ofs += 4;
                    track_start = out_ofs;

                    /* write out a 0 delta */
                    (*out)[out_ofs++] = 0;

                    running_event = 0;
                }
            }
            goto NEXT_EVENT;
        } else if (event->do_event == _WM_do_meta_tempo) {
            // DEBUG
            // fprintf(stderr,"Tempo: %u\r\n",event->event_data.data);
            tempo = event->event_data.data.value & 0xffffff;

            samples_per_tick = _WM_GetSamplesPerTick(divisions, tempo);

            //DEBUG
            //fprintf(stderr,"\rDEBUG: div %i, tempo %i, bpm %f, pps %f, spd %f\r\n", divisions, tempo, bpm_f, pulses_per_second_f, samples_per_delta_f);

            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x51;
            (*out)[out_ofs++] = 0x03;
            (*out)[out_ofs++] = (tempo & 0xff0000) >> 16;
            (*out)[out_ofs++] = (tempo & 0xff00) >> 8;
            (*out)[out_ofs++] = (tempo & 0xff);
        } else if (event->do_event == _WM_do_meta_timesignature) {
            // DEBUG
            // fprintf(stderr,"Time Signature: %x\r\n",event->event_data.data);
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x58;
            (*out)[out_ofs++] = 0x04;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff000000) >> 24;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff0000) >> 16;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff00) >> 8;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff);
        } else if (event->do_event == _WM_do_meta_keysignature) {
            // DEBUG
            // fprintf(stderr,"Key Signature: %x\r\n",event->event_data.data);
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x59;
            (*out)[out_ofs++] = 0x02;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff00) >> 8;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff);
        } else if (event->do_event == _WM_do_meta_sequenceno) {
            // DEBUG
            // fprintf(stderr,"Sequence Number: %x\r\n",event->event_data.data);
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x00;
            (*out)[out_ofs++] = 0x02;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff00) >> 8;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff);
        } else if (event->do_event == _WM_do_meta_channelprefix) {
            // DEBUG
            // fprintf(stderr,"Channel Prefix: %x\r\n",event->event_data.data);
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x20;
            (*out)[out_ofs++] = 0x01;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff);
        } else if (event->do_event == _WM_do_meta_portprefix) {
            // DEBUG
            // fprintf(stderr,"Port Prefix: %x\r\n",event->event_data.data);
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x21;
            (*out)[out_ofs++] = 0x01;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff);
        } else if (event->do_event == _WM_do_meta_smpteoffset) {
            // DEBUG
            // fprintf(stderr,"SMPTE Offset: %x\r\n",event->event_data.data);
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x54;
            (*out)[out_ofs++] = 0x05;
            /*
             Remember because of the 5 bytes we stored it a little hacky.
             */
            (*out)[out_ofs++] = (event->event_data.channel & 0xff);
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff000000) >> 24;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff0000) >> 16;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff00) >> 8;
            (*out)[out_ofs++] = (event->event_data.data.value & 0xff);

        } else if (event->do_event == _WM_do_meta_text) {
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x01;

            goto _WRITE_TEXT;

        } else if (event->do_event == _WM_do_meta_copyright) {
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x02;

            goto _WRITE_TEXT;

        } else if (event->do_event == _WM_do_meta_trackname) {
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x03;

            goto _WRITE_TEXT;

        } else if (event->do_event == _WM_do_meta_instrumentname) {
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x04;

            goto _WRITE_TEXT;

        } else if (event->do_event == _WM_do_meta_lyric) {
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x05;

            goto _WRITE_TEXT;

        } else if (event->do_event == _WM_do_meta_marker) {
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x06;

            goto _WRITE_TEXT;

        } else if (event->do_event == _WM_do_meta_cuepoint) {
            (*out)[out_ofs++] = 0xff;
            (*out)[out_ofs++] = 0x07;

            _WRITE_TEXT:
            value = strlen(event->event_data.data.string);
            if (value > 0x0fffffff)
                (*out)[out_ofs++] = (((value >> 28) &0x7f) | 0x80);
            if (value > 0x1fffff)
                (*out)[out_ofs++] = (((value >> 21) &0x7f) | 0x80);
            if (value > 0x3fff)
                (*out)[out_ofs++] = (((value >> 14) & 0x7f) | 0x80);
            if (value > 0x7f)
                (*out)[out_ofs++] = (((value >> 7) & 0x7f) | 0x80);
            (*out)[out_ofs++] = (value & 0x7f);

            memcpy(&(*out)[out_ofs], event->event_data.data.string, value);
            out_ofs += value;

        } else {
            // DEBUG
            fprintf(stderr,"Unknown Event %.2x %.4x\n",event->event_data.channel, event->event_data.data.value);
            event++;
            continue;
        }

        value_f = (float)event->samples_to_next / samples_per_tick;
        value = (uint32_t)(value_f + 0.5);

        //DEBUG
        //fprintf(stderr,"\rDEBUG: STN %i, SPD %f, Delta %i\r\n", event->samples_to_next, samples_per_delta_f, value);

        if (value > 0x0fffffff)
            (*out)[out_ofs++] = (((value >> 28) &0x7f) | 0x80);
        if (value > 0x1fffff)
            (*out)[out_ofs++] = (((value >> 21) &0x7f) | 0x80);
        if (value > 0x3fff)
            (*out)[out_ofs++] = (((value >> 14) & 0x7f) | 0x80);
        if (value > 0x7f)
            (*out)[out_ofs++] = (((value >> 7) & 0x7f) | 0x80);
        (*out)[out_ofs++] = (value & 0x7f);
    NEXT_EVENT:
        event++;
    } while (event->do_event != NULL);

    if ((_WM_MixerOptions & WM_MO_SAVEASTYPE0) || (!mdi->is_type2)) {
        /* Write end of track marker */
        (*out)[out_ofs++] = 0xff;
        (*out)[out_ofs++] = 0x2f;
        (*out)[out_ofs++] = 0x00;

        /* Write last track size */
        track_size = out_ofs - track_start;
        (*out)[track_start - 4] = (track_size >> 24) & 0xff;
        (*out)[track_start - 3] = (track_size >> 16) & 0xff;
        (*out)[track_start - 2] = (track_size >> 8) & 0xff;
        (*out)[track_start - 1] = track_size & 0xff;
    }
    /* write track count */
    (*out)[10] = (track_count >> 8) & 0xff;
    (*out)[11] = track_count & 0xff;

    (*out) = realloc((*out), out_ofs);
    (*outsize) = out_ofs;

    return 0;
}

Project: wildmidi
File: internal_midi.c

void _WM_do_control_channel_notes_off(struct _mdi *mdi,
                                      struct _event_data *data) {
    struct _note *note_data = mdi->note;
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);

    if (mdi->channel[ch].isdrum)
        return;
    if (note_data) {
        do {
            if ((note_data->noteid >> 8) == ch) {
                if (!note_data->hold) {
                    if (note_data->modes & SAMPLE_ENVELOPE) {
                        if (note_data->env < 5) {
                            if (note_data->env_level
                                > note_data->sample->env_target[5]) {
                                note_data->env_inc =
                                -note_data->sample->env_rate[5];
                            } else {
                                note_data->env_inc =
                                note_data->sample->env_rate[5];
                            }
                            note_data->env = 5;
                        }
                    }
                } else {
                    note_data->hold |= HOLD_OFF;
                }
            }
            note_data = note_data->next;
        } while (note_data);
    }
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_trackname(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_channel_pressure(struct _mdi *mdi, uint8_t channel,
                                       uint8_t pressure) {
    MIDI_EVENT_DEBUG(__FUNCTION__,channel, pressure);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_channel_pressure;
    mdi->events[mdi->event_count].event_data.channel = channel;
    mdi->events[mdi->event_count].event_data.data.value = pressure;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

int _WM_midi_setup_endoftrack(struct _mdi *mdi) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0,0);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_endoftrack;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = 0;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_freeMDI(struct _mdi *mdi) {
    struct _sample *tmp_sample;
    uint32_t i;

    if (mdi->patch_count != 0) {
        _WM_Lock(&_WM_patch_lock);
        for (i = 0; i < mdi->patch_count; i++) {
            mdi->patches[i]->inuse_count--;
            if (mdi->patches[i]->inuse_count == 0) {
                /* free samples here */
                while (mdi->patches[i]->first_sample) {
                    tmp_sample = mdi->patches[i]->first_sample->next;
                    free(mdi->patches[i]->first_sample->data);
                    free(mdi->patches[i]->first_sample);
                    mdi->patches[i]->first_sample = tmp_sample;
                }
                mdi->patches[i]->loaded = 0;
            }
        }
        _WM_Unlock(&_WM_patch_lock);
        free(mdi->patches);
    }

    if (mdi->event_count != 0) {
        for (i = 0; i < mdi->event_count; i++) {
            /* Free up the string event storage */
            if (mdi->events[i].do_event == _WM_do_meta_text) {
                free(mdi->events[i].event_data.data.string);
            } else if (mdi->events[i].do_event == _WM_do_meta_text) {
                free(mdi->events[i].event_data.data.string);
            } else if (mdi->events[i].do_event == _WM_do_meta_copyright) {
                free(mdi->events[i].event_data.data.string);
            } else if (mdi->events[i].do_event == _WM_do_meta_trackname) {
                free(mdi->events[i].event_data.data.string);
            } else if (mdi->events[i].do_event == _WM_do_meta_instrumentname) {
                free(mdi->events[i].event_data.data.string);
            } else if (mdi->events[i].do_event == _WM_do_meta_lyric) {
                free(mdi->events[i].event_data.data.string);
            } else if (mdi->events[i].do_event == _WM_do_meta_marker) {
                free(mdi->events[i].event_data.data.string);
            } else if (mdi->events[i].do_event == _WM_do_meta_cuepoint) {
                free(mdi->events[i].event_data.data.string);
            }
        }
    }

    free(mdi->events);
    _WM_free_reverb(mdi->reverb);
    free(mdi->mix_buffer);
    free(mdi);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_pitch(struct _mdi *mdi, struct _event_data *data) {
    struct _note *note_data = mdi->note;
    uint8_t ch = data->channel;

    MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value);
    mdi->channel[ch].pitch = data->data.value - 0x2000;

    if (mdi->channel[ch].pitch < 0) {
        mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range
        * mdi->channel[ch].pitch / 8192;
    } else {
        mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range
        * mdi->channel[ch].pitch / 8191;
    }

    if (note_data) {
        do {
            if ((note_data->noteid >> 8) == ch) {
                note_data->sample_inc = get_inc(mdi, note_data);
            }
            note_data = note_data->next;
        } while (note_data);
    }
}

Project: wildmidi
File: internal_midi.c

float _WM_GetSamplesPerTick(uint32_t divisions, uint32_t tempo) {
    float microseconds_per_tick;
    float secs_per_tick;
    float samples_per_tick;

    /* Slow but needed for accuracy */
    microseconds_per_tick = (float) tempo / (float) divisions;
    secs_per_tick = microseconds_per_tick / 1000000.0f;
    samples_per_tick = _WM_SampleRate * secs_per_tick;

    return (samples_per_tick);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_cuepoint(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_channelprefix(struct _mdi *mdi, uint32_t setting) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0, setting);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_channelprefix;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = setting;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

void _WM_do_meta_smpteoffset(struct _mdi *mdi, struct _event_data *data) {
/* placeholder function so we can record tempo in the event stream
 * for conversion function _WM_Event2Midi */
#ifdef DEBUG_MIDI
    uint8_t ch = data->channel;
    MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value);
#else
    UNUSED(data);
#endif
    UNUSED(mdi);
    return;
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_smpteoffset(struct _mdi *mdi, uint32_t setting) {
    MIDI_EVENT_DEBUG(__FUNCTION__,0, setting);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_meta_smpteoffset;
    mdi->events[mdi->event_count].event_data.channel = 0;
    mdi->events[mdi->event_count].event_data.data.value = setting;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;
    return (0);
}

Project: wildmidi
File: internal_midi.c

static int midi_setup_noteon(struct _mdi *mdi, uint8_t channel,
                             uint8_t note, uint8_t velocity) {
    MIDI_EVENT_DEBUG(__FUNCTION__,channel, note);
    _WM_CheckEventMemoryPool(mdi);
    mdi->events[mdi->event_count].do_event = *_WM_do_note_on;
    mdi->events[mdi->event_count].event_data.channel = channel;
    mdi->events[mdi->event_count].event_data.data.value = (note << 8) | velocity;
    mdi->events[mdi->event_count].samples_to_next = 0;
    mdi->event_count++;

    if (mdi->channel[channel].isdrum)
        _WM_load_patch(mdi, ((mdi->channel[channel].bank << 8) | (note | 0x80)));
    return (0);
}