/***************************************************
     hb-midilib-midi.c
     Realtime MIDI Library for the MIT Handy Board
     colby leider (cnl@dartmouth.edu)
     last updated 9.16.97

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



/* midi_on:
        enables the SCI to transmit 31.25 kbaud (MIDI's
        baud rate) */
/***************************************************************/
void
midi_on()
{
   poke(0x10102b, 0b00100000);  /* 31.25 kbaud */
   poke(0x3c, 1);  /* disable pcode serial */
   beep();
}


/* midi_off:
        resets the SCI baud rate to 9600 baud allows Interactive
        C to interact with the Handy Board again */
/***************************************************************/
void
midi_off()
{
    poke(0x10102b, 0b11000);  /* 9600 baud */
    poke(0x3c, 0);  /* reenable pcode serial */
}


/* turbo_on:
        speeds Handy Board operation up a bit by disabling
        certain features */
/***************************************************************/
void
turbo_on()
{
   system_pwm_off();
   ir_transmit_off();
   ir_receive_off();
}


/* turbo_off:
        reenables pulse width modulation and the infrared
        subsystem */
/***************************************************************/
void
turbo_off()
{
    system_pwm_on();
    ir_transmit_on();
    ir_receive_on();
}


/* note_on:
        sends MIDI note on message with the given channel, pitch,
        and velocity */
/***************************************************************/
void
note_on(int channel, int pitch, int velocity)
{
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, (143 + channel));
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, pitch);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, velocity);  
}


/* note_off:
        sends MIDI note off message with the given channel and
        pitch */
/***************************************************************/
void
note_off(int channel, int pitch)
{
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 127 + channel);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, pitch);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 0);  
}


/* poly_key_pressure:
        sends MIDI poly key pressure message with the given
        channel, pitch, and pressure value */
/***************************************************************/
void
poly_key_pressure(int channel, int pitch, int pressure_value)
{
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 159 + channel);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, pitch);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, pressure_value);  
}


/* control_change:
        sends MIDI control change message with the given
        channel, controller number, and value */
/***************************************************************/
void
control_change(int channel, int controller, int value)
{
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 175 + channel);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, controller);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, value);  
}


/* program_change:
        sends MIDI program change message with the given channel
        and program number */
/***************************************************************/
void
program_change(int channel, int program)
{
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 191 + channel);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, program);  
}


/* channel_pressure:
        sends MIDI channel pressure message with the given
        channel and pressure value */
/***************************************************************/
void
channel_pressure(int channel, int pressure_value)
{ 
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 207 + channel);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, pressure_value);  
}


/* pitch_bend:
        sends MIDI 7-bit pitch bend message with the given
        channel and pitch bend value */
/***************************************************************/
void
pitch_bend(int channel, int value)
{
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 223 + channel);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 0);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, value);  
}


/* pitch_bend2:
        sends MIDI 14-bit pitch bend message with the given
        channel, least significant byte, and most significant
        byte */
/***************************************************************/
void
pitch_bend2(int channel, int LSB, int MSB)
{
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, 223 + channel);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, LSB);
   while (!(peek(0x102e) & 0x80));
   poke(0x102f, MSB);  
}


/* modulation_depth:
        sends MIDI modulation depth message with the given
        channel and modulation depth value */
/***************************************************************/
void
modulation_depth(int channel, int value)
{
   control_change(channel, MODULATION_WHEEL, value);
}


/* main_volume:
        sends MIDI main volume message with the given channel and main volume
        value */
/***************************************************************/
void
main_volume(int channel, int value)
{
   control_change(channel, MAIN_VOLUME, value);
}


/* pan:
        sends MIDI panpot message with the given channel and
        pan value */
/***************************************************************/
void
pan(int channel, int value)
{
   control_change(channel, PAN, value);
}


/* expression:
        sends MIDI expression message with the given channel and
        expression value */
/***************************************************************/
void
expression(int channel, int value)
{
   control_change(channel, EXPRESSION_CONTROLLER, value);
}


/* sustain_on:
         turns on the MIDI sustain pedal on the given MIDI
         channel */
/***************************************************************/
void
sustain_on(int channel)
{
    control_change(channel, SUSTAIN_PEDAL, 127);
}


/* sustain_off:
        turns off the MIDI sustain pedal on the given MIDI
        channel */
/***************************************************************/
void
sustain_off(int channel)
{
    control_change(channel, SUSTAIN_PEDAL, 0);
}


/* all_sound_off:
        sends a MIDI all sound off channel mode message to the
        given MIDI channel */
/***************************************************************/
void
all_sound_off(int channel)
{
    control_change(channel, ALL_SOUND_OFF_CONTROLLER,
                   ALL_SOUND_OFF_VALUE);
}


/* reset_all_controllers:
        sends a MIDI reset all controllers channel mode message
        to the given MIDI channel */
/***************************************************************/
void
reset_all_controllers(int channel)
{
    control_change(channel, RESET_ALL_CONTROLLERS_CONTROLLER,
                            RESET_ALL_CONTROLLERS_VALUE);
}


/* local_control:
        sends a MIDI local control on/off channel voice message
        to the given MIDI channel.  local_control(0) turns off
        local control, and local_control(1) turns on local
        control. */
/***************************************************************/
void
local_control(int channel, int flag)
{
    int value;
    if (flag == 1) value = 127;
    else value = flag;
    control_change(channel, LOCAL_CONTROL_CONTROLLER, value);
}


/* all_notes_off:
        sends MIDI all notes off (panic) channel voice message
        to the given channel */
/***************************************************************/
void
all_notes_off(int channel)
{
   control_change(channel, ALL_NOTES_OFF_CONTROLLER,
                  ALL_NOTES_OFF_VALUE);
}


/* omni_mode_off:
        turns off MIDI omni mode on the specified MIDI channel */
/***************************************************************/
void
omni_mode_off(int channel)
{
    control_change(channel, OMNI_MODE_OFF_CONTROLLER,
                   OMNI_MODE_OFF_VALUE);
}


/* omni_mode_on:
        turns on MIDI omni mode on the specified MIDI channel */
/***************************************************************/
void
omni_mode_on(int channel)
{
    control_change(channel, OMNI_MODE_ON_CONTROLLER,
                   OMNI_MODE_ON_VALUE);
}


/* mono_mode_on:
        turns on MIDI mono mode on the specified MIDI channel
        with the given number of channels*/
/***************************************************************/
void
mono_mode_on(int channel, int num_channels)
{
    control_change(channel, MONO_MODE_ON_CONTROLLER, num_channels);
}


/* poly_mode_on:
        turns on MIDI poly mode on the specified MIDI channel */
/***************************************************************/
void
poly_mode_on(int channel)
{
    control_change(channel, POLY_MODE_ON_CONTROLLER,
                   POLY_MODE_ON_VALUE);
}


/* midi2octpc:
        returns oct.pc (octave.pitch_class) from MIDI note
        number */
/***************************************************************/
float
midi2octpc(int pitch) {
    return (float)((int)((float)pitch/12.0) + 3) + ((float)(pitch % 12) / 100.0);
}

/* octpc2midi:
        returns MIDI note number from oct.pc
        (octave.pitch_class) */
/***************************************************************/
int
octpc2midi(float octpc)
{
    return ((int)octpc * 12 - 36) + (int)((octpc - (float)(int)octpc) * 100.0);
}


/* midi2oct:
        returns octave from MIDI note number */
/***************************************************************/
int
midi2oct(int pitch) {
    return ((int)((float)pitch/12.0) + 3);
}


/* midi2pc:
        returns the pitch class of a MIDI note number */
/***************************************************************/
int
midi2pc(int pitch) {
    return (pitch % 12);
}

