证券公司有校园招聘吗:MIDI文件结构分析及生成方法
来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 02:13:32
MIDI文件结构分析及生成方法
(2006-03-17 23:30:39)转载 分类: H.264技术 从网上找的,已经将用BC写的改成了VC的,由于对音乐的理解比乐盲还差,对于程序中转换是否有问题我也不得而知,反正用VC生成的MIDI文件听起来惨不忍睹。对于制作MIDI音乐来说,比播放MIDI文件本身更复杂得多。我们得了解一些乐理常识和MIDI文件结构。
一、MIDI文件结构分析 MIDI文件包含首部块(Header Chunk)和音轨块(Track Chunk)两部分。其格式一般如下:
MThd <数据长度>
.......
Mtrk <数据长度>
以下为MIDI文件生成的全部源程序,经Borland c++3.1编译、连接通过。
#include
#include
#include
#include
#define C1 60 //C调1的键名值
#define FOURPAINUM 64 //1/4音符计数
#define MIDICLOCK 24 //每1/64音符的MIDICLOCK数
#define JumpNullChar(x) \ //跳过空字符
{ \
while(*x==' ' \
||*x=='\t' \
||*x=='\n' \
||*x=='|') \
x++; \
};
enum ERRORCODE{ //处理错误信息
ChangeOK, //转换成功
TextFileNotOpen, //文本文件不能打开
MidiFileCanNotCreate, //指定的MIDI文件不能建立
TextFileToBig, //文本文件太大
MallocError, //内存分配错误
InvalideChar, //在文本文件中出现了非法字符
NotFoundTrack, //没有找到指定的磁道信息
NotMIDITextFile, //文本文件不是MIDI文本文件
};
void SWAP(char *x,char *y) //两数据交换
{ char i;
i=*x;
*x=*y;
*y=i;
}
union LENGHT
{ long length;
char b[4];
} ;
struct MH { //MIDI文件头
char MidiId[4]; //MIDI文件标志MThd
long length; //头部信息长度
int format; //存放的格式
int ntracks; //磁道数目
int PerPaiNum; //每节计算器值
};
struct TH //音轨头
{ char TrackId[4]; //磁道标志MTrk
long length; //信息长度
} ;
class MIDI
{
public:
char ErrorMsg[100]; //错误信息
private:
unsigned char *TextFileBuf,
*TextFileOldBuf;
unsigned char *MidiFileBuf,
*MidiFileOldBuf;
char OneVal; //某调时,1的健值
char PaiNum; //第一小节节拍总数
char OnePaiToneNum; //用几分音符作为一基本拍
public:
//将符全MIDI书定格式的文本文件生成MIDI文件
int ChangeTextToMidi(char *TextFileName,
char *MidiFileName);
char *GetErrorMsg() //获取错误信息
{ return(ErrorMsg);}
private:
char GetCurPaiSpeed(int n); //取当前拍的按下强度
void WriteSoundSize(char ntrack,unsigned int );
void SetOnePaiToneNum(int n)
{ OnePaiToneNum=n; };
void SetOneval_r(char *m) ; //取m大调或小调时,1的实际键值
char GetToneNum(char c, //取记名对应的键值
char flag) ;
void WriteMHToFile(long length, //建立MIDI文件头
int format,
int ntracks,
int PerPaiNum,
FILE *fp);
void WriteTHToFile(long lenght,
FILE *fp); //建立MIDI磁道头
void WriteTrackMsgToFile(FILE *fp);
//将磁道音乐信息定入文件中
void WriteSpeed(int speed);
void SetPaiNum(int n)
{ PaiNum=n;}
long NewLong(long n); //新的long值
int NewInt(int n) //新的int值
{ return(n<<8|n>>8);}
//将n改为可变长度,内入buf处
void WriteLenghtToBuf(unsigned long n,
char *buf);
void ChangePrommgram(char channel, //设置音色
char promgram);
void NoteOn (char n, //演奏乐音
char speed,
unsigned long delaytime);
void WriteNoteOn(char,char,char ,unsigned long) ;
void WriteTextMsg(char *msg); //定一串文本信息
void WriteTimeSignature(char n, //设置时间信息
char d);
void WriteTrackEndMsg(); //设置磁道结束信息
/* 作用:将符合MIDI文本文件的text文件转换成MIDI */
/* 文件. */
/* 入口参数:TextFileName 文本文件名 */
/* MidiFileName MIDI文件名 */
/* 出口参数:见 ERRORCODE 说明 */
/*************************************************/
int MIDI::ChangeTextToMidi(char *TextFileName,
char *MidiFileName)
{ int tracks,ntrack,delaytime;
int speed,IsFirst,nn,dd;
unsigned char buf[80],*msgbuf,c;
FILE *TextFp,*MidiFp;
long FileSize;
char SpeedVal;
TextFp=fopen(TextFileName,"r");
if (TextFp==NULL)
{sprintf(ErrorMsg,
"文本文件[%s]不能打开。\n",TextFileName);
return(TextFileNotOpen);
}
fseek(TextFp,0,SEEK_END); /*测试文件大小*/
FileSize=ftell(TextFp);
TextFileBuf=(char *)malloc(FileSize);/*为文件分配内存*/
if (TextFileBuf==NULL)
{ sprintf(ErrorMsg,
"文本文件[%s]太大,没有足够的内存处理。\n",
TextFileName);
fclose(TextFp);
return(TextFileToBig);
}
memset(TextFileBuf,0,FileSize);
MidiFileBuf=(char *) malloc(FileSize*4);
if ( MidiFileBuf==NULL)
{ sprintf(ErrorMsg,"不能为MIDI文件分配内存。\n");
fclose(TextFp);
free(TextFileBuf);
return(MallocError);
}
MidiFp=fopen(MidiFileName,"wb");
if (MidiFp==NULL)
{ sprintf(ErrorMsg,
"Midi文件[%s]不能建立。\n",MidiFileName);
fclose(TextFp);
free(MidiFileBuf);
free(TextFileBuf);
return(MidiFileCanNotCreate);
}
MidiFileOldBuf=MidiFileBuf;
TextFileOldBuf=TextFileBuf;
fseek(TextFp,0,SEEK_SET);
fread(TextFileBuf,FileSize,1,TextFp);
fclose(TextFp);
JumpNullChar(TextFileBuf);
c=strnicmp(TextFileBuf,"[MIDI]",6);
if (c)
{sprintf(ErrorMsg,
"文本文件[%s]不是MIDI文本文件。\n",MidiFileName);
fcloseall();
free(TextFileOldBuf);
free(MidiFileOldBuf);
return(NotMIDITextFile);
}
TextFileBuf+=6;
JumpNullChar(TextFileBuf);
sscanf(TextFileBuf,"%c,%d/%d,%d,%d", //取调号等信息
&c,&nn,&dd,&speed,&tracks);
buf[0]=c;buf[1]=0; SetOneval_r(buf); //设置该调1的键值
if (nn<1 || nn> 7) nn=4;
if (dd<2 || dd>16) dd=4;
while(*TextFileBuf!='\n') TextFileBuf++;
JumpNullChar(TextFileBuf);
if (speed<60 || speed >200) speed=120;
JumpNullChar(TextFileBuf);
if (tracks<1 || tracks>16) tracks=1;
JumpNullChar(TextFileBuf);
ntrack=1;
WriteMHToFile(6,1,tracks,speed,MidiFp);
WriteTimeSignature(nn,dd); //设置时间记录格式
SetPaiNum(nn);
WriteSpeed(speed); //设置演奏速度
while(ntrack<=tracks && *TextFileBuf!=0)
{sprintf(buf,"[%d]",ntrack);
TextFileBuf=strstr(TextFileBuf,buf);//查找该磁道起始位置
if (TextFileBuf==NULL) //没有找到
{ sprintf(ErrorMsg,
"在文件[%s]中,第%d磁道音乐信息没找到。\n.",
TextFileName,ntrack);
free(MidiFileOldBuf);
free(TextFileOldBuf);
fcloseall();
return(NotFoundTrack);
}
if (ntrack!=1) MidiFileBuf=MidiFileOldBuf;
SpeedVal=0;
TextFileBuf+=strlen(buf);
IsFirst=1;
while(*TextFileBuf!=0 && *TextFileBuf!='[')
{ JumpNullChar(TextFileBuf);
c=*(TextFileBuf++);
if ( (c>=?' && c<=?')
|| (c>='a' && c<='g')
|| (c>='A' && c<='G')
)
{JumpNullChar(TextFileBuf);
if (*TextFileBuf=='b' || *TextFileBuf=='#')
{ c=GetToneNum(c,*TextFileBuf);/*取出实际的音符*/
TextFileBuf++;
JumpNullChar(TextFileBuf);
}
else c=GetToneNum(c,' ');
switch(*(TextFileBuf++))
{ case '-': //延长一拍
delaytime=2*FOURPAINUM;
JumpNullChar(TextFileBuf);
while(*TextFileBuf=='-')
{ TextFileBuf++;
delaytime+=FOURPAINUM;
JumpNullChar(TextFileBuf);
}
break;
case '_': //8分音符
delaytime=FOURPAINUM/2;
JumpNullChar(TextFileBuf);
if(*TextFileBuf=='.')
{TextFileBuf++;
delaytime=delaytime*3/2;
}
break;
case '=': //16分音符
delaytime=FOURPAINUM/4;
JumpNullChar(TextFileBuf);
if(*TextFileBuf=='.')
{delaytime=delaytime*3/2;
TextFileBuf++;}
break;
case '.': //附点音符
delaytime=FOURPAINUM*3/2;
break;
case ':': //32分音符
delaytime=FOURPAINUM/16;
JumpNullChar(TextFileBuf);
if(*TextFileBuf=='.')
{delaytime=delaytime*3/2;
TextFileBuf++;}
break;
case '': //64分音符
delaytime=FOURPAINUM/32;
if(*TextFileBuf=='.')
{ delaytime=delaytime*3/2;
TextFileBuf++;}
break;
default:
delaytime=FOURPAINUM;
TextFileBuf--;
break;
} 原文: http://blog.sina.com.cn/s/blog_465bdf0b010002sy.html
MIDI文件结构分析及生成方法
当代中国社会结构及利益集团分析
砼结构开裂原因分析及预防
生成注册表文件
Heritrix源码分析(六) Heritrix的文件结构分析 - 真人假天下 - Jav...
鼻窦炎的生成原因及对症治疗方法
DLL文件基本原理及修改方法
企业现金流及分析方法
我国上市公司发展规模、结构及经营业绩分析
何新:关于当代中国的社会结构及利益集团分析
AA通达信文件结构
apk的文件结构
教育结构不合理 部分大学生成“白菜”
数字证书生成方法
庄家操盘技巧 及分析方法(1)
校园网常见故障现象、分析及排除方法
财务报表分析方法及评价指标,
庄家操盘技巧及分析方法
庄家操盘技巧 及分析方法
变电所常见故障的分析及处理方法
批处理恢复隐藏文件夹及文件的方法
用DiskGenius恢复分区及文件的方法
各种顽固文件及文件夹的删除方法
常用知识扫盲-- 什么叫APK文件及安装方法