1
0

midiinfo.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include "main.h"
  2. #include <intsafe.h>
  3. #define _RIFF 'FFIR'
  4. #define _MThd 'dhTM'
  5. #define _MTrk 'krTM'
  6. #define _RMID 'DIMR'
  7. #define _data 'atad'
  8. //#define BLAH
  9. static cfg_int cfg_loop_ctrl("cfg_loop_ctrl",255),cfg_loop_meta("cfg_loop_meta",255);
  10. class CGetInfo
  11. {
  12. public:
  13. MIDI_file * mf;
  14. int loop;
  15. int nch;
  16. int got_notes;
  17. int cur_track_start;
  18. int c_track,s_track;
  19. bool is_blah,f2;
  20. int max_ff_track,max_ff_num;
  21. CTempoMap *tmap,*ttmap;
  22. CSysexMap *smap;
  23. void CleanTempo();
  24. int DoTrack(const BYTE* track,size_t size,string& name,int);
  25. bool Run(MIDI_file* mf);
  26. };
  27. static bool memicmp(char* b1,char* b2,int s)
  28. {
  29. for(int n = 0; n < s; n++)
  30. {
  31. if (tolower(b1[n]) != tolower(b2[n]))
  32. return 1;
  33. }
  34. return 0;
  35. }
  36. static bool is_kar(char* ptr,int siz) //hack
  37. {
  38. siz -= 7;//strlen("karaoke");
  39. for(int n = 0; n <= siz; n++)
  40. {
  41. // lameness to just prevent a crash on broken
  42. // files no idea what else it'll break though
  43. if ((int)(ptr+n) > siz) return 0;
  44. if (!memicmp(ptr+n,"karaoke",7)) return 1;
  45. }
  46. return 0;
  47. }
  48. extern cfg_int cfg_ff7loopz;
  49. BYTE ff7loopstart[12]={0xFF,6,9,'l','o','o','p','S','t','a','r','t'};
  50. BYTE ff7loopend[10]={0xFF,6,7,'l','o','o','p','E','n','d'};
  51. int CGetInfo::DoTrack(const BYTE* track,size_t size,string& name,int cpos)
  52. {
  53. int res=0,_res=0;
  54. size_t n=0;
  55. BYTE lc1=0,lastcom=0;
  56. bool run=0;
  57. int ff_num=0;
  58. while(n<size)
  59. {
  60. {
  61. unsigned int d=0;
  62. unsigned int _n=DecodeDelta(track+n,&d);
  63. if (_n<4) res+=d;
  64. n+=_n;
  65. }
  66. if (track[n]==0xFF) //meta-events
  67. {
  68. if (f2) _res=res;
  69. if (cfg_ff7loopz
  70. && (size-n)>=sizeof(ff7loopstart) // bounds check
  71. && !memcmp(&track[n],ff7loopstart,sizeof(ff7loopstart)))
  72. {
  73. if (loop==-1) loop=res;
  74. }
  75. if ((UINT)track[n+1]==(UINT)cfg_loop_meta && loop==-1) loop=res;
  76. if (track[n+1]==0x51 && track[n+2]==0x03) //tempo
  77. {
  78. if (ttmap) ttmap->AddEntry(cpos+res,((DWORD)track[n+3]<<16)+((DWORD)track[n+4]<<8)+((DWORD)track[n+5]));
  79. n+=6;
  80. }
  81. else if (track[n+1]==0x2F && track[n+2]==0x00)
  82. {
  83. if (ff_num>max_ff_num)
  84. {
  85. max_ff_num=ff_num;
  86. max_ff_track=cur_track_start;
  87. }
  88. return _res;
  89. }
  90. else
  91. {
  92. DWORD _l=0,l1;
  93. UINT n1=0;
  94. {
  95. do
  96. {
  97. _l=(_l<<7)|(track[n+2+n1++]&0x7F);
  98. }
  99. while((n+1+n1< size) && track[n+1+n1]&0x80);
  100. }
  101. if (_l>255) l1=255;
  102. else l1=_l;
  103. if (track[n+1]<0x10) ff_num++;
  104. switch(track[n+1])
  105. {
  106. case 6:
  107. // if (!cpr || *cpr) break;
  108. case 2:
  109. if (n + 1 + n1 + l1 >= size)
  110. return -1;
  111. mf->info.copyright.add_string_n((char*)(track+n+n1+2),l1);
  112. mf->info.copyright.add_string("\x0d\x0a");
  113. break;
  114. case 5:
  115. is_blah=1;
  116. break;
  117. case 3:
  118. case 1:
  119. if (is_kar((char*)track+n+n1+2,_l)) is_blah=1;
  120. case 4:
  121. if (name.length()==0)
  122. {
  123. name.add_string_n((char*)(track+n+n1+2),l1);
  124. }
  125. break;
  126. }
  127. size_t n_increment;
  128. if (SizeTAdd(2, n1, &n_increment) != S_OK || SizeTAdd(n_increment, _l, &n_increment) != S_OK || SizeTAdd(n_increment, n, &n) != S_OK)
  129. return -1;
  130. }
  131. }
  132. else if ((track[n]&0xF0)==0xF0)
  133. {
  134. if (track[n]==0xF0)
  135. {
  136. _res=res;
  137. UINT s=ReadSysex(&track[n],size-n);
  138. smap->AddEvent(&track[n],s,cpos+res);
  139. n+=s;
  140. if (s_track==-1) s_track=c_track;
  141. else if (s_track!=c_track) s_track=-2;
  142. }
  143. else //hack...
  144. if (track[n]==0xF7) n++;
  145. else
  146. {
  147. #ifdef BLAH
  148. char tmp[32] = {0};
  149. wsprintf(tmp,"invalid Fx event at %x",n);
  150. MessageBox(0,tmp,0,0);
  151. #endif
  152. return -1;
  153. }
  154. }
  155. else
  156. {
  157. lc1=track[n];
  158. // if (lc1 == 0) return -1;
  159. if ((lc1&0x80)==0)
  160. {
  161. if (lastcom==0)
  162. return -1;
  163. run=1;
  164. lc1=lastcom;
  165. n--;
  166. } else run=0;
  167. _res=res;
  168. switch(lc1&0xF0)
  169. {
  170. case 0x80:
  171. case 0x90:
  172. if (!(got_notes&(1<<(lc1&0xF))))
  173. {
  174. nch++;
  175. got_notes|=1<<(lc1&0xF);
  176. }
  177. case 0xB0:
  178. if (track[n+1]==cfg_loop_ctrl && loop==-1)
  179. loop=res;
  180. case 0xA0:
  181. case 0xE0:
  182. n+=3;
  183. lastcom=lc1;
  184. break;
  185. case 0xC0:
  186. case 0xD0:
  187. n+=2;
  188. lastcom=lc1;
  189. break;
  190. default:
  191. return -1;
  192. }
  193. }
  194. }
  195. return _res;
  196. }
  197. bool GetMidiInfo(MIDI_file* mf)
  198. {
  199. CGetInfo i;
  200. return i.Run(mf);
  201. }
  202. bool CGetInfo::Run(MIDI_file* _mf)
  203. {
  204. mf=_mf;
  205. nch=0;
  206. s_track=-1;
  207. is_blah=0;
  208. max_ff_track=max_ff_num=0;
  209. MIDIHEADER hd = *(MIDIHEADER*)(mf->data+8);
  210. tmap=tmap_create();
  211. if (!tmap) return 0;
  212. smap=smap_create();
  213. ttmap=0;
  214. mf->tmap=tmap;//avoid stupid memleaks
  215. mf->smap=smap;
  216. loop=-1;
  217. tmap->AddEntry(0,500000);
  218. DWORD sz = mf->size-14;
  219. FixHeader(hd);
  220. got_notes=0;
  221. nch=0;
  222. const BYTE* trax=mf->data+14;
  223. const BYTE* ntrak=trax;
  224. if (hd.trax>0x100 || hd.fmt>2) return 0;
  225. f2=hd.fmt==2;
  226. int n,tmp;
  227. int size=0;
  228. mf->info.traxnames = new string[hd.trax];
  229. for(c_track=0;c_track<hd.trax;c_track++)
  230. {
  231. if (!ttmap) ttmap=tmap_create();
  232. if ((UINT)(ntrak-trax)>=(UINT)sz || *((DWORD*)ntrak)!='krTM' || (tmp=rev32(*((DWORD*)ntrak+1)))+ntrak>sz+trax) return 0;
  233. cur_track_start=ntrak-mf->data;
  234. tmp=DoTrack(ntrak+8,tmp,mf->info.traxnames[c_track],f2 ? size : 0);
  235. if (tmp==-1)
  236. {
  237. /* ntrak[8]=0;
  238. ntrak[9]=0xFF;
  239. ntrak[10]=0x2F;
  240. ntrak[11]=0;*/
  241. #ifdef BLAH
  242. {
  243. char e[128] = {0};
  244. wsprintf(e,"Bad track #%u",c_track);
  245. MessageBox(0,e,ERROR,0);
  246. }
  247. #endif
  248. }
  249. else
  250. {
  251. if (f2) size+=tmp;
  252. else if (tmp>size) size=tmp;
  253. if (ttmap->pos)
  254. {
  255. mf->tmap=tmap=tmap_merge(tmap,ttmap);
  256. ttmap=0;
  257. }
  258. }
  259. ntrak+=rev32(*((DWORD*)ntrak+1))+8;
  260. }
  261. if (ttmap) delete ttmap;
  262. if (!tmap) return 0;
  263. mf->tix=MulDiv(size+50,768,hd.dtx);
  264. DWORDLONG res=0;
  265. for(n=0;n<tmap->pos-1 && tmap->data[n].pos<size;n++)
  266. {
  267. res+=UInt32x32To64(tmap->data[n].tm,tmap->data[n+1].pos-tmap->data[n].pos);
  268. }
  269. if (tmap->data[n].pos<size) res+=UInt32x32To64(tmap->data[n].tm,size-tmap->data[n].pos);
  270. mf->len=(DWORD)(res/(hd.dtx*1000));
  271. if (loop!=-1 && loop<size)
  272. {
  273. mf->loopstart=loop;
  274. }
  275. mf->info.channels=nch;
  276. mf->info.fmt=hd.fmt;
  277. mf->info.ntrax=hd.trax;
  278. mf->info.tix=size;
  279. if (mf->loopstart)
  280. {
  281. mf->loopstart_t=mf->loopstart;
  282. mf->loopstart=MulDiv(mf->loopstart,768,hd.dtx);
  283. mf->loopend=MulDiv(size+15,768,hd.dtx);
  284. }
  285. else mf->loopstart_t=-1;
  286. if (!f2 && smap && s_track==-2) smap->CleanUp(); //todo: optimize this shit...
  287. /* mf->tmap=tmap;
  288. mf->smap=smap;*/
  289. mf->info.e_type=smap->GetType();
  290. if (is_blah)
  291. {
  292. mf->kar_track=max_ff_track;
  293. }
  294. return 1;
  295. }