Bernard Escaillas
/
MidiTee
filter.h@0:71d791204057, 2011-06-07 (annotated)
- Committer:
- Midimetric
- Date:
- Tue Jun 07 13:32:20 2011 +0000
- Revision:
- 0:71d791204057
Version 1.0
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Midimetric | 0:71d791204057 | 1 | #include <vector> |
Midimetric | 0:71d791204057 | 2 | #include "midi.h" |
Midimetric | 0:71d791204057 | 3 | #include "stack.h" |
Midimetric | 0:71d791204057 | 4 | #include "memory.h" |
Midimetric | 0:71d791204057 | 5 | |
Midimetric | 0:71d791204057 | 6 | #define TO_OUT1 1 |
Midimetric | 0:71d791204057 | 7 | #define TO_OUT2 2 |
Midimetric | 0:71d791204057 | 8 | #define TO_OUT3 4 |
Midimetric | 0:71d791204057 | 9 | |
Midimetric | 0:71d791204057 | 10 | #define BitSet( flag, bit ) ( ( flag >> bit ) & 1 ) |
Midimetric | 0:71d791204057 | 11 | #define BitPut( flag, bit ) ( flag | ( 1 << bit ) ) |
Midimetric | 0:71d791204057 | 12 | #define BitDel( flag, bit ) ( flag & ~( 1 << bit ) ) |
Midimetric | 0:71d791204057 | 13 | |
Midimetric | 0:71d791204057 | 14 | // literals are either 8 bits ( 0 to 255 ) or 14 bits ( 0 to 16383 / -8192 to 8191 ) |
Midimetric | 0:71d791204057 | 15 | // 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 |
Midimetric | 0:71d791204057 | 16 | |
Midimetric | 0:71d791204057 | 17 | #define ISCOMMAND(x) ( (x & 0xF000) == 0x4000 ) |
Midimetric | 0:71d791204057 | 18 | |
Midimetric | 0:71d791204057 | 19 | // sequence delimiter |
Midimetric | 0:71d791204057 | 20 | #define SEQ 0x4000 // escape; introducing a sequence in a Chain: |
Midimetric | 0:71d791204057 | 21 | #define E7_ 0x4001 // return 7 bits byte from computation |
Midimetric | 0:71d791204057 | 22 | #define E8_ 0x4002 // return 8 bits byte from computation |
Midimetric | 0:71d791204057 | 23 | #define E14 0x4003 // return 14 bits word from computation (msb then lsb) |
Midimetric | 0:71d791204057 | 24 | #define NOP 0x4004 // nul terminator in sequence array |
Midimetric | 0:71d791204057 | 25 | #define RAW 0x4005 // output is raw input (no change) |
Midimetric | 0:71d791204057 | 26 | // VALUES |
Midimetric | 0:71d791204057 | 27 | #define VMC 0x4010 // =%mc Full midi command (base command + channel), can be used in sequence or alone |
Midimetric | 0:71d791204057 | 28 | #define VM_ 0x4011 // =%m Base midi command (4 msb of VMC ), can be used in sequence or alone |
Midimetric | 0:71d791204057 | 29 | #define VC_ 0x4012 // =%c Value of Channel (4 lsb of VMC ) |
Midimetric | 0:71d791204057 | 30 | #define VA_ 0x4013 // Value A, can be used in sequence or alone |
Midimetric | 0:71d791204057 | 31 | #define VB_ 0x4014 // Value B |
Midimetric | 0:71d791204057 | 32 | #define VN_ 0x4015 // RPN or NRPN 14bits number |
Midimetric | 0:71d791204057 | 33 | #define VD_ 0x4016 // RPN or NRPN 14bits data |
Midimetric | 0:71d791204057 | 34 | #define VK_ 0x4017 // Bank 14bits data |
Midimetric | 0:71d791204057 | 35 | |
Midimetric | 0:71d791204057 | 36 | // FUNCTIONS |
Midimetric | 0:71d791204057 | 37 | #define ADD 0x4020 |
Midimetric | 0:71d791204057 | 38 | #define SUB 0x4021 // Add 14 bits value as signed integer, bound to 0 - 0xFFFF |
Midimetric | 0:71d791204057 | 39 | #define MUL 0x4022 |
Midimetric | 0:71d791204057 | 40 | #define DIV 0x4023 |
Midimetric | 0:71d791204057 | 41 | #define MOD 0x4024 |
Midimetric | 0:71d791204057 | 42 | #define BIT 0x4125 // folowing int is index value then bit shift then bits count |
Midimetric | 0:71d791204057 | 43 | #define BOR 0x4026 // bynary OR |
Midimetric | 0:71d791204057 | 44 | #define BAN 0x4027 // bynary AND |
Midimetric | 0:71d791204057 | 45 | #define BNO 0x4028 // bynary NOT |
Midimetric | 0:71d791204057 | 46 | #define BSL 0x4029 // bynary shift left (<<) |
Midimetric | 0:71d791204057 | 47 | #define BSR 0x402A // bynary shift right (>>) |
Midimetric | 0:71d791204057 | 48 | #define MAP 0x402B // discrete value mapping |
Midimetric | 0:71d791204057 | 49 | #define RPN 0x402C // RPN type formated output |
Midimetric | 0:71d791204057 | 50 | #define NPN 0x402D // NRPN type formated output |
Midimetric | 0:71d791204057 | 51 | #define BNK 0x402E // Bank type formated output |
Midimetric | 0:71d791204057 | 52 | #define MSB 0x402F // msb part of value |
Midimetric | 0:71d791204057 | 53 | #define LSB 0x4030 // lsb part of value |
Midimetric | 0:71d791204057 | 54 | #define NP8 0x4031 // 8 bit value NRPN (sends only CC6 not CC38) |
Midimetric | 0:71d791204057 | 55 | |
Midimetric | 0:71d791204057 | 56 | // checkSUm |
Midimetric | 0:71d791204057 | 57 | // - compute checksum from value after 'SUB' to value before 'SUE' |
Midimetric | 0:71d791204057 | 58 | #define CSB 0x4040 // checkSUm Begin |
Midimetric | 0:71d791204057 | 59 | #define CSE 0x4041 // checkSUm End |
Midimetric | 0:71d791204057 | 60 | #define CS1 0x4042 // insert 8 bit checksum at position (careful:may appear before SUB-SUE range) |
Midimetric | 0:71d791204057 | 61 | #define CS2 0x4043 // 32 bits checksum |
Midimetric | 0:71d791204057 | 62 | // Checksum Type1 (Roland) : -( sum( SUB -> SUE ) & 127 ) & 127 |
Midimetric | 0:71d791204057 | 63 | // Checksum Type2 (Alesis) : -( sum( SUB -> SUE ) & 0xFFFF ) & 0xFFFF |
Midimetric | 0:71d791204057 | 64 | |
Midimetric | 0:71d791204057 | 65 | // custom identifiers |
Midimetric | 0:71d791204057 | 66 | #define CID 0x4100 // end of Custom IDentifier |
Midimetric | 0:71d791204057 | 67 | // 0x41cc // cc = ascii char index |
Midimetric | 0:71d791204057 | 68 | #define CUL 0x4200 // Custom identifier character set Upper Limit |
Midimetric | 0:71d791204057 | 69 | |
Midimetric | 0:71d791204057 | 70 | #if _DEBUGFILTER |
Midimetric | 0:71d791204057 | 71 | #include "filter_debug.h" |
Midimetric | 0:71d791204057 | 72 | #endif |
Midimetric | 0:71d791204057 | 73 | |
Midimetric | 0:71d791204057 | 74 | // error codes returned by Compute |
Midimetric | 0:71d791204057 | 75 | #define CHAIN_SKIPROUTE -1 |
Midimetric | 0:71d791204057 | 76 | #define CHAIN_NOERROR 0 |
Midimetric | 0:71d791204057 | 77 | #define CHAIN_STACK_FAILURE 1 |
Midimetric | 0:71d791204057 | 78 | #define CHAIN_MISSING_SUB 2 |
Midimetric | 0:71d791204057 | 79 | #define CHAIN_MISSING_SUE 3 |
Midimetric | 0:71d791204057 | 80 | #define CHAIN_SUB_AFTER_SUE 4 |
Midimetric | 0:71d791204057 | 81 | #define CHAIN_NOT_A_BYTE 5 |
Midimetric | 0:71d791204057 | 82 | #define CHAIN_UNKNOWN_OP 6 |
Midimetric | 0:71d791204057 | 83 | #define CHAIN_SYNTAXE_ERROR 7 |
Midimetric | 0:71d791204057 | 84 | #define CHAIN_DIVIDE_BY_ZERO 8 |
Midimetric | 0:71d791204057 | 85 | |
Midimetric | 0:71d791204057 | 86 | #define NEXT i++; break; |
Midimetric | 0:71d791204057 | 87 | #define PUSH(x) Out.push_back(x) |
Midimetric | 0:71d791204057 | 88 | |
Midimetric | 0:71d791204057 | 89 | short bitmasking[] = {0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383}; |
Midimetric | 0:71d791204057 | 90 | |
Midimetric | 0:71d791204057 | 91 | //_____________________________________________________________________________ |
Midimetric | 0:71d791204057 | 92 | class Chain |
Midimetric | 0:71d791204057 | 93 | {//"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" |
Midimetric | 0:71d791204057 | 94 | // a chain defines for each port a message composed of fixed bytes or symbols |
Midimetric | 0:71d791204057 | 95 | public: |
Midimetric | 0:71d791204057 | 96 | vector<short> Msg[3]; |
Midimetric | 0:71d791204057 | 97 | vector<byte> Out; |
Midimetric | 0:71d791204057 | 98 | |
Midimetric | 0:71d791204057 | 99 | Chain() { } |
Midimetric | 0:71d791204057 | 100 | Chain( vector<short> &msg1, vector<short> &msg2, vector<short> &msg3 ) { Msg[0] = msg1; Msg[1] = msg2; Msg[2] = msg3; } |
Midimetric | 0:71d791204057 | 101 | ~Chain() { } |
Midimetric | 0:71d791204057 | 102 | |
Midimetric | 0:71d791204057 | 103 | void Done() // clear output vector until next compute to avoid keeping computation for all filters in memory |
Midimetric | 0:71d791204057 | 104 | { |
Midimetric | 0:71d791204057 | 105 | Out.clear(); |
Midimetric | 0:71d791204057 | 106 | } |
Midimetric | 0:71d791204057 | 107 | short Compute( byte port, MidiM &cur, MidiM &prev ) // 0=ok, else return error code |
Midimetric | 0:71d791204057 | 108 | { |
Midimetric | 0:71d791204057 | 109 | short max = Msg[port].size(); |
Midimetric | 0:71d791204057 | 110 | if( max == 0 ) return -1; |
Midimetric | 0:71d791204057 | 111 | |
Midimetric | 0:71d791204057 | 112 | Stack<long> k; |
Midimetric | 0:71d791204057 | 113 | long a,b,c,d; // temp |
Midimetric | 0:71d791204057 | 114 | short i = 0; // next position in Msg |
Midimetric | 0:71d791204057 | 115 | bool s = false; // true when "in sequence" |
Midimetric | 0:71d791204057 | 116 | short csb = -1; // position of check sum begin |
Midimetric | 0:71d791204057 | 117 | short cse = -1; // position of check sum end |
Midimetric | 0:71d791204057 | 118 | short csu = 0; // position where to insert check sum |
Midimetric | 0:71d791204057 | 119 | short cst = 0; // check sum type |
Midimetric | 0:71d791204057 | 120 | |
Midimetric | 0:71d791204057 | 121 | Out.clear(); |
Midimetric | 0:71d791204057 | 122 | |
Midimetric | 0:71d791204057 | 123 | while( i < max ) |
Midimetric | 0:71d791204057 | 124 | { |
Midimetric | 0:71d791204057 | 125 | short n = Msg[port][i]; |
Midimetric | 0:71d791204057 | 126 | if( ! s ) // out of sequence, expect a byte value or a custom identifier or SEQ |
Midimetric | 0:71d791204057 | 127 | { |
Midimetric | 0:71d791204057 | 128 | if( n < 256 ) { PUSH( (byte)n ); i++; } // just copy fixed message byte |
Midimetric | 0:71d791204057 | 129 | else if( ! ISCOMMAND( n ) ) return CHAIN_NOT_A_BYTE; // short values are not allowed outside of sequence |
Midimetric | 0:71d791204057 | 130 | else switch( n ) { |
Midimetric | 0:71d791204057 | 131 | case SEQ : s = true; NEXT |
Midimetric | 0:71d791204057 | 132 | case VMC : PUSH( cur.Command | ( cur.Channel == NAKN ? 0 : cur.Channel ) ); NEXT |
Midimetric | 0:71d791204057 | 133 | case VM_ : PUSH( cur.Command ); NEXT |
Midimetric | 0:71d791204057 | 134 | case VC_ : PUSH( cur.Channel == NAKN ? 0 : cur.Channel ); NEXT |
Midimetric | 0:71d791204057 | 135 | case VA_ : PUSH( cur.ValA ); NEXT |
Midimetric | 0:71d791204057 | 136 | case VB_ : PUSH( cur.ValB ); NEXT |
Midimetric | 0:71d791204057 | 137 | case VN_ : PUSH( prev.ValA ); PUSH( prev.ValB ); NEXT |
Midimetric | 0:71d791204057 | 138 | case VD_ : PUSH( cur.ValA ); PUSH( cur.ValB ); NEXT |
Midimetric | 0:71d791204057 | 139 | case VK_ : PUSH( cur.ValA ); PUSH( cur.ValB ); NEXT |
Midimetric | 0:71d791204057 | 140 | |
Midimetric | 0:71d791204057 | 141 | case RAW : if( ( cur.Type == DATA || cur.Type == INCR || cur.Type == DECR ) |
Midimetric | 0:71d791204057 | 142 | && ( prev.Type == NRPN || prev.Type == RPN_ ) ) |
Midimetric | 0:71d791204057 | 143 | { |
Midimetric | 0:71d791204057 | 144 | Out = prev.Raw; Out.insert( Out.end(), cur.Raw.begin(), cur.Raw.end() ); |
Midimetric | 0:71d791204057 | 145 | } |
Midimetric | 0:71d791204057 | 146 | else Out = cur.Raw; |
Midimetric | 0:71d791204057 | 147 | return 0; |
Midimetric | 0:71d791204057 | 148 | |
Midimetric | 0:71d791204057 | 149 | default : {char id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; short idi = 0; |
Midimetric | 0:71d791204057 | 150 | while( n > CID && n < CUL ) { id[idi++] = (char)(n - CID); n = Msg[port][++i]; } |
Midimetric | 0:71d791204057 | 151 | PUSH( (byte)ML.Get( id ) ); } NEXT |
Midimetric | 0:71d791204057 | 152 | } |
Midimetric | 0:71d791204057 | 153 | } |
Midimetric | 0:71d791204057 | 154 | else if( ! ISCOMMAND( n ) ) // 14 bit literal inside a sequence, push on stack |
Midimetric | 0:71d791204057 | 155 | { |
Midimetric | 0:71d791204057 | 156 | k.Push( n ); i++; |
Midimetric | 0:71d791204057 | 157 | } |
Midimetric | 0:71d791204057 | 158 | else switch( n ) |
Midimetric | 0:71d791204057 | 159 | { |
Midimetric | 0:71d791204057 | 160 | case NOP : NEXT |
Midimetric | 0:71d791204057 | 161 | case E7_ : k.Pull(a); if(a < 0) a=0; else if(a > 127) a=127; PUSH(a); s = false; NEXT |
Midimetric | 0:71d791204057 | 162 | case E8_ : k.Pull(a); if(a < 0) a=0; else if(a > 255) a=255; PUSH(a); s = false; NEXT |
Midimetric | 0:71d791204057 | 163 | case E14 : k.Pull(a); PUSH( (byte)(a >> 7) & 127 ); PUSH(a & 127); s = false; NEXT |
Midimetric | 0:71d791204057 | 164 | case VMC : k.Push( cur.Command|( cur.Channel == NAKN ? 0 : cur.Channel ) ); NEXT |
Midimetric | 0:71d791204057 | 165 | case VM_ : k.Push( cur.Command ); NEXT |
Midimetric | 0:71d791204057 | 166 | case VC_ : k.Push( ( cur.Channel == NAKN ? 0 : cur.Channel ) ); NEXT |
Midimetric | 0:71d791204057 | 167 | case VA_ : k.Push( cur.ValA ); NEXT |
Midimetric | 0:71d791204057 | 168 | case VB_ : k.Push( cur.ValB ); NEXT |
Midimetric | 0:71d791204057 | 169 | case VN_ : k.Push( prev.Get14() ); NEXT |
Midimetric | 0:71d791204057 | 170 | case VD_ : k.Push( cur.Get14() ); NEXT |
Midimetric | 0:71d791204057 | 171 | case VK_ : k.Push( cur.Get14() ); NEXT |
Midimetric | 0:71d791204057 | 172 | case ADD : k.Pull( b, a ); k.Push( a + b ); NEXT |
Midimetric | 0:71d791204057 | 173 | case SUB : k.Pull( b, a ); k.Push( a - b ); NEXT |
Midimetric | 0:71d791204057 | 174 | case MUL : k.Pull( b, a ); k.Push( a * b ); NEXT |
Midimetric | 0:71d791204057 | 175 | case DIV : k.Pull( b, a ); if(b==0) return CHAIN_DIVIDE_BY_ZERO; k.Push( a / b ); NEXT |
Midimetric | 0:71d791204057 | 176 | case MOD : k.Pull( b, a ); if(b==0) return CHAIN_DIVIDE_BY_ZERO; k.Push( a % b ); NEXT |
Midimetric | 0:71d791204057 | 177 | case BIT : k.Pull( c,b,a); k.Push(cur.Raw[a] >> b & bitmasking[c]); NEXT |
Midimetric | 0:71d791204057 | 178 | case BOR : k.Pull( b, a ); k.Push( a | b ); NEXT |
Midimetric | 0:71d791204057 | 179 | case BAN : k.Pull( b, a ); k.Push( a & b ); NEXT |
Midimetric | 0:71d791204057 | 180 | case BNO : k.Pull( a ); k.Push( ~a ); NEXT |
Midimetric | 0:71d791204057 | 181 | case BSL : k.Pull( b, a ); k.Push( a << b ); NEXT |
Midimetric | 0:71d791204057 | 182 | case BSR : k.Pull( b, a ); k.Push( a >> b ); NEXT |
Midimetric | 0:71d791204057 | 183 | case MSB : k.Pull( a ); k.Push( a >> 7 ); NEXT |
Midimetric | 0:71d791204057 | 184 | case LSB : k.Pull( a ); k.Push( a & 127 ); NEXT |
Midimetric | 0:71d791204057 | 185 | case CSB : csb=Out.size(); s = false; /*quit sequence not waiting for END*/ NEXT |
Midimetric | 0:71d791204057 | 186 | case CSE : cse=Out.size(); s = false; NEXT |
Midimetric | 0:71d791204057 | 187 | case CS1 : csu=Out.size(); cst=1; PUSH(0); NEXT |
Midimetric | 0:71d791204057 | 188 | case CS2 : csu=Out.size(); cst=2; PUSH(0); PUSH(0); PUSH(0); PUSH(0); NEXT |
Midimetric | 0:71d791204057 | 189 | case MAP : k.Pull( d, a, c, b ); d--; |
Midimetric | 0:71d791204057 | 190 | while( a != b ) |
Midimetric | 0:71d791204057 | 191 | if( ( d -= 2 ) == 0 ) return CHAIN_SKIPROUTE; |
Midimetric | 0:71d791204057 | 192 | else k.Pull( c, b ); |
Midimetric | 0:71d791204057 | 193 | while( d -= 2 ) k.Pull(a,b); /* unstack unused values */ k.Push( c ); NEXT |
Midimetric | 0:71d791204057 | 194 | case NPN : k.Pull( c,b,a); a &= 15; |
Midimetric | 0:71d791204057 | 195 | if( b > 127 ) { PUSH( 0xB0 + a ); PUSH( 99 ); PUSH( ( b >> 7 ) & 127 ); } |
Midimetric | 0:71d791204057 | 196 | PUSH( 0xB0 + a ); PUSH( 98 ); PUSH( b & 127 ); |
Midimetric | 0:71d791204057 | 197 | PUSH( 0xB0 + a ); PUSH( 6 ); PUSH( ( c >> 7 ) & 127 ); |
Midimetric | 0:71d791204057 | 198 | PUSH( 0xB0 + a ); PUSH( 38 ); PUSH( c & 127 ); NEXT |
Midimetric | 0:71d791204057 | 199 | |
Midimetric | 0:71d791204057 | 200 | case NP8 : k.Pull( c,b,a); a &= 15; |
Midimetric | 0:71d791204057 | 201 | if( b > 127 ) { PUSH( 0xB0 + a ); PUSH( 99 ); PUSH( ( b >> 7 ) & 127 ); } |
Midimetric | 0:71d791204057 | 202 | PUSH( 0xB0 + a ); PUSH( 98 ); PUSH( b & 127 ); |
Midimetric | 0:71d791204057 | 203 | PUSH( 0xB0 + a ); PUSH( 6 ); PUSH( c & 127 ); NEXT |
Midimetric | 0:71d791204057 | 204 | |
Midimetric | 0:71d791204057 | 205 | case RPN : k.Pull( c,b,a); a &= 15; |
Midimetric | 0:71d791204057 | 206 | if( b > 127 ) { PUSH( 0xB0 + a ); PUSH(101 ); PUSH( ( b >> 7 ) & 127 ); } |
Midimetric | 0:71d791204057 | 207 | PUSH( 0xB0 + a ); PUSH(100 ); PUSH( b & 127 ); |
Midimetric | 0:71d791204057 | 208 | PUSH( 0xB0 + a ); PUSH( 6 ); PUSH( ( c >> 7 ) & 127 ); |
Midimetric | 0:71d791204057 | 209 | PUSH( 0xB0 + a ); PUSH( 38 ); PUSH( c & 127 ); NEXT |
Midimetric | 0:71d791204057 | 210 | |
Midimetric | 0:71d791204057 | 211 | case BNK : k.Pull( b, a ); a &= 15; |
Midimetric | 0:71d791204057 | 212 | if( b > 127 ) { PUSH( 0xB0 + a ); PUSH( 0 ); PUSH( ( b >> 7 ) & 127 ); } |
Midimetric | 0:71d791204057 | 213 | PUSH( 0xB0 + a ); PUSH( 32 ); PUSH( b & 127 ); NEXT |
Midimetric | 0:71d791204057 | 214 | default: |
Midimetric | 0:71d791204057 | 215 | if( n <= CID && n > CID + 0xFF )return CHAIN_UNKNOWN_OP; |
Midimetric | 0:71d791204057 | 216 | {char id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; short idi = 0; |
Midimetric | 0:71d791204057 | 217 | while( n > CID && n < CUL ) { id[idi++] = (char)(n - CID); |
Midimetric | 0:71d791204057 | 218 | n = Msg[port][++i]; } k.Push( (byte)ML.Get( id ) ); } NEXT |
Midimetric | 0:71d791204057 | 219 | } |
Midimetric | 0:71d791204057 | 220 | } |
Midimetric | 0:71d791204057 | 221 | c = 0; |
Midimetric | 0:71d791204057 | 222 | if( cst ) |
Midimetric | 0:71d791204057 | 223 | { |
Midimetric | 0:71d791204057 | 224 | if( csb == -1 ) return CHAIN_MISSING_SUB; |
Midimetric | 0:71d791204057 | 225 | if( cse == -1 ) return CHAIN_MISSING_SUE; |
Midimetric | 0:71d791204057 | 226 | if( csb >= cse ) return CHAIN_SUB_AFTER_SUE; |
Midimetric | 0:71d791204057 | 227 | } |
Midimetric | 0:71d791204057 | 228 | if( cst == 1 ) |
Midimetric | 0:71d791204057 | 229 | { |
Midimetric | 0:71d791204057 | 230 | for( i = csb ; i < cse ; i++ ) |
Midimetric | 0:71d791204057 | 231 | c -= Out[i]; |
Midimetric | 0:71d791204057 | 232 | Out[csu]= (byte)( c & 127 ); |
Midimetric | 0:71d791204057 | 233 | } |
Midimetric | 0:71d791204057 | 234 | if( cst == 2 ) |
Midimetric | 0:71d791204057 | 235 | { |
Midimetric | 0:71d791204057 | 236 | for( i = csb ; i < cse ; i += 4 ) |
Midimetric | 0:71d791204057 | 237 | c -= Out[i] + ( Out[i+1] << 8 ) + ( Out[i+2] << 16 ) + ( Out[i+3] << 24 ); |
Midimetric | 0:71d791204057 | 238 | Out[csu++]= (byte)( c ); |
Midimetric | 0:71d791204057 | 239 | Out[csu++]= (byte)( c >> 8 ); |
Midimetric | 0:71d791204057 | 240 | Out[csu++]= (byte)( c >> 16 ); |
Midimetric | 0:71d791204057 | 241 | Out[csu ]= (byte)( c >> 24 ); |
Midimetric | 0:71d791204057 | 242 | } |
Midimetric | 0:71d791204057 | 243 | |
Midimetric | 0:71d791204057 | 244 | return 0; |
Midimetric | 0:71d791204057 | 245 | } |
Midimetric | 0:71d791204057 | 246 | }; |
Midimetric | 0:71d791204057 | 247 | //_____________________________________________________________________________ |
Midimetric | 0:71d791204057 | 248 | class Assignment |
Midimetric | 0:71d791204057 | 249 | {//"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" |
Midimetric | 0:71d791204057 | 250 | public: |
Midimetric | 0:71d791204057 | 251 | char Name[17]; |
Midimetric | 0:71d791204057 | 252 | vector<short> Msg; |
Midimetric | 0:71d791204057 | 253 | short Value; |
Midimetric | 0:71d791204057 | 254 | |
Midimetric | 0:71d791204057 | 255 | Assignment() { Name[0] = 0; Value = NOP; } |
Midimetric | 0:71d791204057 | 256 | Assignment( char* name, vector<short> &msg ) { strncpy( Name, name, 17 ); Msg = msg; Value = NOP; } |
Midimetric | 0:71d791204057 | 257 | ~Assignment() { } |
Midimetric | 0:71d791204057 | 258 | |
Midimetric | 0:71d791204057 | 259 | short Compute( MidiM &cur, MidiM &prev ) // 0=ok, else return error code |
Midimetric | 0:71d791204057 | 260 | { |
Midimetric | 0:71d791204057 | 261 | Stack<long> k; |
Midimetric | 0:71d791204057 | 262 | long a,b,c,d; // temp |
Midimetric | 0:71d791204057 | 263 | short i = 0; // next position in Msg |
Midimetric | 0:71d791204057 | 264 | bool s = false; // true when "in sequence" |
Midimetric | 0:71d791204057 | 265 | |
Midimetric | 0:71d791204057 | 266 | while( i < Msg.size() ) |
Midimetric | 0:71d791204057 | 267 | { |
Midimetric | 0:71d791204057 | 268 | short n = Msg[i]; |
Midimetric | 0:71d791204057 | 269 | if( ! s ) // out of sequence, expect a byte value or a custom identifier or SEQ |
Midimetric | 0:71d791204057 | 270 | { |
Midimetric | 0:71d791204057 | 271 | if( n < 256 ) { Value = n; return 0; } // just copy fixed message byte |
Midimetric | 0:71d791204057 | 272 | else if( ! ISCOMMAND( n ) ) return CHAIN_NOT_A_BYTE; // short values are not allowed outside of sequence |
Midimetric | 0:71d791204057 | 273 | else switch( n ) { |
Midimetric | 0:71d791204057 | 274 | case SEQ : s = true; NEXT |
Midimetric | 0:71d791204057 | 275 | case VMC : Value = cur.Command | ( cur.Channel == NAKN ? 0 : cur.Channel ); return 0; |
Midimetric | 0:71d791204057 | 276 | case VM_ : Value = cur.Command; return 0; |
Midimetric | 0:71d791204057 | 277 | case VC_ : Value = ( cur.Channel == NAKN ? 0 : cur.Channel ); return 0; |
Midimetric | 0:71d791204057 | 278 | case VA_ : Value = cur.ValA; return 0; |
Midimetric | 0:71d791204057 | 279 | case VN_ : Value = prev.Get14(); return 0; |
Midimetric | 0:71d791204057 | 280 | case VB_ : Value = cur.ValB; return 0; |
Midimetric | 0:71d791204057 | 281 | case VD_ : |
Midimetric | 0:71d791204057 | 282 | case VK_ : Value = cur.Get14(); return 0; |
Midimetric | 0:71d791204057 | 283 | default : char id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; short idi = 0; |
Midimetric | 0:71d791204057 | 284 | while( n > CID && n < CUL ) { id[idi++] = (char)(n - CID); |
Midimetric | 0:71d791204057 | 285 | n = Msg[i++]; } Value = ML.Get( id ); return 0; |
Midimetric | 0:71d791204057 | 286 | } |
Midimetric | 0:71d791204057 | 287 | } |
Midimetric | 0:71d791204057 | 288 | else if( ! ISCOMMAND( n ) ) // 14 bit literal inside a sequence, push on stack |
Midimetric | 0:71d791204057 | 289 | { |
Midimetric | 0:71d791204057 | 290 | k.Push( n ); i++; |
Midimetric | 0:71d791204057 | 291 | } |
Midimetric | 0:71d791204057 | 292 | else switch( n ) |
Midimetric | 0:71d791204057 | 293 | { |
Midimetric | 0:71d791204057 | 294 | case E7_ : |
Midimetric | 0:71d791204057 | 295 | case E8_ : |
Midimetric | 0:71d791204057 | 296 | case E14 : Value = (short)k.Pull(); return 0; |
Midimetric | 0:71d791204057 | 297 | |
Midimetric | 0:71d791204057 | 298 | case VMC : k.Push( cur.Command|( cur.Channel == NAKN ? 0 : cur.Channel ) ); NEXT |
Midimetric | 0:71d791204057 | 299 | case VM_ : k.Push( cur.Command ); NEXT |
Midimetric | 0:71d791204057 | 300 | case VC_ : k.Push( ( cur.Channel == NAKN ? 0 : cur.Channel ) ); NEXT |
Midimetric | 0:71d791204057 | 301 | case VA_ : k.Push( cur.ValA ); NEXT |
Midimetric | 0:71d791204057 | 302 | case VB_ : k.Push( cur.ValB ); NEXT |
Midimetric | 0:71d791204057 | 303 | case VN_ : k.Push( prev.Get14() ); NEXT |
Midimetric | 0:71d791204057 | 304 | case VD_ : |
Midimetric | 0:71d791204057 | 305 | case VK_ : k.Push( cur.Get14() ); NEXT |
Midimetric | 0:71d791204057 | 306 | case ADD : k.Pull( b, a ); k.Push( a + b ); NEXT |
Midimetric | 0:71d791204057 | 307 | case SUB : k.Pull( b, a ); k.Push( a - b ); NEXT |
Midimetric | 0:71d791204057 | 308 | case MUL : k.Pull( b, a ); k.Push( a * b ); NEXT |
Midimetric | 0:71d791204057 | 309 | case DIV : k.Pull( b, a ); k.Push( a / b ); NEXT |
Midimetric | 0:71d791204057 | 310 | case MOD : k.Pull( b, a ); k.Push( a % b ); NEXT |
Midimetric | 0:71d791204057 | 311 | case BIT : k.Pull( c,b,a); k.Push( cur.Raw[a] >> b & bitmasking[c] ); NEXT |
Midimetric | 0:71d791204057 | 312 | case BOR : k.Pull( b, a ); k.Push( a | b ); NEXT |
Midimetric | 0:71d791204057 | 313 | case BAN : k.Pull( b, a ); k.Push( a & b ); NEXT |
Midimetric | 0:71d791204057 | 314 | case BNO : k.Pull( a ); k.Push( ~a ); NEXT |
Midimetric | 0:71d791204057 | 315 | case BSL : k.Pull( b, a ); k.Push( a << b ); NEXT |
Midimetric | 0:71d791204057 | 316 | case BSR : k.Pull( b, a ); k.Push( a >> b ); NEXT |
Midimetric | 0:71d791204057 | 317 | case MSB : k.Pull( a ); k.Push( a >> 7 ); NEXT |
Midimetric | 0:71d791204057 | 318 | case LSB : k.Pull( a ); k.Push( a & 127 ); NEXT |
Midimetric | 0:71d791204057 | 319 | case MAP : k.Pull( d, a, c, b ); d--; |
Midimetric | 0:71d791204057 | 320 | while( a != b ) |
Midimetric | 0:71d791204057 | 321 | if( ( d -= 2 ) == 0 ) { k.Push( NAKN ); NEXT } |
Midimetric | 0:71d791204057 | 322 | else k.Pull( c, b ); |
Midimetric | 0:71d791204057 | 323 | while( d -= 2 ) k.Pull(a,b); /* unstack unused values */ k.Push( c ); NEXT |
Midimetric | 0:71d791204057 | 324 | default: |
Midimetric | 0:71d791204057 | 325 | if( n <= CID && n > CID + 0xFF )return CHAIN_UNKNOWN_OP; |
Midimetric | 0:71d791204057 | 326 | {char id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; short idi = 0; |
Midimetric | 0:71d791204057 | 327 | while( n > CID && n < CUL ) { id[idi++] = (char)(n - CID); |
Midimetric | 0:71d791204057 | 328 | n = Msg[++i]; } k.Push( (byte)ML.Get( id ) ); } NEXT |
Midimetric | 0:71d791204057 | 329 | } |
Midimetric | 0:71d791204057 | 330 | } |
Midimetric | 0:71d791204057 | 331 | return CHAIN_SYNTAXE_ERROR; |
Midimetric | 0:71d791204057 | 332 | } |
Midimetric | 0:71d791204057 | 333 | }; |
Midimetric | 0:71d791204057 | 334 | //_____________________________________________________________________________ |
Midimetric | 0:71d791204057 | 335 | class Filter |
Midimetric | 0:71d791204057 | 336 | {//"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" |
Midimetric | 0:71d791204057 | 337 | public: |
Midimetric | 0:71d791204057 | 338 | byte Port; // use constants TO_OUT1...3 |
Midimetric | 0:71d791204057 | 339 | byte Type; // use constants NOTE, POLA, ... from midi.h |
Midimetric | 0:71d791204057 | 340 | short Channel; |
Midimetric | 0:71d791204057 | 341 | short Amin; // may be a 14 bits value for RPN, NRPN identifier |
Midimetric | 0:71d791204057 | 342 | short Amax; |
Midimetric | 0:71d791204057 | 343 | short Bmin; // may be a 14 bits value for RPN, NRPN value |
Midimetric | 0:71d791204057 | 344 | short Bmax; |
Midimetric | 0:71d791204057 | 345 | vector<byte> Head; |
Midimetric | 0:71d791204057 | 346 | Chain Out; |
Midimetric | 0:71d791204057 | 347 | vector<Assignment*> Assigns; |
Midimetric | 0:71d791204057 | 348 | |
Midimetric | 0:71d791204057 | 349 | Filter() : Port(0), Type(0), Channel(NAKW), Amin(NAKN), Amax(NAKN), Bmin(NAKN), Bmax(NAKN), Head( 1, (short)0xF0 ) { } |
Midimetric | 0:71d791204057 | 350 | ~Filter() { } |
Midimetric | 0:71d791204057 | 351 | |
Midimetric | 0:71d791204057 | 352 | Filter( Filter & f ) |
Midimetric | 0:71d791204057 | 353 | : Port(f.Port),Type(f.Type),Channel(f.Channel),Amin(f.Amin),Amax(f.Amax),Bmin(f.Bmin),Bmax(f.Bmax) |
Midimetric | 0:71d791204057 | 354 | { |
Midimetric | 0:71d791204057 | 355 | 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; |
Midimetric | 0:71d791204057 | 356 | } |
Midimetric | 0:71d791204057 | 357 | |
Midimetric | 0:71d791204057 | 358 | 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 ) |
Midimetric | 0:71d791204057 | 359 | : Port(p), Type(t), Channel(c), Amin(ai), Amax(ax), Bmin(bi), Bmax(bx) |
Midimetric | 0:71d791204057 | 360 | { |
Midimetric | 0:71d791204057 | 361 | Head = head; Out.Msg[0] = o1; Out.Msg[1] = o2; Out.Msg[2] = o3; Assigns = assigns; |
Midimetric | 0:71d791204057 | 362 | } |
Midimetric | 0:71d791204057 | 363 | }; |
Midimetric | 0:71d791204057 | 364 | |
Midimetric | 0:71d791204057 | 365 | //_____________________________________________________________________________ |
Midimetric | 0:71d791204057 | 366 | class FilterList |
Midimetric | 0:71d791204057 | 367 | {//"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" |
Midimetric | 0:71d791204057 | 368 | public: |
Midimetric | 0:71d791204057 | 369 | vector<Filter*> List; |
Midimetric | 0:71d791204057 | 370 | |
Midimetric | 0:71d791204057 | 371 | 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 ) |
Midimetric | 0:71d791204057 | 372 | { |
Midimetric | 0:71d791204057 | 373 | List.push_back( new Filter( inport, message, channels, mina, maxa, minb, maxb, head, sequence1, sequence2, sequence3, assigns ) ); |
Midimetric | 0:71d791204057 | 374 | HasBank |= message == BANK; |
Midimetric | 0:71d791204057 | 375 | HasData |= ( message >= DATA ) && ( message <= NRPN ); |
Midimetric | 0:71d791204057 | 376 | HasSysx |= message == SYSX; |
Midimetric | 0:71d791204057 | 377 | } |
Midimetric | 0:71d791204057 | 378 | Filter* operator[] ( short index ) |
Midimetric | 0:71d791204057 | 379 | { |
Midimetric | 0:71d791204057 | 380 | return List[index]; |
Midimetric | 0:71d791204057 | 381 | } |
Midimetric | 0:71d791204057 | 382 | void Route( byte from, MidiM &cur, MidiM &prev ) |
Midimetric | 0:71d791204057 | 383 | { |
Midimetric | 0:71d791204057 | 384 | for( short i = 0 ; i < List.size() ; i++ ) |
Midimetric | 0:71d791204057 | 385 | { |
Midimetric | 0:71d791204057 | 386 | Filter* f = List[i]; |
Midimetric | 0:71d791204057 | 387 | if( f->Port != from ) continue; |
Midimetric | 0:71d791204057 | 388 | |
Midimetric | 0:71d791204057 | 389 | if( HasSysx && ( f->Type == SYSX ) && ( cur.Type == SYSX ) ) |
Midimetric | 0:71d791204057 | 390 | { |
Midimetric | 0:71d791204057 | 391 | bool ok = f->Head.size() > 0; |
Midimetric | 0:71d791204057 | 392 | if( ok ) |
Midimetric | 0:71d791204057 | 393 | if( f->Head[0] != RAW ) |
Midimetric | 0:71d791204057 | 394 | for( int j = 0 ; j < f->Head.size() ; j++ ) |
Midimetric | 0:71d791204057 | 395 | if( j == cur.Raw.size() || f->Head[j] != cur.Raw[j] ) |
Midimetric | 0:71d791204057 | 396 | ok=false; |
Midimetric | 0:71d791204057 | 397 | if( ok ) |
Midimetric | 0:71d791204057 | 398 | { |
Midimetric | 0:71d791204057 | 399 | for( int assign = 0 ; assign < f->Assigns.size() ; assign++ ) |
Midimetric | 0:71d791204057 | 400 | if( f->Assigns[assign]->Compute( cur, prev ) == 0 ) |
Midimetric | 0:71d791204057 | 401 | ML.Add( f->Assigns[assign]->Name, f->Assigns[assign]->Value ); |
Midimetric | 0:71d791204057 | 402 | |
Midimetric | 0:71d791204057 | 403 | for( int port = 0 ; port < 3 ; port++ ) |
Midimetric | 0:71d791204057 | 404 | if( f->Out.Compute( port, cur, prev ) == 0 ) |
Midimetric | 0:71d791204057 | 405 | { |
Midimetric | 0:71d791204057 | 406 | led[3] = 1; |
Midimetric | 0:71d791204057 | 407 | for( short j = 0 ; j < f->Out.Out.size() ; j++ ) |
Midimetric | 0:71d791204057 | 408 | SL[port].putc( f->Out.Out[j] ); |
Midimetric | 0:71d791204057 | 409 | led[3] = 0; |
Midimetric | 0:71d791204057 | 410 | } |
Midimetric | 0:71d791204057 | 411 | f->Out.Done(); |
Midimetric | 0:71d791204057 | 412 | return; |
Midimetric | 0:71d791204057 | 413 | } |
Midimetric | 0:71d791204057 | 414 | } |
Midimetric | 0:71d791204057 | 415 | else if( HasData && ( f->Type == DATA || f->Type == INCR || f->Type == DECR ) && ( cur.Type == f->Type ) && ( prev.Type == NRPN || prev.Type == RPN_ ) ) |
Midimetric | 0:71d791204057 | 416 | { |
Midimetric | 0:71d791204057 | 417 | short number = prev.Get14(), data = cur.Get14(); |
Midimetric | 0:71d791204057 | 418 | if( f->Channel == NAKW || ( f->Channel & ( 1 << cur.Channel ) & ( 1 << prev.Channel ) ) ) |
Midimetric | 0:71d791204057 | 419 | if( f->Amin==NAKW || ( f->Amax==NAKW && number==f->Amin ) || ( f->Amax!=NAKW && number>=f->Amin && number<=f->Amax ) ) |
Midimetric | 0:71d791204057 | 420 | if( f->Bmin==NAKW || ( f->Bmax==NAKW && data==f->Bmin ) || ( f->Bmax!=NAKW && data>=f->Bmin && data<=f->Bmax ) ) |
Midimetric | 0:71d791204057 | 421 | { |
Midimetric | 0:71d791204057 | 422 | for( int assign = 0 ; assign < f->Assigns.size() ; assign++ ) |
Midimetric | 0:71d791204057 | 423 | if( f->Assigns[assign]->Compute( cur, prev ) == 0 ) |
Midimetric | 0:71d791204057 | 424 | ML.Add( f->Assigns[assign]->Name, f->Assigns[assign]->Value ); |
Midimetric | 0:71d791204057 | 425 | for( int port = 0 ; port < 3 ; port++ ) |
Midimetric | 0:71d791204057 | 426 | if( f->Out.Compute( port, cur, prev ) == 0 ) |
Midimetric | 0:71d791204057 | 427 | { |
Midimetric | 0:71d791204057 | 428 | for( short j = 0 ; j < f->Out.Out.size() ; j++ ) // check for unrountable message |
Midimetric | 0:71d791204057 | 429 | { |
Midimetric | 0:71d791204057 | 430 | short n = f->Out.Out[j]; |
Midimetric | 0:71d791204057 | 431 | if( f->Out.Out[j] == NAKN ) return; |
Midimetric | 0:71d791204057 | 432 | } |
Midimetric | 0:71d791204057 | 433 | led[3] = 1; |
Midimetric | 0:71d791204057 | 434 | for( short j = 0 ; j < f->Out.Out.size() ; j++ ) |
Midimetric | 0:71d791204057 | 435 | SL[port].putc( f->Out.Out[j] ); |
Midimetric | 0:71d791204057 | 436 | led[3] = 0; |
Midimetric | 0:71d791204057 | 437 | } |
Midimetric | 0:71d791204057 | 438 | f->Out.Done(); |
Midimetric | 0:71d791204057 | 439 | return; |
Midimetric | 0:71d791204057 | 440 | } |
Midimetric | 0:71d791204057 | 441 | } |
Midimetric | 0:71d791204057 | 442 | else if( f->Type == cur.Type ) |
Midimetric | 0:71d791204057 | 443 | if( ( f->Channel == NAKW ) || ( f->Channel & ( 1 << cur.Channel ) ) ) |
Midimetric | 0:71d791204057 | 444 | 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 ) ) |
Midimetric | 0:71d791204057 | 445 | 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 ) ) |
Midimetric | 0:71d791204057 | 446 | { |
Midimetric | 0:71d791204057 | 447 | for( int assign = 0 ; assign < f->Assigns.size() ; assign++ ) |
Midimetric | 0:71d791204057 | 448 | if( f->Assigns[assign]->Compute( cur, prev ) == 0 ) |
Midimetric | 0:71d791204057 | 449 | ML.Add( f->Assigns[assign]->Name, f->Assigns[assign]->Value ); |
Midimetric | 0:71d791204057 | 450 | |
Midimetric | 0:71d791204057 | 451 | for( int port = 0 ; port < 3 ; port++ ) |
Midimetric | 0:71d791204057 | 452 | if( f->Out.Compute( port, cur, prev ) == 0 ) |
Midimetric | 0:71d791204057 | 453 | { |
Midimetric | 0:71d791204057 | 454 | for( short j = 0 ; j < f->Out.Out.size() ; j++ ) // check for unrountable message |
Midimetric | 0:71d791204057 | 455 | if( f->Out.Out[j] == NAKN ) return; |
Midimetric | 0:71d791204057 | 456 | led[3] = 1; |
Midimetric | 0:71d791204057 | 457 | for( short j = 0 ; j < f->Out.Out.size() ; j++ ) |
Midimetric | 0:71d791204057 | 458 | SL[port].putc( f->Out.Out[j] ); |
Midimetric | 0:71d791204057 | 459 | led[3] = 0; |
Midimetric | 0:71d791204057 | 460 | } |
Midimetric | 0:71d791204057 | 461 | f->Out.Done(); |
Midimetric | 0:71d791204057 | 462 | return; |
Midimetric | 0:71d791204057 | 463 | } |
Midimetric | 0:71d791204057 | 464 | |
Midimetric | 0:71d791204057 | 465 | } |
Midimetric | 0:71d791204057 | 466 | } |
Midimetric | 0:71d791204057 | 467 | }; |
Midimetric | 0:71d791204057 | 468 | |
Midimetric | 0:71d791204057 | 469 | #undef NEXT |
Midimetric | 0:71d791204057 | 470 | #undef PUSH |
Midimetric | 0:71d791204057 | 471 |