Dependencies:   mbed

main.cpp

Committer:
Midimetric
Date:
2011-06-07
Revision:
0:71d791204057

File content as of revision 0:71d791204057:

#include "mbed.h"
#include <vector>
#include "MODSERIAL.h"

DigitalOut  led[4] = { LED1, LED2, LED3, LED4 };
MODSERIAL   SL[] = { MODSERIAL( p28, p27, 32, 256 ),
                     MODSERIAL( p13, p14, 32, 256 ),
                     MODSERIAL(  p9, p10, 32, 256 )
                   };
Timer       tempo;
bool        HasBank, HasData, HasSysx; // flags to know if special type messages have a route defined. If not, these will be treated as plain cc or not stored.

int AvailableMemory()
{
    register int low = 0;
    register int mid = 0;
    register int high = 8001;
    void* p = NULL;
    
    while( high - low > 1 ) 
        if( ( p = malloc( mid = ( low + high ) / 2 ) ) == NULL )
            high = mid;
        else 
        {
            free( p );
            low = mid;
        }
    return low;
}

#include "midi.h"
#include "stack.h"

#include "memory.h"
MemList     ML;

#include "filter.h"
FilterList  FL;

#include "parse.h"

byte        Last[] = {0,0,0}; // last message type for ports 1,2,3
MidiM*      Previous[3][17] = {
                {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
                {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
                {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
            }; // keep previous per channel 0-15 or not channeled 16, and per port. Call to Route must use Previous from same channel & port than Current.

void Data_in( int port /* 0,1,2*/ ) 
{ 
    int     v           = SL[port].getc();
    if( v == 0xFE ) return; // active sensing
    
    led[port] = 1;

    MidiM*  current     = NULL;
    int     beforelast  = Last[port]; // backup in case of incomplete message
    // new command
    if( v > 0x7F ) // with explicit command
        current = MidiCreateMessage( Last[port] = v );
    else if( Last[port] ) // with implicit command (same than before)
    {
        current = MidiCreateMessage( Last[port]  );
        current->Append( v );
    }
    else // this is junk
    {
        led[port] = 0;
        return;
    }
    int ch = current->Channel == NAKW ? 16 : current->Channel;

    while( current->Next != NONE )
    {
        tempo.reset();
        tempo.start();
        while( SL[port].rxBufferEmpty() )
        {
            if( tempo.read_us() > 512 ) // normal rate should 256 us beetwen bytes. If twice that,  assume message end is lost.
            {
                if( current->Type==BANK || current->Type==DATA || current->Type==RPN_ || current->Type==NRPN ) // LSB may be skipped
                { 
                    current->Next = NONE;
                    break; 
                }
                // else, abort reading this message without transmission
                tempo.stop();
                Last[port] = beforelast; // forget last received command
                delete current;
                current = NULL;
                led[port] = 0;
                return;
            }
        }
        tempo.stop();
        
        if( current->Next != NONE ) 
        {
            int b = SL[port].getcNb();
            if( ( b > -1 )  &&  ( b < 0xF8 ) ) // to ignore real time messages
            {
                if( ! current->Append( b ) )
                {
                // not a pair message (for example: NRPN lsb not followed by msb but by DATA)
                    if( current->Type==RPN_ || current->Type==NRPN || current->Type==BANK )
                    {
                        if( Previous[ ch ][port] != NULL ) delete Previous[ ch ][port];
                        Previous[ ch ][port] = current;
                        current = MidiCreateMessage( Last[port]  );
                        if( current->Next != NONE ) 
                            current->Append( b );
                    }
                }
            }
        }
    }
    // now message is complete (or LSB/MSB from compound message will not follow)
    led[port] = 0;
    
    FL.Route( port, *current, *(Previous[ current->Channel == NAKN ? 16 : current->Channel ][port]) ); // pass also 'previous' in case of multipart messages (RPN|NRP)+(DATA|INC|DEC)
    if( current->Type != DATA && current->Type != INCR && current->Type != DECR )
    {
        if( Previous[ ch ][port] != NULL ) delete Previous[ ch ][port];
        Previous[ ch ][port] = current;
        current = NULL;
    }
    else
        delete current;

}

void Blinking( int ntimes )
{
    if( ntimes )
    {
        for( int i = 0 ; i < ntimes ; i++ )
        {
            led[3] = 1;
            wait(0.2);
            led[3] = 0;
            wait(0.6);
        }
        wait(2);
    }
}

int main()
{
    for( int i = 0 ; i < 3 ; i++ ) SL[i].baud( 31250 );
    
    if( ! Parse() )
    {
        Blinking(ParseError);
        return 0;
    }

    while(1)
    {
        for( int i = 0 ; i < 3 ; i++ ) if( SL[i].readable() ) Data_in(i);
    }

}