Commit message: wildmidi_lib.c (WildMidi_Open, WildMidi_OpenBuffer): refuse to proceed if less then 18 bytes of input

Fixes bug #178.
CVE: CVE-2017-1000418
CWE: CWE-119
Vulnerability description: The WildMidi_Open function in WildMIDI since commit d8a466829c67cacbb1700beded25c448d99514e5 allows remote attackers to cause a denial of service (heap-based buffer overflow and application crash) or possibly have unspecified other impact via a crafted file.

Project: wildmidi
File: wildmidi_lib.c

static void WM_FreePatches(void) {
    int i;
    struct _patch * tmp_patch;
    struct _sample * tmp_sample;

    _WM_Lock(&_WM_patch_lock);
    for (i = 0; i < 128; i++) {
        while (_WM_patch[i]) {
            while (_WM_patch[i]->first_sample) {
                tmp_sample = _WM_patch[i]->first_sample->next;
                free(_WM_patch[i]->first_sample->data);
                free(_WM_patch[i]->first_sample);
                _WM_patch[i]->first_sample = tmp_sample;
            }
            free(_WM_patch[i]->filename);
            tmp_patch = _WM_patch[i]->next;
            free(_WM_patch[i]);
            _WM_patch[i] = tmp_patch;
        }
    }
    _WM_Unlock(&_WM_patch_lock);
}

Project: wildmidi

static int WM_GetOutput_Gauss(midi * handle, int8_t *buffer, uint32_t size) {
    uint32_t buffer_used = 0;
    uint32_t i;
    struct _mdi *mdi = (struct _mdi *) handle;
    uint32_t real_samples_to_mix = 0;
    uint32_t data_pos;
    int32_t premix, left_mix, right_mix;
    struct _note *note_data = NULL;
    uint32_t count;
    int16_t *sptr;
    double y, xd;
    double *gptr, *gend;
    int left, right, temp_n;
    int ii, jj;
    struct _event *event = mdi->current_event;
    int32_t *tmp_buffer;
    int32_t *out_buffer;

    _WM_Lock(&mdi->lock);

    buffer_used = 0;
    memset(buffer, 0, size);

    if ( (size / 2) > mdi->mix_buffer_size) {
        if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) {
            mdi->mix_buffer_size += MEM_CHUNK;
        } else {
            mdi->mix_buffer_size = size / 2;
        }
        mdi->mix_buffer = realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(int32_t));
    }

    tmp_buffer = mdi->mix_buffer;

    memset(tmp_buffer, 0, ((size / 2) * sizeof(int32_t)));
    out_buffer = tmp_buffer;

    do {
        if (__builtin_expect((!mdi->samples_to_mix), 0)) {
            while ((!mdi->samples_to_mix) && (event->do_event)) {
                event->do_event(mdi, &event->event_data);
                if ((mdi->extra_info.mixer_options & WM_MO_LOOP) && (event[0].do_event == *_WM_do_meta_endoftrack)) {
                    _WM_ResetToStart(mdi);
                    event = mdi->current_event;
                } else {
                    mdi->samples_to_mix = event->samples_to_next;
                    event++;
                    mdi->current_event = event;
                }
            }

            if (!mdi->samples_to_mix) {
                if (mdi->extra_info.current_sample
                    >= mdi->extra_info.approx_total_samples) {
                    break;
                } else if ((mdi->extra_info.approx_total_samples
                            - mdi->extra_info.current_sample) > (size >> 2)) {
                    mdi->samples_to_mix = size >> 2;
                } else {
                    mdi->samples_to_mix = mdi->extra_info.approx_total_samples
                    - mdi->extra_info.current_sample;
                }
            }
        }
        if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) {
            real_samples_to_mix = size >> 2;
        } else {
            real_samples_to_mix = mdi->samples_to_mix;
            if (real_samples_to_mix == 0) {
                continue;
            }
        }

        /* do mixing here */
        count = real_samples_to_mix;
        do {
            note_data = mdi->note;
            left_mix = right_mix = 0;
            if (__builtin_expect((note_data != NULL), 1)) {
                while (note_data) {
                    /*
                     * ===================
                     * resample the sample
                     * ===================
                     */
                    data_pos = note_data->sample_pos >> FPBITS;

                    /* check to see if we're near one of the ends */
                    left = data_pos;
                    right = (note_data->sample->data_length >> FPBITS) - left
                            - 1;
                    temp_n = (right << 1) - 1;
                    if (temp_n <= 0)
                        temp_n = 1;
                    if (temp_n > (left << 1) + 1)
                        temp_n = (left << 1) + 1;

                    /* use Newton if we can't fill the window */
                    if (temp_n < gauss_n) {
                        xd = note_data->sample_pos & FPMASK;
                        xd /= (1L << FPBITS);
                        xd += temp_n >> 1;
                        y = 0;
                        sptr = note_data->sample->data
                                + (note_data->sample_pos >> FPBITS)
                                - (temp_n >> 1);
                        for (ii = temp_n; ii;) {
                            for (jj = 0; jj <= ii; jj++)
                                y += sptr[jj] * newt_coeffs[ii][jj];
                            y *= xd - --ii;
                        }
                        y += *sptr;
                    } else { /* otherwise, use Gauss as usual */
                        y = 0;
                        gptr = &gauss_table[(note_data->sample_pos & FPMASK) *
                                     (gauss_n + 1)];
                        gend = gptr + gauss_n;
                        sptr = note_data->sample->data
                                + (note_data->sample_pos >> FPBITS)
                                - (gauss_n >> 1);
                        do {
                            y += *(sptr++) * *(gptr++);
                        } while (gptr <= gend);
                    }

                    premix = (int32_t)((y * (note_data->env_level >> 12)) / 1024);

                    left_mix += (premix * (int32_t)note_data->left_mix_volume) / 1024;
                    right_mix += (premix * (int32_t)note_data->right_mix_volume) / 1024;

                    /*
                     * ========================
                     * sample position checking
                     * ========================
                     */
                    note_data->sample_pos += note_data->sample_inc;
                    if (__builtin_expect(
                                         (note_data->sample_pos > note_data->sample->loop_end),
                                         0)) {
                        if (note_data->modes & SAMPLE_LOOP) {
                            note_data->sample_pos =
                            note_data->sample->loop_start
                            + ((note_data->sample_pos
                                - note_data->sample->loop_start)
                               % note_data->sample->loop_size);
                        } else if (__builtin_expect(
                                                    (note_data->sample_pos
                                                     >= note_data->sample->data_length),
                                                    0)) {
                            goto _END_THIS_NOTE;
                        }
                    }

                    if (__builtin_expect((note_data->env_inc == 0), 0)) {
                        /*
                         fprintf(stderr,"\r\nINC = 0, ENV %i, LEVEL %i, TARGET %d, RATE %i\r\n",
                                 note_data->env, note_data->env_level,
                                 note_data->sample->env_target[note_data->env],
                                 note_data->sample->env_rate[note_data->env]);
                         */
                        note_data = note_data->next;
                        continue;
                    }

                    note_data->env_level += note_data->env_inc;
                    /*
                     fprintf(stderr,"\r\nENV %i, LEVEL %i, TARGET %d, RATE %i, INC %i\r\n",
                             note_data->env, note_data->env_level,
                             note_data->sample->env_target[note_data->env],
                             note_data->sample->env_rate[note_data->env],
                             note_data->env_inc);
                     */
                    if (note_data->env_inc < 0) {
                        if (note_data->env_level
                            > note_data->sample->env_target[note_data->env]) {
                            note_data = note_data->next;
                            continue;
                        }
                    } else if (note_data->env_inc > 0) {
                        if (note_data->env_level
                            < note_data->sample->env_target[note_data->env]) {
                            note_data = note_data->next;
                            continue;
                        }
                    }


                    note_data->env_level =
                    note_data->sample->env_target[note_data->env];
                    switch (note_data->env) {
                        case 0:
                            if (!(note_data->modes & SAMPLE_ENVELOPE)) {
                                note_data->env_inc = 0;
                                note_data = note_data->next;
                                continue;
                            }
                            break;
                        case 2:
                            if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) {
                                note_data->env_inc = 0;
                                note_data = note_data->next;
                                continue;
                            } else if (note_data->modes & SAMPLE_CLAMPED) {
                                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];
                                }
                                continue;
                            }
                            break;
                        case 5:
                            if (__builtin_expect((note_data->env_level == 0), 1)) {
                                goto _END_THIS_NOTE;
                            }
                            /* sample release */
                            if (note_data->modes & SAMPLE_LOOP)
                                note_data->modes ^= SAMPLE_LOOP;
                            note_data->env_inc = 0;
                            note_data = note_data->next;
                            continue;
                        case 6:
                        _END_THIS_NOTE:
                            if (__builtin_expect((note_data->replay != NULL), 1)) {
                                note_data->active = 0;
                                {
                                    struct _note *prev_note = NULL;
                                    struct _note *nte_array = mdi->note;

                                    if (nte_array != note_data) {
                                        do {
                                            prev_note = nte_array;
                                            nte_array = nte_array->next;
                                        } while (nte_array != note_data);
                                    }
                                    if (prev_note) {
                                        prev_note->next = note_data->replay;
                                    } else {
                                        mdi->note = note_data->replay;
                                    }
                                    note_data->replay->next = note_data->next;
                                    note_data = note_data->replay;
                                    note_data->active = 1;
                                }
                            } else {
                                note_data->active = 0;
                                {
                                    struct _note *prev_note = NULL;
                                    struct _note *nte_array = mdi->note;

                                    if (nte_array != note_data) {
                                        do {
                                            prev_note = nte_array;
                                            nte_array = nte_array->next;
                                        } while ((nte_array != note_data)
                                                 && (nte_array));
                                    }
                                    if (prev_note) {
                                        prev_note->next = note_data->next;
                                    } else {
                                        mdi->note = note_data->next;
                                    }
                                    note_data = note_data->next;
                                }
                            }
                            continue;
                    }
                    note_data->env++;

                    if (note_data->is_off == 1) {
                        _WM_do_note_off_extra(note_data);
                    } else {

                        if (note_data->env_level
                            >= note_data->sample->env_target[note_data->env]) {
                            note_data->env_inc =
                            -note_data->sample->env_rate[note_data->env];
                        } else {
                            note_data->env_inc =
                            note_data->sample->env_rate[note_data->env];
                        }
                    }
                    note_data = note_data->next;
                    continue;
                }
            }
            *tmp_buffer++ = left_mix;
            *tmp_buffer++ = right_mix;
        } while (--count);

        buffer_used += real_samples_to_mix * 4;
        size -= (real_samples_to_mix << 2);
        mdi->extra_info.current_sample += real_samples_to_mix;
        mdi->samples_to_mix -= real_samples_to_mix;
    } while (size);

    tmp_buffer = out_buffer;

    if (mdi->extra_info.mixer_options & WM_MO_REVERB) {
        _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2));
    }


    for (i = 0; i < buffer_used; i += 4) {
        left_mix = *tmp_buffer++;
        right_mix = *tmp_buffer++;

        /*
         * ===================
         * Write to the buffer
         * ===================
         */
#ifdef WORDS_BIGENDIAN
        (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80);
        (*buffer++) = left_mix & 0xff;
        (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80);
        (*buffer++) = right_mix & 0xff;
#else
        (*buffer++) = left_mix & 0xff;
        (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80);
        (*buffer++) = right_mix & 0xff;
        (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80);
#endif
    }
    _WM_Unlock(&mdi->lock);
    return (buffer_used);
}

Project: wildmidi

static int WM_GetOutput_Linear(midi * handle, int8_t *buffer, uint32_t size) {
    uint32_t buffer_used = 0;
    uint32_t i;
    struct _mdi *mdi = (struct _mdi *) handle;
    uint32_t real_samples_to_mix = 0;
    uint32_t data_pos;
    int32_t premix, left_mix, right_mix;
    struct _note *note_data = NULL;
    uint32_t count;
    struct _event *event = mdi->current_event;
    int32_t *tmp_buffer;
    int32_t *out_buffer;

    _WM_Lock(&mdi->lock);

    buffer_used = 0;
    memset(buffer, 0, size);

    if ( (size / 2) > mdi->mix_buffer_size) {
        if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) {
            mdi->mix_buffer_size += MEM_CHUNK;
        } else {
            mdi->mix_buffer_size = size / 2;
        }
        mdi->mix_buffer = realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(int32_t));
    }

    tmp_buffer = mdi->mix_buffer;

    memset(tmp_buffer, 0, ((size / 2) * sizeof(int32_t)));
    out_buffer = tmp_buffer;

    do {
        if (__builtin_expect((!mdi->samples_to_mix), 0)) {
            while ((!mdi->samples_to_mix) && (event->do_event)) {
                event->do_event(mdi, &event->event_data);
                if ((mdi->extra_info.mixer_options & WM_MO_LOOP) && (event[0].do_event == *_WM_do_meta_endoftrack)) {
                    _WM_ResetToStart(mdi);
                    event = mdi->current_event;
                } else {
                    mdi->samples_to_mix = event->samples_to_next;
                    event++;
                    mdi->current_event = event;
                }
            }

            if (__builtin_expect((!mdi->samples_to_mix), 0)) {
                if (mdi->extra_info.current_sample >= mdi->extra_info.approx_total_samples) {
                    break;
                } else if ((mdi->extra_info.approx_total_samples
                             - mdi->extra_info.current_sample) > (size >> 2)) {
                    mdi->samples_to_mix = size >> 2;
                } else {
                    mdi->samples_to_mix = mdi->extra_info.approx_total_samples
                                           - mdi->extra_info.current_sample;
                }
            }
        }
        if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) {
            real_samples_to_mix = size >> 2;
        } else {
            real_samples_to_mix = mdi->samples_to_mix;
            if (real_samples_to_mix == 0) {
                continue;
            }
        }

        /* do mixing here */
        count = real_samples_to_mix;

        do {
            note_data = mdi->note;
            left_mix = right_mix = 0;
            RESAMPLE_DEBUGI("SAMPLES_TO_MIX",count);
            if (__builtin_expect((note_data != NULL), 1)) {
                RESAMPLE_DEBUGS("Processing Notes");
                while (note_data) {
                    /*
                     * ===================
                     * resample the sample
                     * ===================
                     */
                    data_pos = note_data->sample_pos >> FPBITS;
                    premix = ((note_data->sample->data[data_pos] + (((note_data->sample->data[data_pos + 1] - note_data->sample->data[data_pos]) * (int32_t)(note_data->sample_pos & FPMASK)) / 1024)) * (note_data->env_level >> 12)) / 1024;

                    left_mix += (premix * (int32_t)note_data->left_mix_volume) / 1024;
                    right_mix += (premix * (int32_t)note_data->right_mix_volume) / 1024;

                    /*
                     * ========================
                     * sample position checking
                     * ========================
                     */
#ifdef DEBUG_RESAMPLE
                    fprintf(stderr,"\r\n%d -> INC %i, ENV %i, LEVEL %i, TARGET %d, RATE %i, SAMPLE POS %i, SAMPLE LENGTH %i, PREMIX %i (%i:%i)",
                            (uint32_t)note_data,
                            note_data->env_inc,
                            note_data->env, note_data->env_level,
                            note_data->sample->env_target[note_data->env],
                            note_data->sample->env_rate[note_data->env],
                            note_data->sample_pos,
                            note_data->sample->data_length,
                            premix, left_mix, right_mix);
                    if (note_data->modes & SAMPLE_LOOP)
                        fprintf(stderr,", LOOP %i + %i",
                                note_data->sample->loop_start,
                                note_data->sample->loop_size);
                    fprintf(stderr,"\r\n");
#endif

                    note_data->sample_pos += note_data->sample_inc;

                    if (__builtin_expect((note_data->modes & SAMPLE_LOOP), 1)) {
                        if (__builtin_expect(
                                             (note_data->sample_pos > note_data->sample->loop_end),
                                             0)) {
                            note_data->sample_pos = note_data->sample->loop_start
                                + ((note_data->sample_pos
                                    - note_data->sample->loop_start)
                                % note_data->sample->loop_size);
                        }

                    } else if (__builtin_expect(
                                                  (note_data->sample_pos
                                                   >= note_data->sample->data_length),
                                                  0)) {
                        goto _END_THIS_NOTE;
                    }

                    if (__builtin_expect((note_data->env_inc == 0), 0)) {
                        note_data = note_data->next;
                        RESAMPLE_DEBUGS("Next Note: 0 env_inc");
                        continue;
                    }

                    note_data->env_level += note_data->env_inc;

                    if (note_data->env_inc < 0) {
                        if (__builtin_expect((note_data->env_level
                            > note_data->sample->env_target[note_data->env]), 0)) {
                            note_data = note_data->next;
                            RESAMPLE_DEBUGS("Next Note: env_lvl > env_target");
                            continue;
                        }
                    } else if (note_data->env_inc > 0) {
                        if (__builtin_expect((note_data->env_level
                            < note_data->sample->env_target[note_data->env]), 0)) {
                            note_data = note_data->next;
                            RESAMPLE_DEBUGS("Next Note: env_lvl < env_target");
                            continue;
                        }
                    }

                    note_data->env_level =
                            note_data->sample->env_target[note_data->env];
                    switch (note_data->env) {
                    case 0:
                        if (!(note_data->modes & SAMPLE_ENVELOPE)) {
                            note_data->env_inc = 0;
                            note_data = note_data->next;
                            RESAMPLE_DEBUGS("Next Note: No Envelope");
                            continue;
                        }
                        break;
                    case 2:
                        if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) {
                            note_data->env_inc = 0;
                            note_data = note_data->next;
                            RESAMPLE_DEBUGS("Next Note: SAMPLE_SUSTAIN");
                            continue;
                        } else if (note_data->modes & SAMPLE_CLAMPED) {
                            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];
                            }
                            continue;
                        }
                        break;
                    case 5:
                        if (__builtin_expect((note_data->env_level == 0), 1)) {
                            goto _END_THIS_NOTE;
                        }
                        /* sample release */
                        if (note_data->modes & SAMPLE_LOOP)
                            note_data->modes ^= SAMPLE_LOOP;
                        note_data->env_inc = 0;
                        note_data = note_data->next;
                        RESAMPLE_DEBUGS("Next Note: Sample Release");

                        continue;
                    case 6:
                        _END_THIS_NOTE:
                        if (__builtin_expect((note_data->replay != NULL), 1)) {
                            note_data->active = 0;
                            {
                                struct _note *prev_note = NULL;
                                struct _note *nte_array = mdi->note;

                                if (nte_array != note_data) {
                                    do {
                                        prev_note = nte_array;
                                        nte_array = nte_array->next;
                                    } while (nte_array != note_data);
                                }
                                if (prev_note) {
                                    prev_note->next = note_data->replay;
                                } else {
                                    mdi->note = note_data->replay;
                                }
                                note_data->replay->next = note_data->next;
                                note_data = note_data->replay;
                                note_data->active = 1;
                            }
                        } else {
                            note_data->active = 0;
                            {
                                struct _note *prev_note = NULL;
                                struct _note *nte_array = mdi->note;

                                if (nte_array != note_data) {
                                    do {
                                        prev_note = nte_array;
                                        nte_array = nte_array->next;
                                    } while ((nte_array != note_data)
                                            && (nte_array));
                                }
                                if (prev_note) {
                                    prev_note->next = note_data->next;
                                } else {
                                    mdi->note = note_data->next;
                                }
                                note_data = note_data->next;
                            }
                        }
                        RESAMPLE_DEBUGS("Next Note: Killed Off Note");
                        continue;
                    }
                    note_data->env++;

                    if (note_data->is_off == 1) {
                        _WM_do_note_off_extra(note_data);
                    } else {

                        if (note_data->env_level
                            >= note_data->sample->env_target[note_data->env]) {
                            note_data->env_inc =
                                -note_data->sample->env_rate[note_data->env];
                        } else {
                            note_data->env_inc =
                                note_data->sample->env_rate[note_data->env];
                        }
                    }
                    note_data = note_data->next;
#ifdef DEBUG_RESAMPLE
                    if (note_data != NULL)
                        RESAMPLE_DEBUGI("Next Note: Next ENV ", note_data->env);
                    else
                        RESAMPLE_DEBUGS("Next Note: Next ENV");
#endif
                    continue;
                }
            }
            *tmp_buffer++ = left_mix;
            *tmp_buffer++ = right_mix;
        } while (--count);

        buffer_used += real_samples_to_mix * 4;
        size -= (real_samples_to_mix << 2);
        mdi->extra_info.current_sample += real_samples_to_mix;
        mdi->samples_to_mix -= real_samples_to_mix;
    } while (size);

    tmp_buffer = out_buffer;

    if (mdi->extra_info.mixer_options & WM_MO_REVERB) {
        _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2));
    }


    for (i = 0; i < buffer_used; i += 4) {
        left_mix = *tmp_buffer++;
        right_mix = *tmp_buffer++;

        /*
         * ===================
         * Write to the buffer
         * ===================
         */
#ifdef WORDS_BIGENDIAN
        (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80);
        (*buffer++) = left_mix & 0xff;
        (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80);
        (*buffer++) = right_mix & 0xff;
#else
        (*buffer++) = left_mix & 0xff;
        (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80);
        (*buffer++) = right_mix & 0xff;
        (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80);
#endif
    }

    _WM_Unlock(&mdi->lock);
    return (buffer_used);
}

Project: wildmidi
File: wildmidi_lib.c

static char** WM_LC_Tokenize_Line(char *line_data) {
    int line_length = (int) strlen(line_data);
    int token_data_length = 0;
    int line_ofs = 0;
    int token_start = 0;
    char **token_data = NULL;
    int token_count = 0;

    if (!line_length) return (NULL);

    do {
        /* ignore everything after #  */
        if (line_data[line_ofs] == '#') {
            break;
        }

        if ((line_data[line_ofs] == ' ') || (line_data[line_ofs] == '\t')) {
            /* whitespace means we aren't in a token */
            if (token_start) {
                token_start = 0;
                line_data[line_ofs] = '\0';
            }
        } else {
            if (!token_start) {
                /* the start of a token in the line */
                token_start = 1;
                if (token_count >= token_data_length) {
                    token_data_length += TOKEN_CNT_INC;
                    token_data = realloc(token_data, token_data_length * sizeof(char *));
                    if (token_data == NULL) {
                        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,"to parse config", errno);
                        return (NULL);
                    }
                }

                token_data[token_count] = &line_data[line_ofs];
                token_count++;
            }
        }
        line_ofs++;
    } while (line_ofs != line_length);

    /* if we have found some tokens then add a null token to the end */
    if (token_count) {
        if (token_count >= token_data_length) {
            token_data = realloc(token_data,
                ((token_count + 1) * sizeof(char *)));
        }
        token_data[token_count] = NULL;
    }

    return (token_data);
}

Project: wildmidi
File: wildmidi_lib.c

static int WM_LoadConfig(const char *config_file) {
    return load_config(config_file, NULL);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL void WildMidi_ClearError (void) {
    _WM_Global_ErrorI = 0;
    if (_WM_Global_ErrorS != NULL) {
        free(_WM_Global_ErrorS);
        _WM_Global_ErrorS = NULL;
    }
    return;
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_Close(midi * handle) {
    struct _mdi *mdi = (struct _mdi *) handle;
    struct _hndl * tmp_handle;

    if (!WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (-1);
    }
    if (handle == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
        return (-1);
    }
    if (first_handle == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(no midi's open)", 0);
        return (-1);
    }
    _WM_Lock(&mdi->lock);
    if (first_handle->handle == handle) {
        tmp_handle = first_handle->next;
        free(first_handle);
        first_handle = tmp_handle;
        if (first_handle)
            first_handle->prev = NULL;
    } else {
        tmp_handle = first_handle;
        while (tmp_handle->handle != handle) {
            tmp_handle = tmp_handle->next;
            if (tmp_handle == NULL) {
                break;
            }
        }
        if (tmp_handle) {
            tmp_handle->prev->next = tmp_handle->next;
            if (tmp_handle->next) {
                tmp_handle->next->prev = tmp_handle->prev;
            }
            free(tmp_handle);
        }
    }

    _WM_freeMDI(mdi);

    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_ConvertToMidi (const char *file, uint8_t **out, uint32_t *size) {
    uint8_t *buf;
    int ret;

    if (!file) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL filename)", 0);
        return (-1);
    }
    if ((buf = (uint8_t *) _WM_BufferFile(file, size)) == NULL) {
        return (-1);
    }

    ret = WildMidi_ConvertBufferToMidi(buf, *size, out, size);
    free(buf);
    return ret;
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_FastSeek(midi * handle, unsigned long int *sample_pos) {
    struct _mdi *mdi;
    struct _event *event;
    struct _note *note_data;

    if (!WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (-1);
    }
    if (handle == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
        return (-1);
    }
    if (sample_pos == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL seek position pointer)", 0);
        return (-1);
    }

    mdi = (struct _mdi *) handle;
    _WM_Lock(&mdi->lock);
    event = mdi->current_event;

    /* make sure we havent asked for a positions beyond the end of the song. */
    if (*sample_pos > mdi->extra_info.approx_total_samples) {
        /* if so set the position to the end of the song */
        *sample_pos = mdi->extra_info.approx_total_samples;
    }

    /* was end of song requested and are we are there? */
    if (*sample_pos == mdi->extra_info.approx_total_samples) {
        /* yes */
        _WM_Unlock(&mdi->lock);
        return (0);
    }

    /* did we want to fast forward? */
    if (mdi->extra_info.current_sample > *sample_pos) {
        /* no - reset some stuff */
        event = mdi->events;
        _WM_ResetToStart(handle);
        mdi->extra_info.current_sample = 0;
        mdi->samples_to_mix = 0;
    }

    if ((mdi->extra_info.current_sample + mdi->samples_to_mix) > *sample_pos) {
        mdi->samples_to_mix = (mdi->extra_info.current_sample + mdi->samples_to_mix) - *sample_pos;
        mdi->extra_info.current_sample = *sample_pos;
    } else {
        mdi->extra_info.current_sample += mdi->samples_to_mix;
        mdi->samples_to_mix = 0;
        while ((!mdi->samples_to_mix) && (event->do_event)) {
            event->do_event(mdi, &event->event_data);
            mdi->samples_to_mix = event->samples_to_next;
                
            if ((mdi->extra_info.current_sample + mdi->samples_to_mix) > *sample_pos) {
                mdi->samples_to_mix = (mdi->extra_info.current_sample + mdi->samples_to_mix) - *sample_pos;
                mdi->extra_info.current_sample = *sample_pos;
            } else {
                mdi->extra_info.current_sample += mdi->samples_to_mix;
                mdi->samples_to_mix = 0;
            }
            event++;
        }
        mdi->current_event = event;
    }

    /*
     * Clear notes as this is a fast seek so we only care
     * about new notes.
     *
     * NOTE: This function is for performance only.
     * Might need a WildMidi_SlowSeek if we need better accuracy.
     */
    note_data = mdi->note;
    if (note_data) {
        do {
            note_data->active = 0;
            if (note_data->replay) {
                note_data->replay = NULL;
            }
            note_data = note_data->next;
        } while (note_data);
    }
    mdi->note = NULL;

    /* clear the reverb buffers since we not gonna be using them here */
    _WM_reset_reverb(mdi->reverb);

    _WM_Unlock(&mdi->lock);
    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

WildMidi_GetInfo(midi * handle) {
    struct _mdi *mdi = (struct _mdi *) handle;
    if (!WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (NULL);
    }
    if (handle == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
        return (NULL);
    }
    _WM_Lock(&mdi->lock);
    if (mdi->tmp_info == NULL) {
        mdi->tmp_info = malloc(sizeof(struct _WM_Info));
        if (mdi->tmp_info == NULL) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set info", 0);
            _WM_Unlock(&mdi->lock);
            return (NULL);
        }
        mdi->tmp_info->copyright = NULL;
    }
    mdi->tmp_info->current_sample = mdi->extra_info.current_sample;
    mdi->tmp_info->approx_total_samples = mdi->extra_info.approx_total_samples;
    mdi->tmp_info->mixer_options = mdi->extra_info.mixer_options;
    mdi->tmp_info->total_midi_time = (mdi->tmp_info->approx_total_samples * 1000) / _WM_SampleRate;
    if (mdi->extra_info.copyright) {
        free(mdi->tmp_info->copyright);
        mdi->tmp_info->copyright = malloc(strlen(mdi->extra_info.copyright) + 1);
        if (mdi->tmp_info->copyright == NULL) {
            free(mdi->tmp_info);
            mdi->tmp_info = NULL;
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set copyright", 0);
            _WM_Unlock(&mdi->lock);
            return (NULL);
        } else {
            strcpy(mdi->tmp_info->copyright, mdi->extra_info.copyright);
        }
    } else {
        mdi->tmp_info->copyright = NULL;
    }
    _WM_Unlock(&mdi->lock);
    return ((struct _WM_Info *)mdi->tmp_info);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL char * WildMidi_GetLyric (midi * handle) {
    struct _mdi *mdi = (struct _mdi *) handle;
    char * lyric = NULL;

    if (!WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (NULL);
    }
    if (handle == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
        return (NULL);
    }
    _WM_Lock(&mdi->lock);
    lyric = mdi->lyric;
    mdi->lyric = NULL;
    _WM_Unlock(&mdi->lock);
    return (lyric);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_GetMidiOutput(midi * handle, int8_t **buffer, uint32_t *size) {
    if (__builtin_expect((!WM_Initialized), 0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (-1);
    }
    if (__builtin_expect((handle == NULL), 0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
        return (-1);
    }
    if (__builtin_expect((buffer == NULL), 0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0);
        return (-1);
    }
    return _WM_Event2Midi(handle, (uint8_t **)buffer, size);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_GetOutput(midi * handle, int8_t *buffer, uint32_t size) {
    if (__builtin_expect((!WM_Initialized), 0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (-1);
    }
    if (__builtin_expect((handle == NULL), 0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
        return (-1);
    }
    if (__builtin_expect((buffer == NULL), 0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0);
        return (-1);
    }
    if (__builtin_expect((size == 0), 0)) {
        return (0);
    }
    if (__builtin_expect((!!(size % 4)), 0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0);
        return (-1);
    }

    if (((struct _mdi *) handle)->extra_info.mixer_options & WM_MO_ENHANCED_RESAMPLING) {
        if (!gauss_table) init_gauss();
        return (WM_GetOutput_Gauss(handle, buffer, size));
    }
    return (WM_GetOutput_Linear(handle, buffer, size));
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL const char *WildMidi_GetString(uint16_t info) {
    static char WM_Version[] = "WildMidi Processing Library " PACKAGE_VERSION;
    switch (info) {
    case WM_GS_VERSION:
        return WM_Version;
    }
    return NULL;
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL long WildMidi_GetVersion (void) {
    return (LIBWILDMIDI_VERSION);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_MasterVolume(uint8_t master_volume) {
    if (!WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (-1);
    }
    if (master_volume > 127) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
                "(master volume out of range, range is 0-127)", 0);
        return (-1);
    }

    _WM_MasterVolume = _WM_lin_volume[master_volume];

    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_SetCvtOption(uint16_t tag, uint16_t setting) {
    _WM_Lock(&WM_ConvertOptions.lock);
    switch (tag) {
    case WM_CO_XMI_TYPE: /* validation happens in xmidi.c */
        WM_ConvertOptions.xmi_convert_type = setting;
        break;
    case WM_CO_FREQUENCY: /* validation happens in format */
        WM_ConvertOptions.frequency = setting;
        break;
    default:
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid setting)", 0);
        _WM_Unlock(&WM_ConvertOptions.lock);
        return (-1);
    }
    _WM_Unlock(&WM_ConvertOptions.lock);
    return (0);
}

Project: wildmidi

WM_SYMBOL int WildMidi_SetOption(midi * handle, uint16_t options, uint16_t setting) {
    struct _mdi *mdi;

    if (!WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (-1);
    }
    if (handle == NULL) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
        return (-1);
    }

    mdi = (struct _mdi *) handle;
    _WM_Lock(&mdi->lock);
    if ((!(options & 0x800F)) || (options & 0x7FF0)) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", 0);
        _WM_Unlock(&mdi->lock);
        return (-1);
    }
    if (setting & 0x7FF0) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid setting)", 0);
        _WM_Unlock(&mdi->lock);
        return (-1);
    }

    mdi->extra_info.mixer_options = ((mdi->extra_info.mixer_options & (0x80FF ^ options))
                                    | (options & setting));

    if (options & WM_MO_LOG_VOLUME) {
            _WM_AdjustChannelVolumes(mdi, 16);  // Settings greater than 15
    } else if (options & WM_MO_REVERB) {
        _WM_reset_reverb(mdi->reverb);
    }

    _WM_Unlock(&mdi->lock);
    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

WM_SYMBOL int WildMidi_Shutdown(void) {
    if (!WM_Initialized) {
        _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
        return (-1);
    }
    while (first_handle) {
        /* closes open handle and rotates the handles list. */
        WildMidi_Close((struct _mdi *) first_handle->handle);
    }
    WM_FreePatches();
    free_gauss();

    /* reset the globals */
    _cvt_reset_options ();
    _WM_MasterVolume = 948;
    _WM_MixerOptions = 0;
    _WM_fix_release = 0;
    _WM_auto_amp = 0;
    _WM_auto_amp_with_amp = 0;
    _WM_reverb_room_width = 16.875f;
    _WM_reverb_room_length = 22.5f;
    _WM_reverb_listen_posx = 8.4375f;
    _WM_reverb_listen_posy = 16.875f;

    WM_Initialized = 0;

    if (_WM_Global_ErrorS != NULL) free(_WM_Global_ErrorS);

    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

uint16_t _cvt_get_option (uint16_t tag) {
    uint16_t r = 0;
    _WM_Lock(&WM_ConvertOptions.lock);
    switch (tag) {
    case WM_CO_XMI_TYPE: r = WM_ConvertOptions.xmi_convert_type; break;
    case WM_CO_FREQUENCY: r = WM_ConvertOptions.frequency; break;
    }
    _WM_Unlock(&WM_ConvertOptions.lock);
    return r;
}

Project: wildmidi
File: wildmidi_lib.c

static int add_handle(void * handle) {
    struct _hndl *tmp_handle = NULL;

    if (first_handle == NULL) {
        first_handle = malloc(sizeof(struct _hndl));
        if (first_handle == NULL) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, " to get ram", errno);
            return (-1);
        }
        first_handle->handle = handle;
        first_handle->prev = NULL;
        first_handle->next = NULL;
    } else {
        tmp_handle = first_handle;
        if (tmp_handle->next) {
            while (tmp_handle->next)
                tmp_handle = tmp_handle->next;
        }
        tmp_handle->next = malloc(sizeof(struct _hndl));
        if (tmp_handle->next == NULL) {
            _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, " to get ram", errno);
            return (-1);
        }
        tmp_handle->next->prev = tmp_handle;
        tmp_handle = tmp_handle->next;
        tmp_handle->next = NULL;
        tmp_handle->handle = handle;
    }
    return (0);
}

Project: wildmidi
File: wildmidi_lib.c

static void free_gauss(void) {
    _WM_Lock(&gauss_lock);
    free(gauss_table);
    gauss_table = NULL;
    _WM_Unlock(&gauss_lock);
}

Project: wildmidi
File: wildmidi_lib.c

static void init_gauss(void) {
    /* init gauss table */
    int n = gauss_n;
    int m, i, k, n_half = (n >> 1);
    int j;
    int sign;
    double ck;
    double x, x_inc, xz;
    double z[35];
    double *gptr, *t;

    _WM_Lock(&gauss_lock);
    if (gauss_table) {
        _WM_Unlock(&gauss_lock);
        return;
    }

    newt_coeffs[0][0] = 1;
    for (i = 0; i <= n; i++) {
        newt_coeffs[i][0] = 1;
        newt_coeffs[i][i] = 1;

        if (i > 1) {
            newt_coeffs[i][0] = newt_coeffs[i - 1][0] / i;
            newt_coeffs[i][i] = newt_coeffs[i - 1][0] / i;
        }

        for (j = 1; j < i; j++) {
            newt_coeffs[i][j] = newt_coeffs[i - 1][j - 1]
                    + newt_coeffs[i - 1][j];
            if (i > 1)
                newt_coeffs[i][j] /= i;
        }
        z[i] = i / (4 * M_PI);
    }

    for (i = 0; i <= n; i++)
        for (j = 0, sign = (int) pow(-1, i); j <= i; j++, sign *= -1)
            newt_coeffs[i][j] *= sign;

    t = malloc((1<<FPBITS) * (n + 1) * sizeof(double));
    x_inc = 1.0 / (1<<FPBITS);
    for (m = 0, x = 0.0; m < (1<<FPBITS); m++, x += x_inc) {
        xz = (x + n_half) / (4 * M_PI);
        gptr = &t[m * (n + 1)];

        for (k = 0; k <= n; k++) {
            ck = 1.0;

            for (i = 0; i <= n; i++) {
                if (i == k)
                    continue;

                ck *= (sin(xz - z[i])) / (sin(z[k] - z[i]));
            }
            *gptr++ = ck;
        }
    }

    gauss_table = t;
    _WM_Unlock(&gauss_lock);
}

Project: wildmidi
File: wildmidi_lib.c

static inline int wm_isdigit(int c) {
    return (c >= '0' && c <= '9');
}

Project: wildmidi
File: wildmidi_lib.c

static inline int wm_isupper(int c) {
    return (c >= 'A' && c <= 'Z');
}

Project: wildmidi
File: wildmidi_lib.c

static int wm_strcasecmp(const char *s1, const char * s2) {
    const char * p1 = s1;
    const char * p2 = s2;
    char c1, c2;

    if (p1 == p2) return 0;
    do {
        c1 = wm_tolower (*p1++);
        c2 = wm_tolower (*p2++);
        if (c1 == '\0') break;
    } while (c1 == c2);
    return (int)(c1 - c2);
}

Project: wildmidi
File: wildmidi_lib.c

static char *wm_strdup (const char *str) {
    size_t l = strlen(str) + 5;
    char *d = (char *) malloc(l * sizeof(char));
    if (d) {
        strcpy(d, str);
        return (d);
    }
    return (NULL);
}

Project: wildmidi
File: wildmidi_lib.c

static inline int wm_tolower(int c) {
    return ((wm_isupper(c)) ? (c | ('a' - 'A')) : c);
}