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(¬e,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(¬e,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(¬e,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); }