/***************************************************
     hb-midilib-misc.c
     Realtime MIDI LIbrary for the MIT HandyBoard
     colby leider (cnl@dartmouth.edu)
     last updated 9.16.97

     http://music.dartmouth.edu/~colby/hb.html
***************************************************/




/* midi_test:
        sends a MIDI note on message to each MIDI channel (1-16)
        with velocity 127.  each note on message lasts 500 ms and
        is followed by a 500 ms pause. */
/***************************************************************/
void
midi_test()
{
   int i;
   midi_on();
   for (i=1; i<=16; i++)
   {
      /* play middle C on the ith channel with maximum velocity */
      note_on(i, 60, 127);
      msleep(500L);
      note_off(i, 60);
      msleep(500L);
   }
}


/* ramp:
        sends a stream of ramped MIDI note on messages to the
        given MIDI channel, each of which is separated by the
        specified time delay in seconds.  the note on ramp begins
        with the specified base pitch and increases each
        successive note's pitch according to a given multiplier
        factor until num_notes have been played */
/***************************************************************/
void
ramp(int channel, int base_pitch, int velocity, float time_delay, int multiplier, int num_notes)
{
   int i;
   for (i=0; i<num_notes; i++)
    {
            note_on(channel, base_pitch + (i * multiplier), velocity);
            sleep(time_delay);
    }
}


/* arpeggiate:
        arpeggiates a note on the given MIDI channel with the
        given velocity.  each note of the arpeggio is separated
        by the given time delay in seconds.  the semitone
        separation of each pitch of the arpeggio relative to the
        given base pitch is passed in the array 'offsets'. */
/***************************************************************/
void
arpeggiate(int channel, int base_pitch, int velocity, float time_delay, int offsets[])
{
    int i;
   for (i=0; i<_array_size(offsets); i++)
    {
            note_on(channel, base_pitch + offsets[i], velocity);
            sleep(time_delay);
            /* provide note off messages if desired */
    }
}


/* flutter:
        plays a given number of pitches centered around the
        specified base pitch, each separated by the given time
        delay in seconds, with a maximum pitch deviation from the
        base pitch given by 'pitch_variance' (in semitones) */
/***************************************************************/
void
flutter(int channel, int base_pitch, int velocity, int pitch_variance, float time_delay, int num_notes)
{
    int i;
    for (i=0; i<num_notes; i++)
    {
        note_on(channel, base_pitch + random(pitch_variance), velocity);
        /* add a note_off message here if necessary for the specific timbre */
        sleep(time_delay);
    }
}


/* harmonize:
        plays a chord of pitches based on the specified
        base_pitch.  the interval in semitones between each
        member of the chord and the base pitch is given in the
        array 'offsets'. */
/***************************************************************/
void
harmonize(int channel, int base_pitch, int velocity, int offsets[])
{
    int i;
    note_on(channel, base_pitch, velocity);
    for (i=0; i<_array_size(offsets); i++)
    {
        note_on(channel, base_pitch + offsets[i], velocity);
    }
}


/* random_midi:
        plays a random pitch on a random MIDI channel with a
        random program for the specified duration in seconds */
/***************************************************************/
void
random_midi(float dur)
{
    int ch, pitch, velocity;
    ch = 1 + random(16);
    pitch = random(127);
    velocity = random(127);
    program_change(random(127), ch);
    note_on(ch, pitch, velocity);
    sleep(dur);
    note_off(ch, pitch);
}


/* midi_hpf:
        midi high pass filter.  only pitches greater than or
        equal to the specified cutoff are returned.  a 0 is
        returned if the filter blocked the pitch. */
/***************************************************************/
int
midi_hpf(int pitch, int cutoff)
{
    if (pitch >= cutoff) return pitch;
    else return 0;
}


/* midi_lpf:
        midi low pass filter.  only pitches less than or equal to
        the specified cutoff are returned.  a 0 is returned if
        the filter blocked the pitch. */
/***************************************************************/
int
midi_lpf(int pitch, int cutoff)
{
    if (pitch <= cutoff) return pitch;
    else return 0;
}


/* midi_bpf:
        midi band pass filter.  only pitches falling within the
        specified cutoffs are returned.  a 0 is returned if the
        filter blocked the pitch. */
/***************************************************************/
int
midi_bpf(int pitch, int cutoff1, int cutoff2)
{
    if (pitch >= cutoff1 && pitch <= cutoff2) return pitch;
    else return 0;
}


/* midi_notch:
        midi notch filter.  only pitches falling outside the
        specified cutoffs are returned.  a 0 is returned if the
        filter blocked the pitch. */
/***************************************************************/
int
midi_notch(int pitch, int cutoff1, int cutoff2)
{
    if (pitch <= cutoff1 && pitch >= cutoff2) return pitch;
    else return 0;
}


/* stutter:
        plays the specidied number MIDI notes on the given
        channel, each separated by a time delay randomized
        according to the given stutter factor */
/***************************************************************/
void
stutter(int channel, int pitch, int velocity, int num_notes, int stutter_factor)
{
    int i;
    for (i=0; i<num_notes; i++)
    {
        note_on(channel, pitch, velocity);
        sleep((float)random(stutter_factor) + (float)random(9)*0.1);
    }
}


/* noodle:
        idles until the start button is pressed.  then, noodle
        plays various MIDI pitches on random MIDI channels
        (separated by 150-650 ms) until the Handy Board's stop
        button is pressed. */
/***************************************************************/
void noodle()
{
    int channel, pitch;
    while (!start_button());  /* wait for start button to be pressed */
    channel = 1;  /* bogus initial values... */
    pitch = 1;
    while (!stop_button())  /* loop until stop button is pressed */
    {
        note_off(channel, pitch);
        channel = 1 + random(16);
        pitch = 40 + random(80);
        note_on(channel, pitch, 64 + random(64));
        printf("ch=%d, pch=%d", channel, pitch);
        sleep(0.15);
        msleep((long)random(500));
    }
}