Dependencies:   mbed

midi.h

Committer:
Midimetric
Date:
2011-06-07
Revision:
0:71d791204057

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