Created
November 13, 2010 00:11
-
-
Save dolpen/674936 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CC=gcc | |
all:mid2mml | |
mid2mml:mid2mml.o midi.o | |
$(CC) -o $@ mid2mml.o midi.o | |
.c.o: | |
$(CC) -c $< | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<stdio.h> | |
#include"midi.h" | |
int main(int argc,char *argv[]){ | |
Midi *m; | |
int i; | |
if(argc<1){ | |
fprintf(stderr,"usage:%s file\n",argv[0]); | |
return 0; | |
} | |
m=newMidi(); | |
loadMidi(m,argv[1]); | |
//showMidi(m); | |
for(i=0;i<m->sh->tracks;i++)showTrackData(m,i); | |
terminateMidi(m); | |
return 0; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "midi.h" | |
void convEndian(char *c,int s){int i,l=--s>>1;for(i=s;i>l;i--){c[s-i]^=c[i];c[i]^=c[s-i];c[s-i]^=c[i];}} | |
Midi *newMidi(){ | |
Midi *m; | |
m=(Midi *)malloc(sizeof(Midi)); | |
m->fh=(FileHeader *)malloc(sizeof(FileHeader)); | |
m->sh=(SmfHeader *)malloc(sizeof(SmfHeader)); | |
m->th=NULL; | |
m->td=NULL; | |
return m; | |
} | |
void terminateMidi(Midi *m){ | |
int i; | |
if(m->td!=NULL){ | |
for(i=0;i<m->sh->tracks;i++)if((m->td+i)->data!=NULL)free((m->td+i)->data); | |
free(m->td); | |
} | |
if(m->th!=NULL)free(m->th); | |
if(m->sh!=NULL)free(m->sh); | |
if(m->fh!=NULL)free(m->fh); | |
free(m); | |
} | |
void loadMidi(Midi *m,char *filename){ | |
FILE *fp; | |
int i; | |
if((fp=fopen(filename,"rb"))==NULL){fprintf(stderr,"loadMidi:file open error\n");exit(0);} | |
fread(m->fh,sizeof(FileHeader),1,fp); | |
convEndian((char *)&m->fh->size,sizeof(m->fh->size)); | |
fread(m->sh,sizeof(SmfHeader),1,fp);//midiヘッダ読み込み | |
convEndian((char *)&m->sh->format,sizeof(m->sh->format)); | |
convEndian((char *)&m->sh->tracks,sizeof(m->sh->tracks)); | |
convEndian((char *)&m->sh->timebase,sizeof(m->sh->timebase)); | |
m->th=(TrackHeader *)malloc(sizeof(TrackHeader)*m->sh->tracks); | |
m->td=(TruckData *)malloc(sizeof(TruckData)*m->sh->tracks); | |
for(i=0;i<m->sh->tracks;i++){ | |
fread((m->th+i),sizeof(TrackHeader),1,fp); | |
convEndian((char *)&(m->th+i)->size,sizeof((m->th+i)->size)); | |
(m->td+i)->size=(m->th+i)->size; | |
(m->td+i)->data=(char *)malloc((m->td+i)->size); | |
fread((m->td+i)->data,(m->td+i)->size,1,fp); | |
} | |
fclose(fp); | |
} | |
void showMidi(Midi *m){ | |
int i; | |
fprintf(stderr,"[File]\n"); | |
fprintf(stderr,"checksum:%c%c%c%c\n",m->fh->chk[0],m->fh->chk[1],m->fh->chk[2],m->fh->chk[3]); | |
fprintf(stderr,"SMF header size:%d\n",m->fh->size); | |
fprintf(stderr,"[SMF]\n"); | |
fprintf(stderr,"midi - format%d\n",m->sh->format); | |
fprintf(stderr,"%dtracks\n",m->sh->tracks); | |
fprintf(stderr,"timebase : %d\n",m->sh->timebase); | |
for(i=0;i<m->sh->tracks;i++){ | |
fprintf(stderr,"[Track%d]\n",i); | |
fprintf(stderr,"checksum:%c%c%c%c\n",(m->th+i)->chk[0],(m->th+i)->chk[1],(m->th+i)->chk[2],(m->th+i)->chk[3]); | |
fprintf(stderr,"Track data size:%d\n",(m->th+i)->size); | |
} | |
} | |
void showTrackData(Midi *m,int n){ | |
char *p,*s,**rp; | |
int l,delta,count=0,time=0,flush=0,octave=DEFAULT_OCTAVE; | |
unsigned char stat,rstat; | |
rp=&p;p=s=(m->td+n)->data; | |
l=(m->td+n)->size; | |
while(p-s<l){ | |
delta=getVariableLengthParam(rp); | |
count+=delta; | |
time+=delta; | |
stat=getByte(rp); | |
//fprintf(stderr,"[%8d]@%8d(+%8d)-[%2x]",p-s,time,delta,stat); | |
switch(stat){ | |
case 0xf0: | |
flush=getExclusiveData(rp,count); | |
break; | |
case 0xff: | |
flush=getOperationData(rp,count,m->sh->timebase); | |
break; | |
default: | |
if(stat<0x80){stat=rstat;p--;} | |
flush=getCommonData(rp,count,stat,&octave,m->sh->timebase); | |
break; | |
} | |
if(flush==1)count=0; | |
rstat=stat; | |
} | |
} | |
int getConstantLengthParam(char **rp,int n){ | |
char *p=*rp; | |
int value=0; | |
while(n-->0)value=(value<<8)+(unsigned char)*p++; | |
*rp=p; | |
return value; | |
} | |
int getVariableLengthParam(char **rp){//可変長表現の取得(0x80以上で次を読む) | |
char *p=*rp; | |
int value=0,temp=0; | |
do{ | |
temp=(unsigned char)*p++; | |
value=(value<<7)+(temp&0x7F); | |
}while(temp&0x80); | |
*rp=p; | |
return value; | |
} | |
int getByte(char **rp){ | |
return 0+(unsigned char)*(*rp)++; | |
} | |
void skipBytes(char **rp,int n){ | |
*rp+=n; | |
} | |
void printString(char **rp,int n){ | |
char *p; | |
p=(char *)malloc(sizeof(char)*(n+1)); | |
strncpy(p,*rp,n); | |
p[n]=0; | |
printf(" %s ",p); | |
*rp+=n; | |
free(p); | |
} | |
int gcd(int a,int b){ | |
while(a&&b){ | |
if(a>b){ | |
a=a%b; | |
}else{ | |
b=b%a; | |
} | |
} | |
return a+b; | |
} | |
int putNoteData(int *octave,int notenum,int span,int timebase){ | |
int s=span,d=timebase*4,o=notenum/12,g; | |
while(o>*octave){printf("<");(*octave)++;} | |
while(o<*octave){printf(">");(*octave)--;} | |
while(s){ | |
g=gcd(s,d);s/=g;d/=g;s--; | |
printf("%s%d%s",NOTENAME[notenum%12],d,s?"&":""); | |
} | |
return 0; | |
} | |
int putRestData(int span,int timebase){ | |
int s=span,d=timebase*4,g; | |
while(s){ | |
g=gcd(s,d);s/=g;d/=g;s--; | |
printf("r%d",d); | |
} | |
return 0; | |
} | |
int getCommonData(char **rp,int count,int stat,int *octave,int timebase){ | |
int data1,data2; | |
switch(stat&0xf0){ | |
case 0x80: | |
data1=getByte(rp); | |
data2=getByte(rp); | |
//fprintf(stderr,"NoteOff\n"); | |
//それまでは音符だった。音を出さなくてはならない | |
putNoteData(octave,((stat&0x0f)==DRUM_CH)?DRUM_NOTE:data1,count,timebase); | |
return 1; | |
case 0x90: | |
data1=getByte(rp); | |
data2=getByte(rp); | |
if(data2>0){ | |
//fprintf(stderr,"NoteOn\n"); | |
//それまでは休符だった。休符を発行しなくてはならない | |
putRestData(count,timebase); | |
}else{ | |
//fprintf(stderr,"NoteOff\n"); | |
//それまでは音符だった。音を出さなくてはならない | |
putNoteData(octave,((stat&0x0f)==DRUM_CH)?DRUM_NOTE:data1,count,timebase); | |
} | |
return 1; | |
case 0xa0: | |
data1=getByte(rp); | |
data2=getByte(rp); | |
//fprintf(stderr,"PolyAfterKey\n"); | |
return 0; | |
case 0xb0: | |
data1=getByte(rp); | |
data2=getByte(rp); | |
if(data1==0x7e)skipBytes(rp,1); | |
//fprintf(stderr,"ControlChange\n"); | |
return 0; | |
case 0xc0: | |
data1=getByte(rp); | |
//fprintf(stderr,"ProgramChange\n"); | |
return 0; | |
case 0xd0: | |
data1=getByte(rp); | |
//fprintf(stderr,"Poly\n"); | |
return 0; | |
case 0xe0: | |
data1=getByte(rp); | |
data2=getByte(rp); | |
//fprintf(stderr,"Pitchbend\n"); | |
return 0; | |
} | |
return 0; | |
} | |
int getExclusiveData(char **rp,int count){ | |
int size; | |
size=getVariableLengthParam(rp); | |
skipBytes(rp,size); | |
//fprintf(stderr,"ExclusiveData\n"); | |
return 0; | |
} | |
int getOperationData(char **rp,int count,int timebase){ | |
int type,size,data; | |
type=getByte(rp); | |
size=getVariableLengthParam(rp); | |
switch(type){ | |
case 0x01: | |
//fprintf(stderr,"TextEvent\n"); | |
putRestData(count,timebase); | |
printString(rp,size); | |
return 1; | |
case 0x02: | |
//fprintf(stderr,"CopyRight\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x03: | |
//fprintf(stderr,"SequenceName\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x04: | |
//fprintf(stderr,"InstrumentName\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x05: | |
//fprintf(stderr,"Iyric\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x06: | |
//fprintf(stderr,"Marker\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x07: | |
//fprintf(stderr,"QueuePoint\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x08: | |
//fprintf(stderr,"ProgramName\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x09: | |
//fprintf(stderr,"DeviceName\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x20: | |
//fprintf(stderr,"ChannelSelect\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x2F: | |
//fprintf(stderr,"EndOfTrack\n"); | |
skipBytes(rp,size); | |
printf(";\n"); | |
return 0; | |
case 0x51: | |
//fprintf(stderr,"Tempo\n"); | |
putRestData(count,timebase); | |
data=getConstantLengthParam(rp,size); | |
printf("t%d",60000000/data); | |
return 1; | |
case 0x58: | |
//fprintf(stderr,"TimeSignature\n"); | |
skipBytes(rp,size); | |
return 0; | |
case 0x59: | |
//fprintf(stderr,"KeySignature\n"); | |
skipBytes(rp,size); | |
return 0; | |
default: | |
//fprintf(stderr,"OperationData\n"); | |
skipBytes(rp,size); | |
return 0; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef MIDI_H_INCLUDED | |
#define MIDI_H_INCLUDED | |
#include<stdio.h> | |
#include<stdlib.h> | |
#define DRUM_CH 9 | |
#define DRUM_NOTE 48 | |
#define DEFAULT_OCTAVE 4 | |
typedef struct _fileheader{ | |
char chk[4];//チェックサム(Mthd) | |
int size;//SMFHeaderのサイズ | |
}FileHeader; | |
typedef struct _smfheader{ | |
short format;//フォーマット(0 or 1) | |
short tracks;//トラック数 | |
short timebase;//分解能 | |
}SmfHeader; | |
typedef struct _trackheader{ | |
char chk[4];//チェックサム(MTrk) | |
int size;//トラックサイズ | |
}TrackHeader; | |
typedef struct _truckdata{ | |
char *data; | |
int size; | |
}TruckData; | |
typedef struct _midifile{ | |
FileHeader *fh; | |
SmfHeader *sh; | |
TrackHeader *th; | |
TruckData *td; | |
}Midi; | |
static char NOTENAME[][3]={"c","c+","d","d+","e","f","f+","g","g+","a","a+","b"}; | |
void convEndian(char *c,int s); | |
Midi *newMidi(); | |
void terminateMidi(Midi *m); | |
void loadMidi(Midi *m,char *filename); | |
void showMidi(Midi *m); | |
void showTrackData(Midi *m,int n); | |
int putNoteData(int *octave,int notenum,int span,int timebase); | |
int putRestData(int span,int timebase); | |
int getCommonData(char **rp,int count,int stat,int *octave,int timebase); | |
int getExclusiveData(char **rp,int count); | |
int getOperationData(char **rp,int count,int timebase); | |
int getConstantLengthParam(char **rp,int n); | |
int getVariableLengthParam(char **rp); | |
int getByte(char **rp); | |
void skipBytes(char **rp,int n); | |
void printString(char **rp,int n); | |
int gcd(int a,int b); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment