mbedでmidi(Format 0)を再生

midi.cpp

Committer:
Naoto_111
Date:
2014-07-15
Revision:
0:7c17c3b3a8d7
Child:
1:250e7251f8fc

File content as of revision 0:7c17c3b3a8d7:

#include "mbed.h"
#include "midi.h"
#define STEP 8
Serial pc(USBTX,USBRX);//tx,rx
midi::midi(PinName _bzr):bzr(_bzr)
{
    //frequency of equal temperament(octave:4)
    freq[0]=261.626;//C(do)
    freq[1]=277.183;//C#
    freq[2]=293.665;//D
    freq[3]=311.127;//D#
    freq[4]=329.628;//E
    freq[5]=349.228;//F
    freq[6]=369.994;//F#
    freq[7]=391.995;//G
    freq[8]=415.305;//G#
    freq[9]=440.000;//A
    freq[10]=466.164;//A#
    freq[11]=493.883;//B

    table=new float[STEP];
    for(int i=0; i<STEP; i++)table[i]=sin(i/(STEP/8.0)*atan(1.0));
    


}
/*
midi::~midi(){
    delete(cache);
}
*/
template<class X>
void midi::change_endian(X *raw,int byte)
{
    X tmp=0;
    for(int i=0; i<byte; i++)for(int j=0; j<8; j++)tmp+=((*raw&(1<<((byte-i-1)*8+j)))>>((byte-i-1)*8+j))<<(i*8+j);
    *raw=tmp;
}

void midi::read(const char *path)
{

    FILE *mid,*cache;
    short int pbend;
    long int dtime,len;
    int time,ch;
    float frequency[16];
    char note,ctrl,value,prgm,prsr;
    unsigned char tmp2[64];
    char vel;
    unsigned char tmp;
    char prev;
    time=tmp=prev=tempo=chmax=0;

    if((mid = fopen(path, "rb")) == NULL)goto end1;














    fseek(mid, 10, SEEK_SET);
    fread(&tracks,2,1,mid);
    //fseek(mid, 2, SEEK_CUR);
    fread(&crochet,2,1,mid);

    change_endian(&tracks,2);
    change_endian(&crochet,2);





    fseek(mid, 4, SEEK_CUR);
    fread(&len,4,1,mid);
    change_endian(&len,4);
    while(1) {
        //fseek(mid, 1, SEEK_CUR);
        fread(&tmp,1,1,mid);

        dtime=0;
        int i;
        for(i=0; i<4; i++) {
            int flag= (tmp&128)==0 ? 1:0;
            
            if(tmp&128)tmp2[i]=tmp-0x80;
            else tmp2[i]=tmp;
            if(flag)break;
            //fseek(mid, 1, SEEK_CUR);
            fread(&tmp,1,1,mid);
        }
        for(int j=0; j<=i; j++)dtime+=((long int)tmp2[j]<<(7*(i-j)));
        time+=(int)tempo*((float)dtime/crochet);
   

        //fseek(mid, 1, SEEK_CUR);
        fread(&tmp,1,1,mid);
//pc.printf("%d %d\r\n",time,tm.size()*4*1+fq.size()*4*1+ca.size());
if(tm.size()>640){
    pc.printf("Memory shortage!\r\n");
    goto end1;
    
}
        if(tmp==0xF0) {
            len=0;
            i=0;
            fread(&tmp,1,1,mid);

            for(i=0; i<4; i++) {
                int flag= (tmp&128)==0 ? 1:0;
                
                tmp2[i]=((tmp<<1)>>1);
                if(flag)break;
                //fseek(mid, 1, SEEK_CUR);
                fread(&tmp,1,1,mid);

            }

            for(int j=i; j>=0; j--)len+=((long int)tmp2[j]<<(7*j));

            fseek(mid, len, SEEK_CUR);

        } else if(tmp==0xF7) {
            len=0;
            i=0;
            fread(&tmp,1,1,mid);
            for(i=0; i<4; i++) {
                int flag= (tmp&128)==0 ? 1:0;
                tmp2[i]=((tmp<<1)>>1);
                if(flag)break;
                //fseek(mid, 1, SEEK_CUR);
                fread(&tmp,1,1,mid);
            }
            for(int j=i; j>=0; j--)len+=((long int)tmp2[j]<<(7*j));
            fseek(mid, len, SEEK_CUR);
        } else if(tmp==0xFF) {
            //fseek(mid, 1, SEEK_CUR);
            fread(&tmp,1,1,mid);
            switch(tmp) {
                case 0x00:
                case 0x59:
                    fseek(mid, 3, SEEK_CUR);
                    break;

                case 0x20:
                case 0x21:
                    fseek(mid, 2, SEEK_CUR);
                    break;

                case 0x54:
                    fseek(mid, 6, SEEK_CUR);
                    break;

                case 0x2F://End of Track

                    goto end1;
                    break;

                case 0x51://Tempo
                    fseek(mid, 1, SEEK_CUR);
                    fread(&tempo,3,1,mid);
                    change_endian(&tempo,3);
                    //pc.printf("tempo=%x\r\n",tempo);
                    break;

                case 0x58://Time Signature
                    fseek(mid, 5, SEEK_CUR);
                    break;

                    /*case 0x59://Key Signature

                        break;
                    */
                case 0x01:
                case 0x02:
                case 0x03:
                case 0x04:
                case 0x05:
                case 0x06:
                case 0x07:
                case 0x08:
                case 0x09:
                case 0x7F:
                    len=0;
                    i=0;
                    fread(&tmp,1,1,mid);

                    for(i=0; i<4; i++) {
                        int flag= (tmp&128)==0 ? 1:0;
                        tmp2[i]=((tmp<<1)>>1);
                        if(flag)break;
                        //fseek(mid, 1, SEEK_CUR);
                        fread(&tmp,1,1,mid);

                    }

                    for(int j=i; j>=0; j--)len+=((unsigned long int)tmp2[j]<<(7*j));

                    fseek(mid, len, SEEK_CUR);

                    break;

                default:
                    break;
            }
        } else {


            //fseek(mid, 1, SEEK_CUR);
            //fread(&tmp,1,1,mid);

MIDIEVENT:
            if(0x80<=tmp&&tmp<=0xEF)prev=tmp;
            if(0x80<=tmp&&tmp<=0x8F) { //note off
                ch=tmp-0x80;
                if(chmax<ch)chmax=ch;
                //fseek(mid, 1, SEEK_CUR);
                fread(&note,1,1,mid);
                fseek(mid, 1, SEEK_CUR);

                tm.push_back(time);
                //ev.push_back(109);
                ca.push_back(ch);
                fq.push_back(0);
                //vo.push_back(0);
            } else if(0x90<=tmp&&tmp<=0x9F) { //note on
                ch=tmp-0x90;
                //fseek(mid, 1, SEEK_CUR);
                fread(&note,1,1,mid);
                frequency[ch]=freq[note%12]*pow(2.0,(note/12-5.0));

                //fseek(mid, 1, SEEK_CUR);
                fread(&vel,1,1,mid);


                tm.push_back(time);
                //ev.push_back(109);
                ca.push_back(ch);
                fq.push_back(frequency[ch]);
                //vo.push_back(vel/127.0);
            }

            else if(0xA0<=tmp&&tmp<=0xAF) { //polyphonic key pressure
                ch=tmp-0xA0;
                //fseek(mid, 1, SEEK_CUR);
                fread(&note,1,1,mid);

                //fseek(mid, 1, SEEK_CUR);
                fread(&vel,1,1,mid);
            } else if(0xB0<=tmp&&tmp<=0xBF) { //control change
                ch=tmp-0xB0;
                //fseek(mid, 1, SEEK_CUR);
                fread(&ctrl,1,1,mid);

                //fseek(mid, 1, SEEK_CUR);
                fread(&value,1,1,mid);
            } else if(0xC0<=tmp&&tmp<=0xCF) { //program change
                ch=tmp-0xC0;
                //fseek(mid, 1, SEEK_CUR);
                fread(&prgm,1,1,mid);
            } else if(0xD0<=tmp&&tmp<=0xDF) { //channel pressure
                ch=tmp-0x90;
                //fseek(mid, 1, SEEK_CUR);
                fread(&prsr,1,1,mid);
            } else if(0xE0<=tmp&&tmp<=0xEF) { //pitch bend
                ch=tmp-0xE0;
                //fseek(mid, 1, SEEK_CUR);
                fread(&pbend,2,1,mid);
            } else { //running status
                tmp=prev;
                fseek(mid, -1, SEEK_CUR);
                pc.printf(" ->%x\r\n",tmp);
                goto MIDIEVENT;
            }
        }
    }
end1:
    fclose(mid);

    pc.printf("Loading complete.\r\n");
}




void midi::play()
{

    //FILE *fp;
    AnalogOut buzzer(bzr);
    int time, /*event, */ch;
    float *frequency/*,tmp,tmp2,vel[16]*/;
    //if((fp = fopen(path, "r")) == NULL)goto end;
    //if(fscanf(fp,"%d\n",&tracks)==EOF)goto end;
    frequency=new float[chmax+1];
    for(int i=0; i<=chmax; i++)frequency[i]=0;
    
/*
    if(!tm.empty())goto end;


    pi=tm.begin();
    time=*pi;
    tm.pop_front();

    pi=ev.begin();
    event=*pi;
    ev.pop_front();

    pi=ca.begin();
    ch=*pi;
    ca.pop_front();

    pd=fq.begin();
    frequency[ch]=*pd;
    fq.pop_front();

    pd=vo.begin();
    vel[ch]=*pd;
    vo.pop_front();
*/

    t.reset();
    t.start();
    time=0;
    while(1) {
//static int count=0;
//pc.printf("%d\r\n",count++);
        int now=t.read_us();
        while(1) {
            if(time<=now) {
                
                if(tm.empty())return;
                
                pi=tm.begin();
                time=*pi;
                if(time>=now)break;
                tm.pop_front();
/*
                pi=ev.begin();
                event=*pi;
                ev.pop_front();
*/
                pch=ca.begin();
                ch=*pch;
                ca.pop_front();
                


                pf=fq.begin();
                frequency[ch]=*pf;
                fq.pop_front();
                /*
                pd=vo.begin();
                vel[ch]=*pd;
                vo.pop_front();
                */
                //pc.printf("%d %d %d %lf %lf\r\n",time,event,ch,frequency[ch],vel[ch]);
            } else break;
        }
        float voltage=0;
        for(int i=0; i<=chmax; i++)voltage+=/*vel[i]*/(0.5/(chmax+1))*table[(int)(STEP*frequency[i]*now/1000000)%STEP];
        //for(int i=0;i<tracks;i++)voltage+=(0.5/tracks)*sin(2*pi*frequency[i]*now/1000000);
        buzzer=0.5+voltage;
        
    }
//end:
    //fclose(fp);
}