Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
Midimetric
Date:
Tue Jun 07 13:32:20 2011 +0000
Commit message:
Version 1.0

Changed in this revision

MODSERIAL.lib Show annotated file Show diff for this revision Revisions of this file
filter.h Show annotated file Show diff for this revision Revisions of this file
filter_debug.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
memory.h Show annotated file Show diff for this revision Revisions of this file
midi.h Show annotated file Show diff for this revision Revisions of this file
parse.h Show annotated file Show diff for this revision Revisions of this file
stack.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL.lib	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/code/MODSERIAL/#af2af4c61c2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/filter.h	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,471 @@
+#include <vector>
+#include "midi.h"
+#include "stack.h"
+#include "memory.h"
+
+#define TO_OUT1 1
+#define TO_OUT2 2
+#define TO_OUT3 4
+
+#define BitSet( flag, bit )  ( ( flag >> bit ) & 1 )
+#define BitPut( flag, bit )  ( flag | ( 1 << bit ) )
+#define BitDel( flag, bit )  ( flag & ~( 1 << bit ) )
+
+// literals are either 8 bits ( 0 to 255 ) or 14 bits ( 0 to 16383 / -8192 to 8191 )
+// commands are coded with bit 14 set (above 16383 ) but not with bit 15 to leave negative down to -8192 to literals and to avoid ambiguity
+
+#define ISCOMMAND(x) ( (x & 0xF000) == 0x4000 )
+
+// sequence delimiter
+#define SEQ 0x4000 // escape; introducing a sequence in a Chain:
+#define E7_ 0x4001 // return 7 bits byte from computation
+#define E8_ 0x4002 // return 8 bits byte from computation
+#define E14 0x4003 // return 14 bits word from computation (msb then lsb)
+#define NOP 0x4004 // nul terminator in sequence array
+#define RAW 0x4005 // output is raw input (no change)
+// VALUES
+#define VMC 0x4010 // =%mc Full midi command (base command + channel), can be used in sequence or alone
+#define VM_ 0x4011 // =%m Base midi command (4 msb of VMC ), can be used in sequence or alone
+#define VC_ 0x4012 // =%c Value of Channel (4 lsb of VMC )
+#define VA_ 0x4013 // Value A, can be used in sequence or alone
+#define VB_ 0x4014 // Value B
+#define VN_ 0x4015 // RPN or NRPN 14bits number
+#define VD_ 0x4016 // RPN or NRPN 14bits data
+#define VK_ 0x4017 // Bank 14bits data
+
+// FUNCTIONS
+#define ADD 0x4020
+#define SUB 0x4021 // Add 14 bits value as signed integer, bound to 0 - 0xFFFF
+#define MUL 0x4022
+#define DIV 0x4023
+#define MOD 0x4024
+#define BIT 0x4125 // folowing int is index value then bit shift then bits count
+#define BOR 0x4026 // bynary OR
+#define BAN 0x4027 // bynary AND
+#define BNO 0x4028 // bynary NOT
+#define BSL 0x4029 // bynary shift left (<<)
+#define BSR 0x402A // bynary shift right (>>)
+#define MAP 0x402B // discrete value mapping
+#define RPN 0x402C // RPN type formated output
+#define NPN 0x402D // NRPN type formated output
+#define BNK 0x402E // Bank type formated output
+#define MSB 0x402F // msb part of value
+#define LSB 0x4030 // lsb part of value
+#define NP8 0x4031 // 8 bit value NRPN (sends only CC6 not CC38)
+
+// checkSUm
+// - compute checksum from value after 'SUB' to value before 'SUE'
+#define CSB 0x4040 // checkSUm Begin
+#define CSE 0x4041 // checkSUm End
+#define CS1 0x4042 // insert 8 bit checksum at position (careful:may appear before SUB-SUE range)
+#define CS2 0x4043 // 32 bits checksum
+// Checksum Type1 (Roland) : -( sum( SUB -> SUE ) & 127 ) & 127
+// Checksum Type2 (Alesis) : -( sum( SUB -> SUE ) & 0xFFFF ) & 0xFFFF
+
+// custom identifiers
+#define CID 0x4100 // end of Custom IDentifier
+//          0x41cc // cc = ascii char index
+#define CUL 0x4200 // Custom identifier character set Upper Limit
+
+#if _DEBUGFILTER
+#include "filter_debug.h"
+#endif
+
+// error codes returned by Compute
+#define CHAIN_SKIPROUTE     -1
+#define CHAIN_NOERROR        0
+#define CHAIN_STACK_FAILURE  1
+#define CHAIN_MISSING_SUB    2
+#define CHAIN_MISSING_SUE    3
+#define CHAIN_SUB_AFTER_SUE  4
+#define CHAIN_NOT_A_BYTE     5
+#define CHAIN_UNKNOWN_OP     6
+#define CHAIN_SYNTAXE_ERROR  7
+#define CHAIN_DIVIDE_BY_ZERO 8
+
+#define NEXT                i++; break;
+#define PUSH(x)             Out.push_back(x)
+
+short bitmasking[] = {0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383};
+
+//_____________________________________________________________________________
+class Chain
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+// a chain defines for each port a message composed of fixed bytes or symbols
+public:
+    vector<short> Msg[3];
+    vector<byte> Out;
+
+    Chain()                                                                { }
+    Chain( vector<short> &msg1, vector<short> &msg2, vector<short> &msg3 ) { Msg[0] = msg1; Msg[1] = msg2; Msg[2] = msg3; }
+    ~Chain()                                                               { }
+
+    void Done() // clear output vector until next compute to avoid keeping computation for all filters in memory
+    {
+        Out.clear();
+    }
+    short Compute( byte port, MidiM &cur, MidiM &prev ) // 0=ok, else return error code
+    {
+        short max = Msg[port].size();
+        if( max == 0 ) return -1;
+
+        Stack<long> k;
+        long        a,b,c,d;     // temp
+        short       i   = 0;     // next position in Msg
+        bool        s   = false; // true when "in sequence"
+        short       csb = -1;    // position of check sum begin
+        short       cse = -1;    // position of check sum end
+        short       csu = 0;     // position where to insert check sum
+        short       cst = 0;     // check sum type
+
+        Out.clear();
+
+        while( i < max )
+        {
+            short n = Msg[port][i];
+            if( ! s  ) // out of sequence, expect a byte value or a custom identifier or SEQ
+            {
+                if( n < 256 ) { PUSH( (byte)n ); i++; } // just copy fixed message byte
+                else if( ! ISCOMMAND( n ) )    return CHAIN_NOT_A_BYTE;        // short values are not allowed outside of sequence
+                else switch( n ) {
+                    case SEQ :     s = true;                                                        NEXT
+                    case VMC :    PUSH( cur.Command | ( cur.Channel == NAKN ? 0 : cur.Channel ) );  NEXT
+                    case VM_ :    PUSH( cur.Command );                                              NEXT
+                    case VC_ :    PUSH( cur.Channel == NAKN ? 0 : cur.Channel );                    NEXT
+                    case VA_ :    PUSH( cur.ValA );                                                 NEXT
+                    case VB_ :    PUSH( cur.ValB );                                                 NEXT
+                    case VN_ :    PUSH( prev.ValA ); PUSH( prev.ValB );                             NEXT
+                    case VD_ :    PUSH( cur.ValA );  PUSH( cur.ValB );                              NEXT
+                    case VK_ :    PUSH( cur.ValA );  PUSH( cur.ValB );                              NEXT
+
+                    case RAW :  if( ( cur.Type == DATA || cur.Type == INCR || cur.Type == DECR )
+                                &&  ( prev.Type == NRPN || prev.Type == RPN_ ) )
+                                {   
+                                    Out = prev.Raw; Out.insert( Out.end(), cur.Raw.begin(), cur.Raw.end() );
+                                }
+                                else Out = cur.Raw; 
+                                return 0;
+
+                    default  : {char id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; short idi = 0;
+                                while( n > CID && n < CUL ) { id[idi++] = (char)(n - CID); n = Msg[port][++i]; }
+                                PUSH( (byte)ML.Get( id ) ); }                                       NEXT
+                }
+            }
+            else if( ! ISCOMMAND( n ) ) // 14 bit literal inside a sequence, push on stack
+            {
+                k.Push( n ); i++;
+            }
+            else switch( n )
+            {
+                case NOP :                                                                        NEXT
+                case E7_ : k.Pull(a); if(a < 0) a=0; else if(a > 127) a=127; PUSH(a); s = false;  NEXT
+                case E8_ : k.Pull(a); if(a < 0) a=0; else if(a > 255) a=255; PUSH(a); s = false;  NEXT
+                case E14 : k.Pull(a); PUSH( (byte)(a >> 7) & 127 ); PUSH(a & 127); s = false;     NEXT
+                case VMC : k.Push( cur.Command|( cur.Channel == NAKN ? 0 : cur.Channel ) );       NEXT
+                case VM_ : k.Push( cur.Command );                                                 NEXT
+                case VC_ : k.Push( ( cur.Channel == NAKN ? 0 : cur.Channel ) );                   NEXT
+                case VA_ : k.Push( cur.ValA );                                                    NEXT
+                case VB_ : k.Push( cur.ValB );                                                    NEXT
+                case VN_ : k.Push( prev.Get14() );                                                NEXT
+                case VD_ : k.Push( cur.Get14() );                                                 NEXT
+                case VK_ : k.Push( cur.Get14() );                                                 NEXT
+                case ADD : k.Pull( b, a ); k.Push( a + b );                                       NEXT
+                case SUB : k.Pull( b, a ); k.Push( a - b );                                       NEXT
+                case MUL : k.Pull( b, a ); k.Push( a * b );                                       NEXT
+                case DIV : k.Pull( b, a ); if(b==0) return CHAIN_DIVIDE_BY_ZERO; k.Push( a / b ); NEXT
+                case MOD : k.Pull( b, a ); if(b==0) return CHAIN_DIVIDE_BY_ZERO; k.Push( a % b ); NEXT
+                case BIT : k.Pull( c,b,a); k.Push(cur.Raw[a] >> b & bitmasking[c]);               NEXT
+                case BOR : k.Pull( b, a ); k.Push( a | b );                                       NEXT
+                case BAN : k.Pull( b, a ); k.Push( a & b );                                       NEXT
+                case BNO : k.Pull(    a ); k.Push( ~a    );                                       NEXT
+                case BSL : k.Pull( b, a ); k.Push( a << b );                                      NEXT
+                case BSR : k.Pull( b, a ); k.Push( a >> b );                                      NEXT
+                case MSB : k.Pull( a ); k.Push( a >> 7 );                                         NEXT
+                case LSB : k.Pull( a ); k.Push( a & 127 );                                        NEXT
+                case CSB : csb=Out.size(); s = false; /*quit sequence not waiting for END*/       NEXT
+                case CSE : cse=Out.size(); s = false;                                             NEXT
+                case CS1 : csu=Out.size(); cst=1; PUSH(0);                                        NEXT
+                case CS2 : csu=Out.size(); cst=2; PUSH(0); PUSH(0); PUSH(0); PUSH(0);             NEXT
+                case MAP : k.Pull( d, a, c, b ); d--;
+                           while( a != b )
+                               if( ( d -= 2 ) == 0 ) return CHAIN_SKIPROUTE;
+                               else k.Pull( c, b );
+                           while( d -= 2 ) k.Pull(a,b); /* unstack unused values */ k.Push( c );  NEXT
+                case NPN : k.Pull( c,b,a); a &= 15;
+                           if( b > 127 ) { PUSH( 0xB0 + a ); PUSH( 99 ); PUSH( ( b >> 7 ) & 127 ); }
+                                           PUSH( 0xB0 + a ); PUSH( 98 ); PUSH( b & 127 );
+                                           PUSH( 0xB0 + a ); PUSH(  6 ); PUSH( ( c >> 7 ) & 127 );
+                                           PUSH( 0xB0 + a ); PUSH( 38 ); PUSH( c & 127 );         NEXT
+
+                case NP8 : k.Pull( c,b,a); a &= 15;
+                           if( b > 127 ) { PUSH( 0xB0 + a ); PUSH( 99 ); PUSH( ( b >> 7 ) & 127 ); }
+                                           PUSH( 0xB0 + a ); PUSH( 98 ); PUSH( b & 127 );
+                                           PUSH( 0xB0 + a ); PUSH(  6 ); PUSH( c & 127 );         NEXT
+
+                case RPN : k.Pull( c,b,a); a &= 15;
+                           if( b > 127 ) { PUSH( 0xB0 + a ); PUSH(101 ); PUSH( ( b >> 7 ) & 127 ); }
+                                           PUSH( 0xB0 + a ); PUSH(100 ); PUSH( b & 127 );
+                                           PUSH( 0xB0 + a ); PUSH(  6 ); PUSH( ( c >> 7 ) & 127 );
+                                           PUSH( 0xB0 + a ); PUSH( 38 ); PUSH( c & 127 );         NEXT
+
+                case BNK : k.Pull( b, a ); a &= 15;
+                           if( b > 127 ) { PUSH( 0xB0 + a ); PUSH(  0 ); PUSH( ( b >> 7 ) & 127 ); }
+                                           PUSH( 0xB0 + a ); PUSH( 32 ); PUSH( b & 127 );         NEXT
+                default: 
+                    if( n <= CID && n > CID + 0xFF )return CHAIN_UNKNOWN_OP;
+                    {char id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; short idi = 0;
+                                while( n > CID && n < CUL ) { id[idi++] = (char)(n - CID);
+                                        n = Msg[port][++i]; } k.Push( (byte)ML.Get( id ) ); }     NEXT
+            }
+        }
+        c = 0;
+        if( cst )
+        {
+            if( csb == -1 ) return CHAIN_MISSING_SUB;
+            if( cse == -1 ) return CHAIN_MISSING_SUE;
+            if( csb >= cse ) return CHAIN_SUB_AFTER_SUE;
+        }
+        if( cst == 1 )
+        {
+            for( i = csb ; i < cse ; i++ )
+                c -= Out[i];
+            Out[csu]= (byte)( c & 127 );
+        }
+        if( cst == 2 )
+        {
+            for( i = csb ; i < cse ; i += 4 )
+                c -= Out[i] + ( Out[i+1] << 8 ) + ( Out[i+2] << 16 ) + ( Out[i+3] << 24 );
+            Out[csu++]= (byte)( c );
+            Out[csu++]= (byte)( c >> 8 );
+            Out[csu++]= (byte)( c >> 16 );
+            Out[csu  ]= (byte)( c >> 24 );
+        }
+
+        return 0;
+    }
+};
+//_____________________________________________________________________________
+class Assignment
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    char Name[17];
+    vector<short> Msg;
+    short Value;
+
+    Assignment()                                 { Name[0] = 0; Value = NOP; }
+    Assignment( char* name, vector<short> &msg ) { strncpy( Name, name, 17 ); Msg = msg; Value = NOP; }
+    ~Assignment()                                { }
+    
+    short Compute( MidiM &cur, MidiM &prev ) // 0=ok, else return error code
+    {
+        Stack<long> k;
+        long        a,b,c,d;   // temp
+        short       i = 0;     // next position in Msg
+        bool        s = false; // true when "in sequence"
+        
+        while( i < Msg.size() )
+        {
+            short n = Msg[i];
+            if( ! s  ) // out of sequence, expect a byte value or a custom identifier or SEQ
+            {
+                if( n < 256 ) { Value = n; return 0; } // just copy fixed message byte
+                else if( ! ISCOMMAND( n ) )    return CHAIN_NOT_A_BYTE;        // short values are not allowed outside of sequence
+                else switch( n ) {
+                    case SEQ : s = true;                                                         NEXT
+                    case VMC : Value = cur.Command | ( cur.Channel == NAKN ? 0 : cur.Channel );  return 0;
+                    case VM_ : Value = cur.Command;                                              return 0;
+                    case VC_ : Value = ( cur.Channel == NAKN ? 0 : cur.Channel );                return 0;
+                    case VA_ : Value = cur.ValA;                                                 return 0;
+                    case VN_ : Value = prev.Get14();                                             return 0;
+                    case VB_ : Value = cur.ValB;                                                 return 0;
+                    case VD_ :
+                    case VK_ : Value = cur.Get14();                                              return 0;
+                    default  : char id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; short idi = 0;
+                               while( n > CID && n < CUL ) { id[idi++] = (char)(n - CID);
+                                   n = Msg[i++]; } Value = ML.Get( id );                    return 0;
+                }
+            }
+            else if( ! ISCOMMAND( n ) ) // 14 bit literal inside a sequence, push on stack
+            {
+                k.Push( n ); i++;
+            }
+            else switch( n )
+            {
+                case E7_ : 
+                case E8_ : 
+                case E14 : Value = (short)k.Pull(); return 0;
+                
+                case VMC : k.Push( cur.Command|( cur.Channel == NAKN ? 0 : cur.Channel ) );       NEXT
+                case VM_ : k.Push( cur.Command );                                                 NEXT
+                case VC_ : k.Push( ( cur.Channel == NAKN ? 0 : cur.Channel ) );                   NEXT
+                case VA_ : k.Push( cur.ValA );                                                    NEXT
+                case VB_ : k.Push( cur.ValB );                                                    NEXT
+                case VN_ : k.Push( prev.Get14() );                                                NEXT
+                case VD_ :
+                case VK_ : k.Push( cur.Get14() );                                                 NEXT
+                case ADD : k.Pull( b, a ); k.Push( a + b );                                       NEXT
+                case SUB : k.Pull( b, a ); k.Push( a - b );                                       NEXT
+                case MUL : k.Pull( b, a ); k.Push( a * b );                                       NEXT
+                case DIV : k.Pull( b, a ); k.Push( a / b );                                       NEXT
+                case MOD : k.Pull( b, a ); k.Push( a % b );                                       NEXT
+                case BIT : k.Pull( c,b,a); k.Push( cur.Raw[a] >> b & bitmasking[c] );             NEXT
+                case BOR : k.Pull( b, a ); k.Push( a | b );                                       NEXT
+                case BAN : k.Pull( b, a ); k.Push( a & b );                                       NEXT
+                case BNO : k.Pull(    a ); k.Push( ~a    );                                       NEXT
+                case BSL : k.Pull( b, a ); k.Push( a << b );                                      NEXT
+                case BSR : k.Pull( b, a ); k.Push( a >> b );                                      NEXT
+                case MSB : k.Pull( a ); k.Push( a >> 7 );                                         NEXT
+                case LSB : k.Pull( a ); k.Push( a & 127 );                                        NEXT
+                case MAP : k.Pull( d, a, c, b ); d--;
+                           while( a != b )
+                               if( ( d -= 2 ) == 0 ) { k.Push( NAKN );                            NEXT }
+                               else k.Pull( c, b );
+                           while( d -= 2 ) k.Pull(a,b); /* unstack unused values */ k.Push( c );  NEXT
+                default: 
+                    if( n <= CID && n > CID + 0xFF )return CHAIN_UNKNOWN_OP;
+                    {char id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; short idi = 0;
+                                while( n > CID && n < CUL ) { id[idi++] = (char)(n - CID);
+                                        n = Msg[++i]; } k.Push( (byte)ML.Get( id ) ); }           NEXT
+            }
+        }
+        return CHAIN_SYNTAXE_ERROR;
+    }
+};
+//_____________________________________________________________________________
+class Filter
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    byte  Port; // use constants TO_OUT1...3
+    byte  Type; // use constants NOTE, POLA, ... from midi.h
+    short Channel;
+    short Amin; // may be a 14 bits value for RPN, NRPN identifier
+    short Amax;
+    short Bmin; // may be a 14 bits value for RPN, NRPN value
+    short Bmax;
+    vector<byte> Head;
+    Chain Out;
+    vector<Assignment*> Assigns;
+    
+    Filter() : Port(0), Type(0), Channel(NAKW), Amin(NAKN), Amax(NAKN), Bmin(NAKN), Bmax(NAKN), Head( 1, (short)0xF0 ) { }
+    ~Filter() { }
+    
+    Filter( Filter & f ) 
+    : Port(f.Port),Type(f.Type),Channel(f.Channel),Amin(f.Amin),Amax(f.Amax),Bmin(f.Bmin),Bmax(f.Bmax)
+    {
+        Head = f.Head; Out.Msg[0] = f.Out.Msg[0]; Out.Msg[1] = f.Out.Msg[1]; Out.Msg[2] = f.Out.Msg[2]; Assigns = f.Assigns;
+   }
+   
+    Filter( byte p, byte t, short c, short ai, short ax, short bi, short bx, vector<byte> &head, vector<short> &o1, vector<short> &o2, vector<short> &o3, vector<Assignment*> &assigns )
+    : Port(p), Type(t), Channel(c), Amin(ai), Amax(ax), Bmin(bi), Bmax(bx)
+    {
+        Head = head; Out.Msg[0] = o1; Out.Msg[1] = o2; Out.Msg[2] = o3; Assigns = assigns;
+   }
+};
+
+//_____________________________________________________________________________
+class FilterList
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    vector<Filter*> List;
+    
+    void Add( byte inport, byte message, short channels, short mina, short maxa, short minb, short maxb, vector<byte> &head, vector<short> &sequence1, vector<short> &sequence2, vector<short> &sequence3, vector<Assignment*> &assigns )
+    {
+        List.push_back( new Filter( inport, message, channels, mina, maxa, minb, maxb, head, sequence1, sequence2, sequence3, assigns ) );
+        HasBank |= message == BANK;
+        HasData |= ( message >= DATA ) && ( message <= NRPN );
+        HasSysx |= message == SYSX;
+    }
+    Filter* operator[] ( short index )
+    {
+        return List[index];
+    }
+    void Route( byte from, MidiM &cur, MidiM &prev )
+    {
+        for( short i = 0 ; i < List.size() ; i++ )
+        {
+            Filter* f = List[i];
+            if( f->Port != from ) continue;
+
+            if( HasSysx  &&  ( f->Type == SYSX )  &&  ( cur.Type == SYSX ) )
+            {
+                bool ok =  f->Head.size() > 0;
+                if( ok )
+                    if( f->Head[0] != RAW )
+                        for( int j = 0 ; j < f->Head.size() ; j++ )
+                            if( j == cur.Raw.size() || f->Head[j] != cur.Raw[j] ) 
+                                ok=false;
+                if( ok )
+                {
+                    for( int assign = 0 ; assign < f->Assigns.size() ; assign++ )
+                        if( f->Assigns[assign]->Compute( cur, prev ) == 0 )
+                            ML.Add( f->Assigns[assign]->Name, f->Assigns[assign]->Value );
+
+                    for( int port = 0 ; port < 3 ; port++ )
+                        if( f->Out.Compute( port, cur, prev ) == 0 )
+                        {
+                            led[3] = 1;
+                            for( short j = 0 ; j < f->Out.Out.size() ; j++ )
+                                SL[port].putc( f->Out.Out[j] );
+                            led[3] = 0;
+                       }
+                    f->Out.Done();
+                   return;
+                }
+            }
+            else if( HasData &&  ( f->Type == DATA || f->Type == INCR || f->Type == DECR ) &&  ( cur.Type == f->Type )  &&  ( prev.Type == NRPN || prev.Type == RPN_ ) )
+            {
+                short number = prev.Get14(), data = cur.Get14(); 
+                if( f->Channel == NAKW || ( f->Channel & ( 1 << cur.Channel ) & ( 1 << prev.Channel ) ) )
+                    if( f->Amin==NAKW || ( f->Amax==NAKW && number==f->Amin ) || ( f->Amax!=NAKW && number>=f->Amin && number<=f->Amax ) )
+                        if( f->Bmin==NAKW || ( f->Bmax==NAKW && data==f->Bmin ) || ( f->Bmax!=NAKW && data>=f->Bmin && data<=f->Bmax ) )
+                        {
+                            for( int assign = 0 ; assign < f->Assigns.size() ; assign++ )
+                                if( f->Assigns[assign]->Compute( cur, prev ) == 0 )
+                                    ML.Add( f->Assigns[assign]->Name, f->Assigns[assign]->Value );
+                            for( int port = 0 ; port < 3 ; port++ )
+                                if( f->Out.Compute( port, cur, prev ) == 0 )
+                                {
+                                    for( short j = 0 ; j < f->Out.Out.size() ; j++ ) // check for unrountable message
+                                    {
+                                        short n = f->Out.Out[j];
+                                        if( f->Out.Out[j] == NAKN ) return;
+                                    }
+                                    led[3] = 1;
+                                    for( short j = 0 ; j < f->Out.Out.size() ; j++ )
+                                        SL[port].putc( f->Out.Out[j] );
+                                    led[3] = 0;
+                                }
+                            f->Out.Done();
+                            return;
+                        }
+            }
+            else if( f->Type == cur.Type )
+                if( ( f->Channel == NAKW ) || ( f->Channel & ( 1 << cur.Channel ) ) )
+                    if( cur.ValCount()==0 || f->Amin==NAKN || ( f->Amax==NAKN && cur.ValA==f->Amin ) || ( f->Amax!=NAKN && cur.ValA>=f->Amin && cur.ValA<=f->Amax ) )
+                        if( cur.ValCount()==1 || f->Bmin==NAKN || ( f->Bmax==NAKN && cur.ValB==f->Bmin ) || ( f->Bmax!=NAKN && cur.ValB>=f->Bmin && cur.ValB<=f->Bmax ) )
+                        {
+                            for( int assign = 0 ; assign < f->Assigns.size() ; assign++ )
+                                if( f->Assigns[assign]->Compute( cur, prev ) == 0 )
+                                    ML.Add( f->Assigns[assign]->Name, f->Assigns[assign]->Value );
+
+                            for( int port = 0 ; port < 3 ; port++ )
+                                if( f->Out.Compute( port, cur, prev ) == 0 )
+                                {
+                                    for( short j = 0 ; j < f->Out.Out.size() ; j++ ) // check for unrountable message
+                                        if( f->Out.Out[j] == NAKN ) return;
+                                    led[3] = 1;
+                                    for( short j = 0 ; j < f->Out.Out.size() ; j++ )
+                                        SL[port].putc( f->Out.Out[j] );
+                                    led[3] = 0;
+                                }
+                            f->Out.Done();
+                            return;
+                        }
+    
+        }
+    }
+};
+
+#undef NEXT
+#undef PUSH
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/filter_debug.h	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,66 @@
+#ifndef FILTER_DEBUG_H
+#define FILTER_DEBUG_H
+
+int PrintFilterSymbol( short* p )
+{
+    int shift = 0;
+
+    if( *p > 0 && *p < 128 )
+    {
+        printf( "%d ", *p ); return 0;
+    }
+    if( *p > 0 && *p < 256 )
+    {
+        printf( "0x%02.2X ", *p ); return 0;
+    }
+    if( *p < SEQ || *p > NAKW )
+    {
+        printf( "0x%04.4X ", *p ); return 0;
+    }
+    switch( *p )
+    {
+        case SEQ: printf( "SEQ " ); return 0;
+        case E7_: printf( "E7_ " ); return 0;
+        case E8_: printf( "E8_ " ); return 0;
+        case E14: printf( "E14 " ); return 0;
+        case NOP: printf( "NOP " ); return 0;
+        case VMC: printf( "VMC " ); return 0;
+        case VM_: printf( "VM_ " ); return 0;
+        case VC_: printf( "VC_ " ); return 0;
+        case VA_: printf( "VA_ " ); return 0;
+        case VB_: printf( "VB_ " ); return 0;
+        case VD_: printf( "VD_ " ); return 0;
+        case VN_: printf( "VN_ " ); return 0;
+        case ADD: printf( "ADD " ); return 0;
+        case SUB: printf( "SUB " ); return 0;
+        case MUL: printf( "MUL " ); return 0;
+        case DIV: printf( "DIV " ); return 0;
+        case MOD: printf( "MOD " ); return 0;
+        case BIT: printf( "BIT " ); return 0;
+        case BOR: printf( "BOR " ); return 0;
+        case BAN: printf( "BAN " ); return 0; 
+        case BNO: printf( "BNO " ); return 0;
+        case BSL: printf( "BSL " ); return 0;
+        case BSR: printf( "BSR " ); return 0;
+        case MAP: printf( "MAP " ); return 0;
+        case RPN: printf( "RPN " ); return 0;
+        case NPN: printf( "NPN " ); return 0;
+        case CSB: printf( "CSB " ); return 0; 
+        case CSE: printf( "CSE " ); return 0;
+        case CS1: printf( "CS1 " ); return 0;
+        case CS2: printf( "CS2 " ); return 0;
+        case NAKW:printf( "NAKW "); return 0;
+        case RAW: printf( "* "   ); return 0;
+    }
+    if( *p > CID && *p < CUL )
+    {
+        char buffer[17];
+        while( *p != CID ) buffer[shift++]= (char)( *p++ - CID );
+        buffer[shift] = 0;
+        printf( "%s ", buffer );
+        return shift;
+    }
+    return 0;
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,162 @@
+#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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/memory.h	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,78 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+//_____________________________________________________________________________
+class Memory
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+private:
+public:
+    char    Name[16];
+    short   Value;
+    Memory() { Name[0] = 0; Value = 0; }
+    Memory( char* n, short v ) { strncpy( Name, n, 16 ); Value = v; }
+    ~Memory() {}
+};
+//_____________________________________________________________________________
+class MemList
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+private:
+    short   allocated_; // size of allocated list
+public:
+    short   Count;     // size of initialized list
+    Memory* List;      // list of names
+
+    MemList() : Count(0), List(NULL) {}
+    
+    ~MemList()
+    {
+        if( List != NULL ) free( List );
+        Count = allocated_ = 0;
+    }
+    void Add( Memory &m )
+    {
+        int n = Find( m.Name );
+        if( n == -1 )
+        {
+            if( Count == allocated_ ) List = (Memory*)realloc( List, ( allocated_ += 5 ) * sizeof( Memory ) );
+            List[ Count++ ] = m;
+        }
+        else
+            List[n].Value = m.Value;
+    }
+    void Add( char* name, short value )
+    {
+        int n = Find( name );
+        if( n == -1 )
+        {
+            if( Count == allocated_ ) List = (Memory*)realloc( List, ( allocated_ += 5 ) * sizeof( Memory ) );
+            List[ Count++ ] = Memory( name, value );
+        }
+        else
+            List[n].Value = value;
+    }
+    short Find( char* name )
+    {
+        for( short i = 0 ; i < Count ; i++ )
+            if( strcmp( List[i].Name, name ) == 0 )
+                return i;
+        return -1;
+    }
+    short Get( char* name )
+    {
+        for( short i = 0 ; i < Count ; i++ )
+            if( strcmp( List[i].Name, name ) == 0 )
+                return List[i].Value;
+        return 0;
+    }
+    void Set( char* name, short value )
+    {
+        for( short i = 0 ; i < Count ; i++ )
+            if( strcmp( List[i].Name, name ) == 0 )
+            {
+                List[i].Value = value;
+                break;
+            }
+    }
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/midi.h	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,435 @@
+#ifndef MIDI_H
+#define MIDI_H
+
+#include <vector>
+
+#ifndef BYTE
+    #define BYTE
+    typedef unsigned char byte;
+#endif
+
+#ifndef WORD
+    #define WORD
+    typedef unsigned short word;
+#endif
+
+ // unused midi code serves as defining 'Not A Known Value':
+#define NAKN  253
+
+// out of 14bit range value serves as defining 'Not A Known Word':
+#define NAKW  0x5000
+
+// generic:
+#define NONE    0
+
+// values for member 'next':
+#define VALA    1
+#define VALB    2
+#define MSB     3
+#define LSB     4
+#define PAIR    5
+#define ITEM    6
+#define MSB2    7
+#define LSB2    8
+
+// values for member 'type':
+// channel message:
+#define NOTE    1
+#define POLA    2
+#define CTRL    3
+#define PROG    4
+#define BANK    5
+#define DATA    6
+#define INCR    7
+#define DECR    8
+#define RPN_    9
+#define NRPN   10
+#define MONA   11
+#define BEND   12
+// no channel message:
+#define SYSX   13
+#define TCOD   14
+#define SPOS   15
+#define SSEL   16
+#define TUNE   17
+#define CLOK   18
+#define STAR   19
+#define CONT   20
+#define STOP   21
+#define SENS   22
+#define RSET   23
+
+///////////////////////////////////////////////////////////////////////////////
+ // base class for all Messages
+//_____________________________________________________________________________
+class MidiM
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    byte Command;
+    byte Type;
+    byte Channel;
+    byte Next; // expected type of next inconming byte
+    byte ValA; // data
+    byte ValB; // data
+    vector<byte> Raw;
+
+    MidiM( byte type )                  : Command(0), Type( type ), Channel( NAKN ), Next(NONE), ValA(NAKN), ValB(NAKN) {}
+    MidiM( byte type, byte ch )         : Command(0), Type( type ), Channel( ch ), Next(NONE), ValA(NAKN), ValB(NAKN) {}
+    virtual ~MidiM(){}
+
+    virtual bool Append( byte b) { Raw.push_back(b); return true; }
+
+    virtual byte ValCount() { return 0; }
+
+    short  Get14()
+    { 
+        return ( ValA == NAKN ? 0 : ValA << 7 ) + ( ValB == NAKN ? 0 : ValB ); 
+    }
+    void Set14( short v )
+    { 
+        ValA = ( v >> 7 ) & 127; 
+        ValB = v & 127; 
+        Next = NONE;
+    }
+};
+//_____________________________________________________________________________
+class MidiTune     : public MidiM 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiTune()     : MidiM( TUNE )      { Raw.push_back( Command = 0xF6 ); } 
+    virtual ~MidiTune(){}
+//    virtual void Send( Serial &s )      { s.putc( 0xF6 ); } 
+};
+//_____________________________________________________________________________
+class MidiClock    : public MidiM 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiClock()    : MidiM( CLOK )      { Raw.push_back( Command = 0xF8 ); } 
+    virtual ~MidiClock(){}
+//   virtual void Send( Serial &s )      { s.putc( 0xF8 ); } 
+};
+//_____________________________________________________________________________
+class MidiStart    : public MidiM 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiStart()    : MidiM( STAR )      { Raw.push_back( Command = 0xFA ); }
+    virtual ~MidiStart(){}
+//    virtual void Send( Serial &s )      { s.putc( 0xFA ); }
+};
+//_____________________________________________________________________________
+class MidiContinue : public MidiM
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiContinue() : MidiM( CONT )      { Raw.push_back( Command = 0xFB ); }
+    virtual ~MidiContinue(){}
+//    virtual void Send( Serial &s )      { s.putc( 0xFB ); }
+};
+//_____________________________________________________________________________
+class MidiStop     : public MidiM
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiStop()     : MidiM( STOP )      { Raw.push_back( Command = 0xFC ); }
+    virtual ~MidiStop(){}
+//    virtual void Send( Serial &s )      { s.putc( 0xFC ); }
+};
+//_____________________________________________________________________________
+class MidiSensing  : public MidiM
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiSensing()  : MidiM( SENS )      { Raw.push_back( Command = 0xFE ); }
+    virtual ~MidiSensing(){}
+//    virtual void Send( Serial &s )      { s.putc( 0xFE ); }
+};
+//_____________________________________________________________________________
+class MidiReset    : public MidiM
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiReset()    : MidiM( RSET )      { Raw.push_back( Command = 0xFF ); }
+    virtual ~MidiReset(){}
+//    virtual void Send( Serial &s )      { s.putc( 0xFF ); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// base class & derived classes for all Messages having 1 byte of data
+//_____________________________________________________________________________
+class MidiM1 : public MidiM 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiM1( byte type, byte ch )         : MidiM( type, ch ) { Next = VALA; }
+    MidiM1( byte type, byte ch, byte v ) : MidiM( type, ch ) { Next = NONE; ValA = v; }
+    virtual ~MidiM1(){}
+    virtual bool Append( byte b )
+    { 
+        Raw.push_back(b);
+        if( b > 127 || Next == NONE  ) return false; 
+        Next = NONE; ValA = b; return true; 
+     }
+    virtual byte ValCount() { return 1; }
+};
+//_____________________________________________________________________________
+class MidiSelect   : public MidiM1
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public: 
+    MidiSelect()                : MidiM1( SSEL, NAKN )      { Raw.push_back( Command = 0xF3 ); } 
+    MidiSelect( byte v )        : MidiM1( SSEL, NAKN, v )   { Raw.push_back( Command = 0xF3 ); } 
+    virtual ~MidiSelect(){}
+//    virtual void Send( Serial &s )          { s.putc( 0xF3 ); s.putc( ValA ); } 
+};
+//_____________________________________________________________________________
+class MidiTimeCode : public MidiM1 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiTimeCode()              : MidiM1( TCOD, NAKN )      { Raw.push_back( Command = 0xF1 ); }
+    MidiTimeCode( byte v )      : MidiM1( TCOD, NAKN, v )   { Raw.push_back( Command = 0xF1 ); }
+    virtual ~MidiTimeCode(){}
+//    virtual void Send( Serial &s )          { s.putc( 0xF1 ); s.putc( ValA ); } 
+};
+//_____________________________________________________________________________
+class MidiProgram  : public MidiM1 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiProgram( byte ch )           : MidiM1( PROG, ch )   { Raw.push_back( ( Command = 0xC0 ) + ch ); }
+    MidiProgram( byte ch, byte v )   : MidiM1( PROG, ch, v ){ Raw.push_back( ( Command = 0xC0 ) + ch ); }
+    virtual ~MidiProgram(){}
+//    virtual void Send( Serial &s ){ s.putc( 0xC0 + Channel ); s.putc( ValA ); }
+};
+//_____________________________________________________________________________                            
+class MidiMonoAft  : public MidiM1 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiMonoAft( byte ch )           : MidiM1( MONA, ch )   { Raw.push_back( ( Command = 0xD0 ) + ch ); }
+    MidiMonoAft( byte ch, byte v )   : MidiM1( MONA, ch, v ){ Raw.push_back( ( Command = 0xD0 ) + ch ); }
+    virtual ~MidiMonoAft(){}
+//    virtual void Send( Serial &s ){ s.putc( 0xD0 + Channel ); s.putc( ValA ); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// base class & derived classes for all Messages having 2 byte of data
+//_____________________________________________________________________________                            
+class MidiM2 : public MidiM 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiM2(byte type,byte ch)              : MidiM(type,ch){ Next = VALA; }
+    MidiM2(byte type,byte ch,byte v)       : MidiM(type,ch){Next=VALB;ValA=v;}
+    MidiM2(byte type,byte ch,byte v,byte w): MidiM(type,ch){Next=NONE;ValA=v;ValB=w;}
+    virtual ~MidiM2(){}
+    virtual byte ValCount() { return 2; }
+
+    virtual bool Append( byte b )
+    {
+        Raw.push_back(b);
+        if( b > 127 || Next == NONE ) return false;
+        if( Next == VALA ) { ValA = b; Next = VALB; }
+        else               { ValB = b; Next = NONE; }
+        return true;
+    }
+};
+//_____________________________________________________________________________                            
+class MidiPosition : public MidiM2 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiPosition()             : MidiM2( SPOS, NAKN )       { Raw.push_back( Command = 0xF3 ); } 
+    MidiPosition( byte v )     : MidiM2( SPOS, NAKN, v )    { Raw.push_back( Command = 0xF3 ); } 
+    MidiPosition( byte v, byte w ) : MidiM2( SPOS, NAKN, v, w ) { Command = 0xF3; } 
+    virtual ~MidiPosition(){}
+//    virtual void Send( Serial &s ){ s.putc(0xF3); s.putc(ValA); s.putc(ValB); }
+};
+//_____________________________________________________________________________                            
+class MidiNoteOn   : public MidiM2 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiNoteOn( byte ch )        : MidiM2( NOTE, ch )       { Raw.push_back( ( Command = 0x90 ) + ch ); }
+    MidiNoteOn( byte ch, byte v ): MidiM2( NOTE, ch, v )    { Raw.push_back( ( Command = 0x90 ) + ch ); }
+    MidiNoteOn( byte ch, byte v, byte w ) : MidiM2( NOTE, ch, v, w ) { Command = 0x90; }
+    virtual ~MidiNoteOn(){}
+/*    virtual void Send( Serial &s )
+    {
+        s.putc( 0x90 + Channel ); s.putc( ValA ); s.putc( ValB );
+    }*/
+};
+//_____________________________________________________________________________                            
+class MidiNoteOff  : public MidiM2 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiNoteOff( byte ch )       : MidiM2( NOTE, ch )       { Raw.push_back( ( Command = 0x80 ) + ch ); }
+    MidiNoteOff( byte ch, byte v ): MidiM2( NOTE, ch, v )    { Raw.push_back( ( Command = 0x80 ) + ch ); }
+    MidiNoteOff( byte ch, byte v, byte w ): MidiM2( NOTE, ch, v, w ) { Command = 0x80; }
+    virtual ~MidiNoteOff(){}
+/*    virtual void Send( Serial &s )
+    {
+        s.putc( 0x80 + Channel ); s.putc( ValA ); s.putc( ValB );
+    }*/
+};
+//_____________________________________________________________________________                            
+class MidiPolyAft  : public MidiM2 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiPolyAft( byte ch )       : MidiM2( POLA, ch )       { Raw.push_back( ( Command = 0xA0 ) + ch ); }
+    MidiPolyAft( byte ch, byte v ): MidiM2( POLA, ch, v )    { Raw.push_back( ( Command = 0xA0 ) + ch ); }
+    MidiPolyAft( byte ch, byte v, byte w ): MidiM2( POLA, ch, v, w ) { Command = 0xA0; }
+    virtual ~MidiPolyAft(){}
+/*    virtual void Send( Serial &s )
+    {
+        s.putc( 0xA0 + Channel ); s.putc( ValA ); s.putc( ValB );
+    }*/
+};
+//_____________________________________________________________________________                            
+class MidiBend     : public MidiM2 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiBend( byte ch )          : MidiM2( BEND, ch )       { Raw.push_back( ( Command = 0xE0 ) + ch ); }
+    MidiBend( byte ch, byte v )  : MidiM2( BEND, ch, v )    { Raw.push_back( ( Command = 0xE0 ) + ch ); }
+    MidiBend( byte ch, byte v, byte w ): MidiM2( BEND, ch, v, w ) { Command = 0xE0; }
+    virtual ~MidiBend(){}
+/*    virtual void Send( Serial &s )
+    {
+        s.putc( 0xE0 + Channel ); s.putc( ValA ); s.putc( ValB );
+    }*/
+};
+//_____________________________________________________________________________                            
+class MidiControl  : public MidiM2 
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiControl( byte ch )       : MidiM2( CTRL, ch )       { Raw.push_back( ( Command = 0xB0 ) + ch ); }
+    MidiControl( byte ch, byte v ): MidiM2( CTRL, ch, v )   { Raw.push_back( ( Command = 0xB0 ) + ch ); }
+    MidiControl( byte ch, byte v, byte w ): MidiM2( CTRL, ch, v, w ) { Command = 0xB0; }
+    virtual ~MidiControl(){}
+/*    virtual void Send( Serial &s )           
+    {
+        byte c = 0xB0 + Channel;
+        switch( Type ) {
+            case CTRL :                    s.putc( c ); s.putc(ValA ); s.putc( ValB ); break;
+            case BANK : if( ValA != NAKN ) s.putc( c ); s.putc(   0 ); s.putc( ValA );
+                        if( ValB != NAKN ) s.putc( c ); s.putc(  32 ); s.putc( ValB ); break;
+            case DATA : if( ValA != NAKN ) s.putc( c ); s.putc(   6 ); s.putc( ValA );
+                        if( ValB != NAKN ) s.putc( c ); s.putc(  38 ); s.putc( ValB ); break;
+            case INCR :                    s.putc( c ); s.putc(  96 );                 break;
+            case DECR :                    s.putc( c ); s.putc(  97 );                 break;
+            case NRPN : if( ValA != NAKN ) s.putc( c ); s.putc(  99 ); s.putc( ValA );
+                        if( ValB != NAKN ) s.putc( c ); s.putc(  98 ); s.putc( ValB ); break;
+            case RPN_ : if( ValA != NAKN ) s.putc( c ); s.putc( 101 ); s.putc( ValA );
+                        if( ValB != NAKN ) s.putc( c ); s.putc( 100 ); s.putc( ValB ); break;
+        }        
+    }*/
+    virtual bool Append( byte b )
+    {
+        Raw.push_back(b);
+        switch( Next ) {
+            case VALA: 
+                if( HasBank || HasData )
+                        switch( b ) {
+                        case   0:   if( HasBank ) { Next=MSB;  Type=BANK; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+
+                        case  32:   if( HasBank ) { Next=LSB;  Type=BANK; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+
+                        case   6:   if( HasData ) { Next=MSB;  Type=DATA; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+                       
+                        case  38:   if( HasData ) { Next=LSB;  Type=DATA; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+                       
+                        case  96:   if( HasData ) { Next=NONE;  Type=INCR; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+
+                        case  97:   if( HasData ) { Next=NONE;  Type=DECR; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+                       
+                        case  98:   if( HasData ) { Next=LSB;  Type=NRPN; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+                       
+                        case  99:   if( HasData ) { Next=MSB;  Type=NRPN; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+
+                        case 100:   if( HasData ) { Next=LSB;  Type=NRPN; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+                       
+                        case 101:   if( HasData ) { Next=MSB;  Type=NRPN; }
+                                    else          { Next=VALB; ValA=b;    } return true;
+
+                        default:    Next = VALB;    ValA = b;               return true;
+                       }
+                else{
+                                    Next = VALB;
+                                    ValA = b;
+                                    return true;
+                }                                    
+            case VALB:              Next = NONE;    ValB = b;       return true;
+            case MSB:               Next = PAIR;    ValA = b;       return true; // wait for 0xB*
+            case LSB:               Next = PAIR;    ValB = b;       return true; // wait for 0xB*
+            case MSB2:              Next = NONE;    ValA = b;       return true;
+            case LSB2:              Next = NONE;    ValB = b;       return true;
+            case PAIR:              Next = ITEM;                    return true; // 0xB*
+            case ITEM: 
+                switch( Type ) {
+                    case BANK: if( b!=  0 && b!= 32 ){ Next = NONE; return false; }
+                                    Next = b ==  0 ? MSB2 : LSB2;   return true;
+                    case DATA: if( b!=  6 && b!= 38 ){ Next = NONE; return false; }
+                                    Next = b ==  6  ? MSB2 : LSB2;   return true;
+                    case NRPN: if( b!= 98 && b!= 99 ){ Next = NONE; return false; }
+                                    Next = b == 99 ? MSB2 : LSB2;   return true;
+                    case RPN_: if( b!=100 && b!=101 ){ Next = NONE; return false; }
+                                    Next = b ==101 ? MSB2 : LSB2;   return true;
+                }    
+        }
+        return false;
+    }
+
+};
+
+//_____________________________________________________________________________                            
+class MidiX : public MidiM2 // class for SysEx message
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+public:
+    MidiX() : MidiM2( SYSX, NAKN ){ Raw.push_back( Command = 0xF0 ); }
+    virtual ~MidiX(){}
+    virtual bool Append( byte b )
+    {
+        Raw.push_back(b);
+        if( b==0xF7 ) 
+            Next = NONE; 
+        return true;
+    }
+};
+
+//_____________________________________________________________________________                            
+MidiM* MidiCreateMessage( byte command )
+{//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+    if( command >= 0xF0 )
+        switch( command ) {
+            case 0xF0: return new MidiX();
+            case 0xF1: return new MidiTimeCode();
+            case 0xF2: return new MidiPosition();
+            case 0xF3: return new MidiSelect();
+            case 0xF6: return new MidiTune();
+            case 0xF8: return new MidiClock();
+            case 0xFA: return new MidiStart();
+            case 0xFB: return new MidiContinue();
+            case 0xFC: return new MidiStop();
+            case 0xFE: return new MidiSensing();
+            case 0xFF: return new MidiReset();
+        }
+    else switch( command >> 4 ) {
+            case 0x8: return new MidiNoteOff( command & 15 );
+            case 0x9: return new MidiNoteOn ( command & 15 );
+            case 0xA: return new MidiPolyAft( command & 15 );
+            case 0xB: return new MidiControl( command & 15 );
+            case 0xC: return new MidiProgram( command & 15 );
+            case 0xD: return new MidiMonoAft( command & 15 );
+            case 0xE: return new MidiBend   ( command & 15 );
+    
+        }
+    return new MidiM( NONE );
+}
+
+#undef VALA
+#undef VALB
+#undef MSB
+#undef LSB
+#undef PAIR
+#undef ITEM
+#undef MSB2
+#undef LSB2
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parse.h	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,448 @@
+#ifndef PARSE_H
+#define PARSE_H
+
+#include <string.h>
+#include <vector>
+
+void ParseCleanUp( char* s1, char* s2 )
+{
+    // copy all non blank till ; or 0
+    for( int i = 0, j = 0 ; i < 256 ; i++ )
+        if( s1[i] != 32 && s1[i] != 13 && s1[i] != 10 && s1[i] != 9 )
+            switch( s2[j++] = s1[i] ) {
+            case ';': s2[j-1] = 0; return;
+            case 0: return;
+        }
+}
+int GetOPIDfromFunction( char * f )
+{
+    if( strcmp( f, "add" ) == 0 ) return ADD;
+    if( strcmp( f, "mul" ) == 0 ) return MUL;
+    if( strcmp( f, "sub" ) == 0 ) return SUB;
+    if( strcmp( f, "div" ) == 0 ) return DIV;
+    if( strcmp( f, "i8"  ) == 0 ) return E8_;
+    if( strcmp( f, "i14" ) == 0 ) return E14;
+    if( strcmp( f, "mod" ) == 0 ) return MOD;
+    if( strcmp( f, "bit" ) == 0 ) return BIT;
+    if( strcmp( f, "bor" ) == 0 ) return BOR;
+    if( strcmp( f, "ban" ) == 0 ) return BAN;
+    if( strcmp( f, "bno" ) == 0 ) return BNO;
+    if( strcmp( f, "bsl" ) == 0 ) return BSL;
+    if( strcmp( f, "bsr" ) == 0 ) return BSR;
+    if( strcmp( f, "msb" ) == 0 ) return MSB;
+    if( strcmp( f, "lsb" ) == 0 ) return LSB;
+    if( strcmp( f, "map" ) == 0 ) return MAP;
+    if( strcmp( f, "nrpn") == 0 ) return NPN;
+    if( strcmp( f, "rpn" ) == 0 ) return RPN;
+    if( strcmp( f, "bank") == 0 ) return BNK;
+    if( strcmp( f, "nrp8") == 0 ) return NP8;
+    return 0;
+}
+
+int ParseError = 0;
+int ParseLine  = 0;
+#define abort(x) { ParseError = x; return false; }
+
+#define PARSE_NOERROR                0
+#define PARSE_NO_FILE                1
+#define PARSE_BAD_NUMBER_DEFINITION  2
+#define PARSE_BAD_MESSAGE_DEFINITION 3
+#define PARSE_BAD_SEQ_SYNTAXE        4
+#define PARSE_BAD_SEQ_HEXA_SIGN      5
+#define PARSE_BAD_SEQ_NUMBER         6
+#define PARSE_BAD_SEQ_IDENTIFIER     7
+#define PARSE_BAD_SEQ_BYTE           8
+#define PARSE_BAD_SEQ_FUNCTION       9
+#define PARSE_BAD_SEQ_TOOLONG       10
+#define PARSE_UNKNWON_ENTRY         11
+#define PARSE_MIN_GREATER_THAN_MAX  12
+
+#define TOKEN_END  *p == 0 || *p == ',' || *p == ')'
+#define TOKEN_NUM  *p >= '0' && *p <= '9'
+#define TOKEN_LOW  *p >= 'a' && *p <= 'z'
+#define TOKEN_UPP  *p >= 'A' && *p <= 'Z'
+#define TOKEN_LOX  *p >= 'a' && *p <= 'f'
+#define TOKEN_UPX  *p >= 'A' && *p <= 'F'
+
+class ParseEntry   
+{
+public:
+    char Name[17];
+    ParseEntry( char* name ) 
+    {
+        short i = 0;
+        for( i = 0 ; i < 16 && name[i] ; i++ )
+        {
+            if( name[i] >= 'A' && name[i]<='Z' ) Name[i] = name[i] + 32; else Name[i] = name[i];
+        }
+        Name[i] = 0;
+    }
+    virtual ~ParseEntry() {}
+    
+    virtual bool Parse( char* data ){ return true; }
+};
+class ParseFlag     : public ParseEntry
+{
+public:
+    int Flag;
+    ParseFlag( char* name ) : ParseEntry( name ), Flag(0) {}
+    virtual ~ParseFlag(){}
+    virtual bool Parse( char* data )
+    {
+        if( *data == '*' )
+        {
+            Flag = NAKW;
+            return true;
+        }
+        Flag = 0;
+        for( int i = 0 ; i < 16 ; i++ )
+            if( data[i] == 0 ) break;
+            else if( data[i] != '-' ) Flag |= 1 << i;
+        return true;
+    }
+};
+class ParseByte : public ParseEntry
+{
+public:
+    byte Mini;
+    byte Maxi;
+    ParseByte( char* name ) : ParseEntry( name ),Mini(NAKN), Maxi(NAKN) {}
+    virtual ~ParseByte(){}
+    virtual bool Parse( char* data )
+    {
+        if( *data == '*' )
+        {
+            Mini = NAKN;
+            Maxi = NAKN;
+            return true;
+        }
+
+        int   base  = 10;
+        bool  start = true;
+        int   dot   = 0;
+        char  set[] = "0123456789ABCDEF$.";
+        char* p;
+        bool  ok    = false;
+        
+        Mini = 0;
+        
+        while( *data )
+        {
+            ok = false;
+            p = strchr( set, *data++ );
+            if( p )
+            {
+                int index = p - set;
+
+                if( index==16 && start==true )                          { start=false; base=16,                    ok=true; }
+                else if( index == 17 && dot < 3 ) { dot++; if( dot==3)  { start=true;  base=10; Maxi = 0;          ok=true; } }
+                else if( index < base )                  { if( dot==3 ) { start=false; Maxi = Maxi * base + index; ok=true; }
+                                                           else         { start=false; Mini = Mini * base + index; ok=true; } }
+                else break;
+            }
+            else break;
+        }
+        if( ! ok ) abort( PARSE_BAD_NUMBER_DEFINITION )
+        if( Maxi != NAKN && Mini > Maxi ) abort( PARSE_MIN_GREATER_THAN_MAX )
+        return true;
+    }
+};
+class ParseShort : public ParseEntry
+{
+public:
+    short Mini;
+    short Maxi;
+    ParseShort( char* name ) : ParseEntry( name ),Mini(NAKW), Maxi(NAKW) {}
+    virtual ~ParseShort(){}
+    virtual bool Parse( char* data )
+    {
+        if( *data == '*' )
+        {
+            Mini = NAKW;
+            Maxi = NAKW;
+            return true;
+        }
+        int   base  = 10;
+        bool  start = true;
+        int   dot   = 0;
+        char  set[] = "0123456789ABCDEF$.";
+        char* p;
+        bool  ok    = false;
+        
+        Mini = 0;
+        
+        while( *data )
+        {
+            ok = false;
+            p = strchr( set, *data++ );
+            if( p )
+            {
+                int index = p - set;
+
+                if( index==16 && start==true )                          { start=false; base=16,                    ok=true; }
+                else if( index == 17 && dot < 3 ) { dot++; if( dot==3)  { start=true;  base=10; Maxi = 0;          ok=true; } }
+                else if( index < base )                  { if( dot==3 ) { start=false; Maxi = Maxi * base + index; ok=true; }
+                                                           else         { start=false; Mini = Mini * base + index; ok=true; } }
+                else break;
+            }
+            else break;
+        }
+        if( ! ok ) abort( PARSE_BAD_NUMBER_DEFINITION )
+        if( Maxi != NAKW && Mini>Maxi ) abort( PARSE_MIN_GREATER_THAN_MAX )
+        return true;
+    }
+};
+class ParseMessage  : public ParseEntry
+{
+public:
+    byte Code;
+    ParseMessage( char* name ) : ParseEntry( name ),Code(NAKN) {}
+    virtual ~ParseMessage(){}
+    virtual bool Parse( char* data )
+    {
+        static char keywords[] = "NOTE;POLA;CTRL;PROG;BANK;DATA;INCR;DECR;RPN_;NRPN;MONA;BEND;SYSX;TCOD;SPOS;SSEL;TUNE;CLOK;STAR;CONT;STOP;SENS;RSET";
+
+        char* p = strstr( keywords, data );
+         if( p == NULL ) abort( PARSE_BAD_MESSAGE_DEFINITION )
+
+        Code = ( p - keywords ) / 5 + 1;
+        return true;
+    }
+};
+
+#define PUSH(x) Sequence.push_back(x)
+
+class ParseSequence : public ParseEntry
+{
+public:
+    vector<short> Sequence;
+    ParseSequence( char* name ) : ParseEntry(name) {}
+    virtual ~ParseSequence() { }
+    
+    virtual bool Parse( char* data )
+    {
+        if( *data == '*' )
+        {
+            Sequence = vector<short>( 1, RAW );
+            return true;
+        }
+        char* p = data;
+        if( SubParse( p ) )
+        {
+            Sequence.push_back(NOP);
+            return true;
+        }
+        return false;
+    }
+    short SubParse( char* &p ) // returns the number of arguments in the sub-sequence
+    {
+        static int level = 0;
+        level++;
+
+        int args = 0;
+
+        while( *p )
+        {
+            int num = 0;
+
+            switch( *p ) 
+            {
+            case '=':
+            case ',':    p++; break;
+            case ')':    p++; level--; return args;
+
+                case '$':    while( 1 ) {
+                                p++; if( TOKEN_END ) { PUSH( num ); break; }
+                                else if( TOKEN_NUM )   num = num * 16 + (*p - 48 );
+                                else if( TOKEN_UPX )   num = num * 16 + (*p - 55 );
+                                else if( TOKEN_LOX )   num = num * 16 + (*p - 87 );
+                                else abort( PARSE_BAD_SEQ_HEXA_SIGN )
+                            } args++; break;
+
+                case '%':    { char fn[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int i = 0;
+                                while( 1 ) {
+                                    p++; if( TOKEN_END ) break;
+                                    else if( TOKEN_NUM ) fn[i++] = *p;
+                                    else if( TOKEN_UPP ) fn[i++] = *p + 32;
+                                    else if( TOKEN_LOW ) fn[i++] = *p;
+                                    else abort( PARSE_BAD_SEQ_IDENTIFIER )
+                                    if( i == 16 ) abort( PARSE_BAD_SEQ_TOOLONG )
+                                }
+                                     if( strcmp( fn, "mc") == 0 ) PUSH( VMC );
+                                else if( strcmp( fn, "m" ) == 0 ) PUSH( VM_ );
+                                else if( strcmp( fn, "c" ) == 0 ) PUSH( VC_ );
+                                else if( strcmp( fn, "a" ) == 0 ) PUSH( VA_ );
+                                else if( strcmp( fn, "b" ) == 0 ) PUSH( VB_ );
+                                else if( strcmp( fn, "n" ) == 0 ) PUSH( VN_ );
+                                else if( strcmp( fn, "d" ) == 0 ) PUSH( VD_ );
+                                else if( strcmp( fn, "k" ) == 0 ) PUSH( VK_ );
+                                else {
+                                    for( int j = 0 ; j < i ; j++ )
+                                        PUSH( CID + fn[j] );
+                                    PUSH( CID );
+                                }
+                            } args++; break;
+
+                default: if( TOKEN_UPP ) *p += 32;
+                
+                    if( TOKEN_LOW ) { char fn[] = {*p,0,0,0,0,0,0,0,0,0}; int i = 1;
+                            while( 1 ) {
+                                p++; if( *p == '(' ) break;
+                                else if( TOKEN_UPP ) fn[i++] = *p + 32;
+                                else if( TOKEN_LOW ) fn[i++] = *p;
+                                else if( TOKEN_NUM ) fn[i++] = *p;
+                                else abort(PARSE_BAD_SEQ_FUNCTION)
+                            }
+                            p++; // skip (
+                            if( level == 1 ) PUSH( SEQ );
+                            short a = SubParse( p );
+                            if( a == 0 ) return 0;
+                            int n = GetOPIDfromFunction( fn );
+                            if( n == 0 ) abort(PARSE_BAD_SEQ_FUNCTION)
+                            if( n == MAP ) PUSH( a );
+                            PUSH( n );
+                            if( level==1 && n!=E8_ && n!=E14 && n!=RPN && n!=NPN && n!=BNK && n!=NP8 ) PUSH( E7_ );
+                            args++;
+                            break;
+                    }
+                    if( TOKEN_NUM ) { 
+                            num = *p - 48;
+                            while( 1 ) {
+                                p++; if( TOKEN_END ) { PUSH( num ); break; }
+                                else if( TOKEN_NUM )   num = num * 10 + (*p - 48 );
+                                else abort( PARSE_BAD_SEQ_NUMBER )
+                            } args++; break;                                
+                    }
+                    abort( PARSE_BAD_SEQ_SYNTAXE )
+            }
+        }
+        level--;
+        return args;
+    }
+};
+
+class ParseRoute
+{
+public :
+    byte Inport;
+    byte Message;
+    short  Channels;
+    short minA;
+    short maxA;
+    short minB;
+    short maxB;
+    vector<byte> Head;
+    vector<short> Sequence1;
+    vector<short> Sequence2;
+    vector<short> Sequence3;
+    vector<Assignment*> Assigns;
+
+    ParseRoute() : Inport(0), Message(NAKN), Channels(NAKW), minA(NAKN), maxA(NAKN), minB(NAKN), maxB(NAKN) {}
+    ~ParseRoute()
+    {
+    }
+    bool Add( ParseEntry* entry )
+    {
+        ParseMessage*  m = (ParseMessage*)entry;
+        ParseFlag*     f = (ParseFlag*)entry;
+        ParseByte*     b = (ParseByte*)entry;
+        ParseShort*    s = (ParseShort*)entry;
+        ParseSequence* q = (ParseSequence*)entry;
+        
+             if( strcmp( entry->Name, "input1"   ) == 0 ) { Inport   = 0; Message  = m->Code; return true; }
+        else if( strcmp( entry->Name, "input2"   ) == 0 ) { Inport   = 1; Message  = m->Code; return true; }
+        else if( strcmp( entry->Name, "input3"   ) == 0 ) { Inport   = 2; Message  = m->Code; return true; }
+        else if( strcmp( entry->Name, "channels" ) == 0 ) { Channels = f->Flag; return true; }
+        else if( strcmp( entry->Name, "program"  ) == 0 ) { minA     = b->Mini; maxA = b->Maxi; return true; }
+        else if( strcmp( entry->Name, "valuea"   ) == 0 ) { minA     = b->Mini; maxA = b->Maxi; return true; }
+        else if( strcmp( entry->Name, "valueb"   ) == 0 ) { minB     = b->Mini; maxB = b->Maxi; return true; }
+        else if( strcmp( entry->Name, "parameter") == 0 ) { minA     = s->Mini; maxA = s->Maxi; return true; }
+        else if( strcmp( entry->Name, "data"     ) == 0 ) { minB     = s->Mini; maxB = s->Maxi; return true; }
+        else if( strcmp( entry->Name, "bank"     ) == 0 ) { minA     = s->Mini; maxA = s->Maxi; return true; }
+        else if( strcmp( entry->Name, "output1"  ) == 0 ) { Sequence1.insert( Sequence1.end(), q->Sequence.begin(), q->Sequence.end() ); return true; }
+        else if( strcmp( entry->Name, "output2"  ) == 0 ) { Sequence2.insert( Sequence2.end(), q->Sequence.begin(), q->Sequence.end() ); return true; }
+        else if( strcmp( entry->Name, "output3"  ) == 0 ) { Sequence3.insert( Sequence3.end(), q->Sequence.begin(), q->Sequence.end() ); return true; }
+        else if( strcmp( entry->Name, "header"   ) == 0 ) { Head.insert( Head.end(), q->Sequence.begin(), q->Sequence.end() ); return true; }
+        else if( entry->Name[0] == '%' )                  { Assigns.push_back( new Assignment( entry->Name + 1 /* skip the %*/, q->Sequence ) ); return true; }
+        ParseError = PARSE_UNKNWON_ENTRY;
+        return false;
+    }
+    bool Done()    
+    { 
+        FL.Add( Inport, Message, Channels, minA, maxA, minB, maxB, Head, Sequence1, Sequence2, Sequence3, Assigns );
+        return true; 
+    }
+};
+
+const char keywords_flag[] = "channels";
+const char keywords_nums[] = "valueA valueB program";
+const char keywords_nu14[] = "parameter data bank";
+const char keywords_mess[] = "input1 input2 input3";
+const char keywords_sequ[] = "output1 output2 output3 header";
+
+bool Parse()
+{
+    char Line1[256];
+    char Line2[256];
+    LocalFileSystem local("local");
+    FILE* f = fopen( "/local/filter.txt", "r" );
+    if( f == NULL )
+    {
+        ParseError = PARSE_NO_FILE;
+        return false;
+    }
+    ParseRoute* pr = NULL;
+    ParseLine = 0;
+    while( /* ( ParseLine < 200 ) && */ fgets( Line1, 256, f ) )
+    {
+        ParseLine++;
+        ParseEntry* sp = NULL;
+
+        ParseCleanUp( Line1, Line2 );
+        strtok( Line2, ":" );
+
+        if( Line2[0] == 0 || Line2[0] == 10 ) continue;
+
+        if( strcmp( Line2, "ROUTE"      ) == 0 ) { 
+            if( pr ) if( ! pr->Done() ) goto Bad;     
+            delete pr;
+            pr = NULL;
+            int mem =  AvailableMemory();
+            if( mem < 512 ) { printf("Only %d bytes left for program.\nFilter definitions reading stopped at line %d\n", mem, ParseLine ); break; }
+            pr = new ParseRoute();
+        }
+        else if( strstr( keywords_flag, Line2 ) )      sp = new ParseFlag(    Line2 );
+        else if( strstr( keywords_nums, Line2 ) )      sp = new ParseByte(    Line2 );
+        else if( strstr( keywords_nu14, Line2 ) )      sp = new ParseShort(   Line2 );
+        else if( strstr( keywords_mess, Line2 ) )      sp = new ParseMessage( Line2 );
+        else if( strstr( keywords_sequ, Line2 ) )      sp = new ParseSequence(Line2 );
+        else if( Line2[0] == '%' )                     sp = new ParseSequence(Line2 );
+        else { ParseError = PARSE_UNKNWON_ENTRY; goto Bad; }
+
+        if( sp != NULL )
+        {
+            if( pr == NULL )                          goto Bad;
+            if( ! sp->Parse( strtok( NULL, "\n" ) ) ) goto Bad;
+            if( ! pr->Add( sp ) )                     goto Bad;
+            delete sp;
+        }
+    }
+
+    if( pr ) if( ! pr->Done() ) goto Bad;
+
+    fclose( f );
+    return true;
+Bad:
+    if( f != NULL ) fclose(f);
+    return false;
+}
+
+#undef abort
+#undef TOKEN_END
+#undef TOKEN_NUM
+#undef TOKEN_LOW
+#undef TOKEN_UPP
+#undef TOKEN_LOX
+#undef TOKEN_UPX
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stack.h	Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,49 @@
+#ifndef STACK_H
+#define STACK_H
+
+template<class T>
+class Stack
+{
+public:
+    T Data[50];
+    short Position;
+
+    Stack() : Position(0) {}
+
+    inline void Push( T v ) { if( Position < 50 ) Data[Position++] = v; }
+    inline T Pull() { if( Position ) return Data[--Position]; else return (T)NAKN; }
+    
+    void Pull( T &a ) 
+    { 
+        if( Position )     a = Data[--Position]; 
+        else             a = (T)NAKN; 
+    }
+    void Pull( T &b, T &a ) 
+    { 
+        if( Position )  b = Data[--Position]; 
+        else            b = (T)NAKN; 
+        if( Position )  a = Data[--Position]; 
+        else            a = (T)NAKN; 
+    }
+    void Pull( T &c, T &b, T &a ) 
+    { 
+        if( Position )  c = Data[--Position]; 
+        else            c = (T)NAKN; 
+        if( Position )  b = Data[--Position]; 
+        else            b = (T)NAKN; 
+        if( Position )  a = Data[--Position]; 
+        else            a = (T)NAKN; 
+    }
+    void Pull( T &d, T &c, T &b, T &a ) 
+    { 
+        if( Position )  d = Data[--Position]; 
+        else            d = (T)NAKN; 
+        if( Position )  c = Data[--Position]; 
+        else            c = (T)NAKN; 
+        if( Position )  b = Data[--Position]; 
+        else            b = (T)NAKN; 
+        if( Position )  a = Data[--Position]; 
+        else            a = (T)NAKN; 
+    }
+};
+#endif
\ No newline at end of file