Gemphet8 ; 8-polyphonic synthesizer control application

Dependencies:   MIDI REnc button mbed

MIDI_Proc/midi_proc.cpp

Committer:
ChuckTimber
Date:
2014-08-11
Revision:
4:c18cfcad2c48

File content as of revision 4:c18cfcad2c48:

#include "midi_proc.h"

using namespace mbed;

MIDI_P::MIDI_P(PinName tx, PinName rx) : _midi(tx, rx)
{
    NoteEnd = { 255, 255, 15, 0 };
    NoteStart = { 0, 0, 0, &NoteEnd };
    NumOfNotes = POLYPHONICE_NOTES;
}


/// @brief  Reset all MIDI controller
void MIDI_P::midi_allnoteoff(void)
{
    int i;
    uint16_t msk;

    for (i = 0, msk = 0x01; i < NumOfNotes; i++, msk<<=1) {
        if (MidiNotesTag & msk) {
            _midi.sendNoteOff(MidiNotes[i].Note, MidiNotes[i].Velocity, MidiNotes[i].Channel);
            MidiNotesTag &= ~msk;
        }
    }

    MidiNotesTag = 0x0000;
    NoteEnd.next = NULL;
    NoteStart.next = &NoteEnd;
}

/// @brief  Reset MIDI controller
void MIDI_P::midi_resetcontrol(void)
{
}

/// @brief  Reset all MIDI controller
void MIDI_P::midi_sysreset(void)
{
    midi_allnoteoff();
    midi_resetcontrol();
}

/// @brief  MIDI note structure allocate function
MN_p MIDI_P::allocN(void)
{
    int i;
    uint16_t msk;

    for (i = 0, msk = 0x01; i < NumOfNotes; i++, msk<<=1) {
        if (!(MidiNotesTag & msk)) {
            MidiNotesTag |= msk;
            MidiNotes[i].Channel = i;
            return (&MidiNotes[i]);
        }
    }
    return NULL;
}

/// @brief  MIDI note structure free function
void MIDI_P::freeN(MN_p addr)
{
    int i;
    uint16_t msk;

    for (i = 0, msk = 0x01; i < NumOfNotes; i++, msk<<=1) {
        if (addr == &MidiNotes[i])
            MidiNotesTag &= ~msk;
    }
}

/// @brief  MIDI Control Change callback funcion
void MIDI_P::midi_cc(byte channel, byte number, byte value)
{
    if (number == MIDI_ALL_NOTE_OFF) {
        midi_allnoteoff();
    }
    if (number == MIDI_RESET_ALL_CONTROLLERS) {
        midi_resetcontrol();
    }
    _midi.sendControlChange(number, value, channel);
}

/// @brief  MIDI Program Change callback funcion
void MIDI_P::midi_pc(byte channel, byte number)
{
    _midi.sendProgramChange(number, channel);
}

/// @brief  MIDI Pitch Bend callback funcion
void MIDI_P::midi_pbend(byte channel, int bend)
{
    _midi.sendPitchBend(bend, channel);
}

/// @brief  MIDI Note On callback funcion
void MIDI_P::midi_noteon(byte channel, byte note, byte velocity)
{
    MN_p ptr, newnote;

    if ((newnote = allocN()) == NULL) { // if table full, release oldest note
        ptr = NoteStart.next;
        _midi.sendNoteOff(ptr->Note, ptr->Velocity, ptr->Channel);
        NoteStart.next = ptr->next;
        freeN(ptr);
        newnote = allocN();
    }
    newnote->Note = note;
    newnote->Velocity = velocity;
    // newnote->Channel // do not set channel
    _midi.sendNoteOn(note, velocity, newnote->Channel);
    for (ptr = &NoteStart; ptr->next; ptr = ptr->next) {    // put newnote on the tail
        if (ptr->next == &NoteEnd) {
            newnote->next = ptr->next;
            ptr->next = newnote;
            break;
        }
    }
}

/// @brief  MIDI Note Off callback funcion
void MIDI_P::midi_noteoff(byte channel, byte note, byte velocity)
{
    MN_p ptr, lastptr;

    for (ptr = &NoteStart; ptr->next; ptr = ptr->next) {
        if (note == ptr->next->Note) {
            lastptr = ptr->next;
            _midi.sendNoteOff(lastptr->Note, lastptr->Velocity, lastptr->Channel);
            ptr->next = lastptr->next;
            freeN(lastptr);
            break;
        }
    }
}

void MIDI_P::Init(void)
{
    _midi.setHandleNoteOff((void (*))(&MIDI_P::midi_noteoff));
    _midi.setHandleNoteOn(&MIDI_P::midi_noteon);
    _midi.setHandleControlChange(&MIDI_P::midi_cc);
    _midi.setHandleProgramChange(&MIDI_P::midi_pc);
    _midi.setHandlePitchBend(&MIDI_P::midi_pbend);
    _midi.setHandleSystemReset(&MIDI_P::midi_sysreset);
}