eventsAnalyse.m
上传用户:abcwxk
上传日期:2016-05-20
资源大小:434k
文件大小:6k
源码类别:

midi

开发平台:

Visual C++

  1. % ------------------------------------------------------------------------------------------------
  2. function notes =eventsAnalyse(eventsData)
  3. % description
  4. %     分析events数据,找出noteOn和noteOff事件,notes存储音符的时长和音高
  5. %     从内存中的eventsData中,分析events
  6. %     分析文件中第一个noteon开始的所有events,只分析voice message
  7. %     遇到system message和meta-data  message会退出
  8. % 方法:
  9. %     1、找到第一个note on的status byte,将data1存储到notes(1,1)中,notes(1,2)=0
  10. %     2、循环分析events
  11. %     (1)delta time: 调用[value, len] = readViaLen(via)给函数传入下面4个字节的数据
  12. %                  获得变长量的value和data长度,数据指针指向下一个delta time
  13. %     (2)status byte : 
  14. %                       >0 得到状态字节: 如果是running
  15. %                       status,则状态=lastStatus,指针指向data bytes
  16. %                       >1 通过映射表找到对应于status  byte的data-bytes的长度
  17. %                             利用长度判断非voice msg情况,将error退出
  18. %                       >2 voice msg
  19. %                                 <1 存储status 到 lastStatus  
  20. %                                 <2 是note on或者note off,将音高和音长存入notes中
  21. %                      >3  从data-bytes的长度得到下一个delta-time的开始位置,
  22. %                             若到结尾退出,改变数据指针位置,循环
  23. %     (3)data bytes:无
  24. % Note:
  25. %     遇到除了voice message之外的会提示出错
  26. % 08.9.22   21:27
  27. % 0、初始化一些变量
  28.     % 1) Status Byte Of Voice Messages
  29.     noteOn = 9*16; noteOff = 8*16; afterTouch = 10*16;
  30.     controlChange = 11*16; programChange = 12*16;
  31.     channelPressure = 13*16; pitchWheel = 14*16;
  32.     system_exclusive = 240;
  33.     
  34.     meta_data = 255; tempo_meta = 81;
  35.     time_meta = 88;
  36.     noteNum = 0; % 音符号
  37.     numOfNotes = 0; % 音符个数
  38.     noteSound = 1; noteMute = 0; noteState = noteMute; % 音符类别,无声音符 & 有声音符
  39.     
  40.     bytePointer = 1; % 指针在eventsData中的位置
  41.     % 王方师哥qq教我的映射表方法
  42.     v_msg_dataBytesLength = zeros(256,1); 
  43.     v_msg_dataBytesLength(noteOn) = 2;
  44.     v_msg_dataBytesLength(noteOff) = 2;
  45.     v_msg_dataBytesLength(afterTouch) = 2;
  46.     v_msg_dataBytesLength(controlChange) = 2;
  47.     v_msg_dataBytesLength(programChange) = 1;
  48.     v_msg_dataBytesLength(channelPressure) = 1;
  49.     v_msg_dataBytesLength(pitchWheel) = 2;
  50.     % 小方  21:04:27% 就是一个数组
  51.     % 小方  21:05:03% 比如说下标是status-byte,对应定内容是date-bytes长度
  52.     % 漓江烟雨 21:05:15% 哦 
  53.     % 漓江烟雨 21:05:16% 呵呵 
  54.     % 小方  21:05:28% 这样直接通过[]访问就行了
  55.     % 2) 找到Tempo, Time Signature, PPQN / SMPTE
  56. %     放在里find_PPQN函数中
  57.     
  58. % 1、找到第一个note on message
  59. n = length(eventsData);
  60. m=0; % 第一个noteOn message的status byte位置
  61. for i = 1 : n-2
  62.     state = bitand(eventsData(i), 240); % 0xF0 240
  63.     if(state == noteOn)
  64.         if eventsData(i+2)==0
  65.             continue; % 力度为0情况,表示note off情况
  66.         else
  67.             m = i;
  68.             break;
  69.         end
  70.     end
  71. end
  72. % if m==0; % 没有找到音符情况
  73. %     return;
  74. % end
  75. noteNum = double(eventsData(m+1));
  76. notes = [noteNum 0];
  77. numOfNotes = 1;
  78. % if m+3 >n % 到结尾了
  79. %     return;
  80. % end
  81. noteState = noteSound;
  82. lastStatus = noteOn;
  83. bytePointer = m+3;
  84. % 2、逐个分析events,保存其中的noteOn和Off信息到notes
  85. for i = bytePointer : n
  86.     if i==1290
  87.         i;
  88.     end
  89.     if i ~= bytePointer
  90.         continue;
  91.     end        
  92. % a delta time: 
  93. %         调用[value, len] = readViaLen(via)给函数传入下面4个字节的数据
  94. %         获得变长量的value和data长度,数据指针指向下一个status byte
  95.     via = eventsData(i:i+3);
  96.     [value, len] = readViaLen(via)
  97.     i=i+len;
  98. % b status byte : 
  99. % b.0 得到状态字节: 检测running status,则状态=lastStatus,指针指向databytes
  100.     if bitand(128, eventsData(i)) ~= 0 % 0x80 128
  101.         % 不是 running status
  102.         status = bitand(eventsData(i), 240); % 0xF0 240
  103.         i=i+1; % 指针指向databytes
  104.     else
  105.         status = lastStatus;
  106.         i=i; % 指针指向databytes
  107.     end
  108.     
  109.     if status == meta_data;
  110.         disp('error! 是Meta-data');
  111.         return;
  112.     elseif status > system_exclusive
  113.         disp('error! 是system-exclusive Message');
  114.         return;
  115.     end
  116.     
  117. % b.1 通过映射表找到对应于status  byte的data-bytes的长度
  118. %       利用长度判断非voice msg情况,将error退出
  119.     dataBytesLength = v_msg_dataBytesLength(status);
  120.     if dataBytesLength==0
  121.         disp('error! 不是Voice Message');
  122.         return;
  123.     end
  124. % b.2 voice msg
  125. % b.2.1 存储status 到 lastStatus
  126.     lastStatus = status;
  127. % b.2.2 是note on或者note off,将音高和音长存入notes中
  128.     if status == noteOn && eventsData(i+1) ~= 0 % note On情况
  129.         if noteState == noteSound
  130.             % 保存前一个音符
  131.             deltatime = value;
  132.             notes(numOfNotes, 2) = value;
  133.             % 增加一个有声音符
  134.             noteNum = double(eventsData(i));
  135.             notes = [ notes; [noteNum 0] ];
  136.             numOfNotes = numOfNotes + 1;
  137.             % 状态
  138.             noteState == noteSound;
  139.         elseif noteState == noteMute
  140.             % 保存前一个音符
  141.             deltatime = value;
  142.             if value ~= 0 % 即前一个noteOff事件的持续时间不是0,是一个无声音符,需要保存
  143.                 notes(numOfNotes, 2) = value;
  144.                 % 增加一个有声音符
  145.                 noteNum = double(eventsData(i));
  146.                 notes = [ notes; [noteNum 0] ];
  147.                 numOfNotes = numOfNotes + 1; % 音符数+1
  148.             else % 前一个noteOff时间的持续时间是0,不是无声音符
  149.                 % 将前面定义的无声音符去掉,改成有声音符
  150.                 noteNum = eventsData(i);
  151.                 notes(numOfNotes, 1) = noteNum;
  152.                 numOfNotes = numOfNotes; % 音符数不变
  153.             end
  154.             % 状态
  155.             noteState = noteSound;
  156.         end
  157.     elseif status == noteOff | (status == noteOn && eventsData(i+1) == 0) % note Off情况
  158.         % 保存前一个音符
  159.         deltatime = value;
  160.         notes(numOfNotes, 2) = value;
  161.         % 增加一个无声音符
  162.         notes = [ notes; [-1 0] ];
  163.         numOfNotes = numOfNotes + 1;
  164.         % 状态
  165.         noteState = noteMute;
  166.     else
  167.         disp('其他的voice msg');
  168.     end
  169. % b.2.3 其他voice msg不管,从data-bytes的长度得到下一个delta-time的开始位置,
  170. %             若到结尾退出,改变数据指针位置,循环
  171.     i = i+dataBytesLength;
  172.     if i >n
  173.         return;
  174.     end
  175.     bytePointer = i;
  176. end
  177. return;