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

midi

开发平台:

Visual C++

  1. function notes_relative = midiLibrary_add();
  2. % 功能:1、调用Find_PPQN(file)函数,验证格式
  3. % 是否是单声道的midi format0,读取PPQN值
  4. % 2、读取所有的音符(包括静音段)的音高、
  5. % 通道、持续时间(即deltatime的值,时钟个数)
  6. % to be continued
  7. % 读取所有的Note On和Note Off消息
  8. % 事件的deltatime作为上一个事件的持续时间
  9. % 我们默认时间都是note on和note off交替进行
  10. % 如有几个音符同时发声的情况,第二个音符开始发声时
  11. % 认为前一个音符结束,再遇到它的note off消息时
  12. % 我们将会忽略,note on时间的delta time表示如果不为0
  13. % 认为是前面有静音的地方
  14. % 知识点:参考 Borg.com+Midi+Specification.pdf  Page158 : Events In an MTrk
  15. % Page 9 - 15 : Message, Note Off, Note On
  16. % 作者:刘涛 08年9月21日 22:07
  17. % 中国传媒大学 智能信息处理实验室
  18. % 0、打开文件
  19. [file,path]=uigetfile('*.mid','please select a midi file'); 
  20. filename=strcat(path,file);
  21. % 1、验证文件格式 
  22. [tempo, time_signature, PPQN]  = Find_PPQN(filename);
  23. % 2、将所有的音符信息保存成2 by n的notes矩阵
  24. % 从MTrk之后,找到T_quarterNote和mid_clock的长度
  25. % 保存mid中的音符
  26. fid = fopen(filename);
  27. if fid == -1
  28.     error('打开文件失败');
  29. end
  30. % 读取MThd chunk 、mtrk头 和 长度
  31. temp = fread(fid,14+4+4, '*uint8');
  32. MTrk = temp(15:18);
  33. if sum(char(MTrk) == ['M'; 'T'; 'r'; 'k']) ~= 4
  34.     error('不是MTrk头');
  35. end
  36. mtrkLength = double(temp(22)) + double(temp(21))*16^2 ...
  37.     + double(temp(20))*16^4 + double(temp(19))*16^6;
  38. clear temp;
  39. % 全部读入MTrk chunk中的数据,以1个字节为单位循环分析数据
  40. % 检测note on状态位和note off状态位,并提取所有音符
  41. eventsData = fread(fid,mtrkLength,'*uint8');
  42. % 循环分析遍历event,保存其中的noteOn信息和noteOff信息,遇到非voice Message推出
  43. notes =eventsAnalyse(eventsData);
  44. % 统计notes中1/16 1/8 1/4等各种音符的个数
  45. notes_length = [];
  46. for i = 1:size(notes,1)
  47.     if notes(i,1) == -1;
  48.         continue;
  49.     else
  50.         notes_length = [notes_length notes(i,2)];
  51.     end
  52. end
  53. notes_sta = [];
  54. for i = 1:size(notes_length,2)
  55.      if isempty ( find(notes_sta == notes_length(i)) )
  56.          notes_sta = [notes_sta; notes_length(i) 1];
  57.      else
  58.          n = find(notes_sta(:,1) == notes_length(i));
  59.          notes_sta(n,2)= notes_sta(n,2) + 1;
  60.      end
  61. end
  62. % 从最短音长的音符开始找,找到一个数量较多的最短音符最为quatize的基本单位
  63. sum_of_notes = sum(notes_sta(:,2));
  64. length_descend = sort(notes_sta(:,1));
  65. base_note_length = 0;
  66. for i = 1:length(length_descend)
  67.     n = find(notes_sta(:,1) == length_descend(i));
  68.     if notes_sta(n,2) / sum_of_notes > 0.2;
  69.         base_note_length =  length_descend(i);
  70.         break;
  71.     else
  72.         continue;
  73.     end
  74. end
  75. [m,n] = min(abs([PPQN PPQN/2 PPQN/4 PPQN/8] - base_note_length));
  76. base_note_length = PPQN / 2^(n-1);
  77. % 对音符量化
  78. rest_of_lastnote = 0;
  79. notes_quantize = [];
  80. for i = 1:size(notes)
  81.     rest_of_notes = notes(i,2)-rest_of_lastnote
  82.         N = round(rest_of_notes/ base_note_length )
  83.         newnote = ones(1,N)*notes(i,1)
  84.         notes_quantize = [notes_quantize newnote]
  85.         rest_of_lastnote = rest_of_lastnote + base_note_length * N - notes(i,2)
  86. end
  87. % 将0音符的音高认为成是前一个音符的音高
  88. for i=1:length(notes_quantize)
  89.     if notes_quantize(i) == -1;
  90.         notes_quantize(i) = notes_quantize(i-1);
  91.     end
  92. end
  93. % 转为相对音高序列
  94. notes_relative = notes_quantize(2:end) - notes_quantize(1:(size(notes_quantize,2)-1));
  95. % 把文件名和相对音高序列存入库中
  96. load midLib;
  97. count = midLib{1}+1;
  98. midData = midLib{1,2};
  99. midData{count,1} = file;
  100. midData{count,2} = notes_relative;
  101. newMidLib{1,1} = count;
  102. newMidLib{1,2} = midData;
  103. midLib = newMidLib;
  104. save midLib.mat midLib;
  105. return;