Find_PPQN.m
资源名称:10_11.rar [点击查看]
上传用户:abcwxk
上传日期:2016-05-20
资源大小:434k
文件大小:4k
源码类别:
midi
开发平台:
Visual C++
- function [tempo, time_signature, PPQN] = Find_PPQN(file);
- % 验证文件格式是否是midi,是否是format0,提取MThd头中的Division
- % 形参:mid文件名,这里使用的mid文件必须是format0,会有验证部分的代码
- % 返回值:PPQN(Pulses Per Quarter Note)每1/4音符所含的时钟数
- % delta-time的单位就是clock(Pulse)
- %
- % 知识点:参考 Borg.com+Midi+Specification.pdf Page151 : MThd chunk
- % MThd chunk在C中的定义:
- % struct MTHD_CHUNK
- % {
- % /* Here's the 8 byte header that all chunks must have */
- % char ID[4]; /* This will be 'M','T','h','d' */
- % unsigned long Length; /* This will be 6 */
- % /* Here are the 6 bytes */
- % unsigned short Format; /*只有0、1、2三种*/
- % unsigned short NumTracks; /*Track的个数*/
- % unsigned short Division; /*PPQN*/
- % };
- %
- % Division表示每个1/4音符是多少个midi clocks,
- % 即PPQN(Pulses ie clocks Per Quarter Note),
- % delta-time的单位是1个clock。
- %
- % Division第一字节如果为负,-24, -25, -29, or -30
- % 对应于4种SMPTE的标准,每秒多少帧。
- % 第二字节就表示每帧的精度,分成多少子帧。
- % 作者:刘涛 08年9月19日 15:37
- % 中国传媒大学 智能信息处理实验室
- % 1、文件格式验证 MThd chunk验证
- % (1)打开文件
- fid = fopen(file);
- if fid == -1
- error('打开文件失败');
- end
- % (2)读取MThd chunk中的数据
- MThd_Chunk = fread(fid, 12, '*uint8');
- % (3)验证MThd chunk中的前面12个字节数据
- % 是不是'M' 'T' 'h' 'd' 0 0 0 6,验证是不是fomat 0,只有1个track
- if sum(MThd_Chunk(1:12) - uint8([77;84;104;100;0;0;0;6;0;0;0;1]))...
- ~= 0
- error('这不是midi文件');
- end
- % 2、读取Division并判断PPQN
- Division = fread(fid, 2, '*uint8');
- SMPTE = 0; % 每秒多少帧,当division的data1为负的时候
- % data1表示SMPTE,只有4个值
- % -24,-25,-29 or -30
- PPQN = 0; % 每四分音符有几个clock
- deltatime = 0; % 1个clock的时间,单位是毫秒
- if Division(1) >127
- switch Division(1)
- case 232, % E8 -24
- SMPTE = 24;
- case 231, % E7 -25
- SMPTE = 25;
- case 227, % E3 -29
- SMPTE = 29;
- case 226, % E2 -30
- SMPTE = 30;
- otherwise
- error('Division第一字节为负,但不属于-24-25-29-30这四种SMPTE标准格式');
- end
- deltatime = 1000 / SMPTE / Division(2);
- error('没有找到PPQN,找到了SMPTE')
- else
- PPQN = double(Division(1))*256 + double(Division(2));
- end
- % 3、遍历events data,寻找tempo和time sigature
- % 读取MThd chunk 、mtrk头 和 长度
- temp = fread(fid,4+4, '*uint8');
- MTrk = temp(1:4);
- if sum(char(MTrk) == ['M'; 'T'; 'r'; 'k']) ~= 4
- error('不是MTrk头');
- end
- mtrkLength = double(temp(8)) + double(temp(7))*16^2 ...
- + double(temp(6))*16^4 + double(temp(5))*16^6;
- % 全部读入MTrk chunk中的数据,以1个字节为单位循环分析数据
- eventsData = fread(fid,mtrkLength,'*uint8');
- fclose(fid);
- meta_data = 255; tempo_meta = 81;
- time_meta = 88;
- tempo = 500000; time_signature = [4 4];
- tempo_change = false; time_change = false;
- for i = 1:length(eventsData)
- if eventsData(i) == meta_data
- switch eventsData(i+1)
- case tempo_meta, % Tempo
- if tempo_change
- disp('tempo被改了');
- else
- tempo_change = true;
- end
- tempo = double(eventsData(i+3))*16^4 + ...
- double(eventsData(i+4))*16^2 + ...
- double(eventsData(i+5));
- case time_meta, % Time Signature
- if time_change
- disp('time signature被改了');
- else
- time_change = true;
- end
- time_signature(1) = double(eventsData(i+3));
- time_signature(2) = double(2^double(eventsData(i+4)));
- end
- end
- end
- return;