mbedでmidi(Format 0)を再生

Revision:
0:7c17c3b3a8d7
Child:
1:250e7251f8fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/midi.cpp	Tue Jul 15 09:45:03 2014 +0000
@@ -0,0 +1,377 @@
+#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);
+}
\ No newline at end of file