Bernard Escaillas
/
MidiTee
Revision 0:71d791204057, committed 2011-06-07
- Comitter:
- Midimetric
- Date:
- Tue Jun 07 13:32:20 2011 +0000
- Commit message:
- Version 1.0
Changed in this revision
--- /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