File content as of revision 0:71d791204057:
#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