mbedでmidi(Format 0)を再生

Revision:
1:250e7251f8fc
Parent:
0:7c17c3b3a8d7
--- a/midi.cpp	Tue Jul 15 09:45:03 2014 +0000
+++ b/midi.cpp	Sat Aug 09 09:29:31 2014 +0000
@@ -1,6 +1,6 @@
 #include "mbed.h"
 #include "midi.h"
-#define STEP 8
+#define STEP 20
 Serial pc(USBTX,USBRX);//tx,rx
 midi::midi(PinName _bzr):bzr(_bzr)
 {
@@ -18,9 +18,10 @@
     freq[10]=466.164;//A#
     freq[11]=493.883;//B
 
-    table=new float[STEP];
+    //sine
+    table=new double[STEP];
     for(int i=0; i<STEP; i++)table[i]=sin(i/(STEP/8.0)*atan(1.0));
-    
+
 
 
 }
@@ -29,6 +30,7 @@
     delete(cache);
 }
 */
+
 template<class X>
 void midi::change_endian(X *raw,int byte)
 {
@@ -37,6 +39,14 @@
     *raw=tmp;
 }
 
+int midi::powi(int a)
+{
+    int tmp=1;
+    for(int i=0; i<a; i++)tmp=tmp<<1;
+    return tmp;
+}
+
+
 void midi::read(const char *path)
 {
 
@@ -45,31 +55,16 @@
     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;
+    char note,ctrl,value,prgm,prsr,vel,prev;
+    unsigned char tmp,tmp2[64];
+
     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);
@@ -83,32 +78,29 @@
     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(tm.size()>640) {
+            pc.printf("Memory shortage!\r\n");
+            goto end1;
+
+        }
         if(tmp==0xF0) {
             len=0;
             i=0;
@@ -116,10 +108,9 @@
 
             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);
 
             }
@@ -136,13 +127,11 @@
                 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:
@@ -197,7 +186,6 @@
                         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);
 
                     }
@@ -222,7 +210,6 @@
             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);
 
@@ -233,11 +220,9 @@
                 //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);
 
 
@@ -250,29 +235,22 @@
 
             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;
@@ -291,7 +269,7 @@
 
 
 
-void midi::play()
+void midi::play(/*int repeat*/)
 {
 
     //FILE *fp;
@@ -302,31 +280,31 @@
     //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;
+
+    /*
+        if(!tm.empty())goto end;
 
 
-    pi=tm.begin();
-    time=*pi;
-    tm.pop_front();
+        pi=tm.begin();
+        time=*pi;
+        tm.pop_front();
 
-    pi=ev.begin();
-    event=*pi;
-    ev.pop_front();
+        pi=ev.begin();
+        event=*pi;
+        ev.pop_front();
 
-    pi=ca.begin();
-    ch=*pi;
-    ca.pop_front();
+        pi=ca.begin();
+        ch=*pi;
+        ca.pop_front();
 
-    pd=fq.begin();
-    frequency[ch]=*pd;
-    fq.pop_front();
+        pd=fq.begin();
+        frequency[ch]=*pd;
+        fq.pop_front();
 
-    pd=vo.begin();
-    vel[ch]=*pd;
-    vo.pop_front();
-*/
+        pd=vo.begin();
+        vel[ch]=*pd;
+        vo.pop_front();
+    */
 
     t.reset();
     t.start();
@@ -337,22 +315,22 @@
         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();
-*/
+                /*
+                                pi=ev.begin();
+                                event=*pi;
+                                ev.pop_front();
+                */
                 pch=ca.begin();
                 ch=*pch;
                 ca.pop_front();
-                
+
 
 
                 pf=fq.begin();
@@ -370,8 +348,227 @@
         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);
+}
+
+
+
+
+void midi::play_realtime(const char *path/*, int repeat*/)
+{
+    FILE *mid;
+    short int pbend;
+    long int dtime,len,time,ch;
+    char note,ctrl,value,prgm,prsr,vel,prev;
+    unsigned char tmp,tmp2[64];
+    AnalogOut buzzer(bzr);
+
+    time=tmp=prev=tempo=chmax=0;
+
+    if((mid = fopen(path, "rb")) == NULL)return;
+
+    fseek(mid, 10, SEEK_SET);
+    fread(&tracks,2,1,mid);
+    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);
+    t.reset();
+    t.start();
+    while(1) {
+        fread(&tmp,1,1,mid);
+
+//delta time
+        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;
+            fread(&tmp,1,1,mid);
+        }
+        for(int j=0; j<=i; j++)dtime+=((long int)tmp2[j]<<(7*(i-j)));
+        time+=(int)tempo*((double)dtime/crochet);
+
+
+        while(t.read_us()<time) {
+            double voltage=0;
+            for(list<int>::iterator i =no.begin(); i!=no.end(); i++)voltage+=/*vel[i]*/(0.5/4)*table[(int)(STEP*  (freq[*i%12]*powi(*i/12-5))  *t.read_us()/1000000)%STEP];
+            buzzer=0.5+voltage;
+        }
+
+//event
+        fread(&tmp,1,1,mid);
+
+        //meta event
+        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;
+                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;
+                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) {
+            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 end2;
+                    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;
+                        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 {//midi event
+
+
+            //fseek(mid, 1, SEEK_CUR);
+            //fread(&tmp,1,1,mid);
+
+MIDIEVENT:
+            if(0x80<=tmp&&tmp<=0xEF)prev=tmp;//running status
+            if(0x80<=tmp&&tmp<=0x8F) { //note off
+                ch=tmp-0x80;
+                fread(&note,1,1,mid);
+                fseek(mid, 1, SEEK_CUR);
+                //if(ch)break;
+                list<int>::iterator i =no.begin();
+                for(; i!=no.end(); i++)if(*i==note)break;
+                no.erase(i);
+            } else if(0x90<=tmp&&tmp<=0x9F) { //note on
+                ch=tmp-0x90;
+                fread(&note,1,1,mid);
+
+                fread(&vel,1,1,mid);
+                //if(ch)break;
+                if(vel==0) {
+                    fread(&note,1,1,mid);
+                    fseek(mid, 1, SEEK_CUR);
+                    list<int>::iterator i =no.begin();
+                    for(; i!=no.end(); i++)if(*i==note)break;
+                    no.erase(i);
+
+                } else no.push_back(note);
+            }
+
+            else if(0xA0<=tmp&&tmp<=0xAF) { //polyphonic key pressure
+                ch=tmp-0xA0;
+                fread(&note,1,1,mid);
+                fread(&vel,1,1,mid);
+            } else if(0xB0<=tmp&&tmp<=0xBF) { //control change
+                ch=tmp-0xB0;
+                fread(&ctrl,1,1,mid);
+                fread(&value,1,1,mid);
+            } else if(0xC0<=tmp&&tmp<=0xCF) { //program change
+                ch=tmp-0xC0;
+                fread(&prgm,1,1,mid);
+            } else if(0xD0<=tmp&&tmp<=0xDF) { //channel pressure
+                ch=tmp-0x90;
+                fread(&prsr,1,1,mid);
+            } else if(0xE0<=tmp&&tmp<=0xEF) { //pitch bend
+                ch=tmp-0xE0;
+                fread(&pbend,2,1,mid);
+            } else { //running status
+                tmp=prev;
+                fseek(mid, -1, SEEK_CUR);
+                pc.printf(" ->%x\r\n",tmp);
+                goto MIDIEVENT;
+            }
+        }
+
+
+
+    }
+
+end2:
+    fclose(mid);
 }
\ No newline at end of file