Skip to content

Instantly share code, notes, and snippets.

@dolpen
Created November 13, 2010 00:11
Show Gist options
  • Save dolpen/674936 to your computer and use it in GitHub Desktop.
Save dolpen/674936 to your computer and use it in GitHub Desktop.
CC=gcc
all:mid2mml
mid2mml:mid2mml.o midi.o
$(CC) -o $@ mid2mml.o midi.o
.c.o:
$(CC) -c $<
#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;
}
#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;
}
}
#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