Bernard Escaillas
/
MidiTee
Diff: midi.h
- Revision:
- 0:71d791204057
--- /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