123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- #include "main.h"
- #include <intsafe.h>
- #define _RIFF 'FFIR'
- #define _MThd 'dhTM'
- #define _MTrk 'krTM'
- #define _RMID 'DIMR'
- #define _data 'atad'
- //#define BLAH
- static cfg_int cfg_loop_ctrl("cfg_loop_ctrl",255),cfg_loop_meta("cfg_loop_meta",255);
- class CGetInfo
- {
- public:
- MIDI_file * mf;
- int loop;
- int nch;
- int got_notes;
- int cur_track_start;
- int c_track,s_track;
- bool is_blah,f2;
- int max_ff_track,max_ff_num;
- CTempoMap *tmap,*ttmap;
- CSysexMap *smap;
- void CleanTempo();
- int DoTrack(const BYTE* track,size_t size,string& name,int);
- bool Run(MIDI_file* mf);
- };
- static bool memicmp(char* b1,char* b2,int s)
- {
- for(int n = 0; n < s; n++)
- {
- if (tolower(b1[n]) != tolower(b2[n]))
- return 1;
- }
- return 0;
- }
- static bool is_kar(char* ptr,int siz) //hack
- {
- siz -= 7;//strlen("karaoke");
- for(int n = 0; n <= siz; n++)
- {
- // lameness to just prevent a crash on broken
- // files no idea what else it'll break though
- if ((int)(ptr+n) > siz) return 0;
- if (!memicmp(ptr+n,"karaoke",7)) return 1;
- }
- return 0;
- }
- extern cfg_int cfg_ff7loopz;
- BYTE ff7loopstart[12]={0xFF,6,9,'l','o','o','p','S','t','a','r','t'};
- BYTE ff7loopend[10]={0xFF,6,7,'l','o','o','p','E','n','d'};
- int CGetInfo::DoTrack(const BYTE* track,size_t size,string& name,int cpos)
- {
- int res=0,_res=0;
- size_t n=0;
- BYTE lc1=0,lastcom=0;
- bool run=0;
- int ff_num=0;
- while(n<size)
- {
- {
- unsigned int d=0;
- unsigned int _n=DecodeDelta(track+n,&d);
- if (_n<4) res+=d;
- n+=_n;
- }
- if (track[n]==0xFF) //meta-events
- {
- if (f2) _res=res;
- if (cfg_ff7loopz
- && (size-n)>=sizeof(ff7loopstart) // bounds check
- && !memcmp(&track[n],ff7loopstart,sizeof(ff7loopstart)))
- {
- if (loop==-1) loop=res;
- }
- if ((UINT)track[n+1]==(UINT)cfg_loop_meta && loop==-1) loop=res;
- if (track[n+1]==0x51 && track[n+2]==0x03) //tempo
- {
- if (ttmap) ttmap->AddEntry(cpos+res,((DWORD)track[n+3]<<16)+((DWORD)track[n+4]<<8)+((DWORD)track[n+5]));
- n+=6;
- }
- else if (track[n+1]==0x2F && track[n+2]==0x00)
- {
- if (ff_num>max_ff_num)
- {
- max_ff_num=ff_num;
- max_ff_track=cur_track_start;
- }
- return _res;
- }
- else
- {
- DWORD _l=0,l1;
- UINT n1=0;
- {
- do
- {
- _l=(_l<<7)|(track[n+2+n1++]&0x7F);
- }
- while((n+1+n1< size) && track[n+1+n1]&0x80);
- }
- if (_l>255) l1=255;
- else l1=_l;
- if (track[n+1]<0x10) ff_num++;
- switch(track[n+1])
- {
- case 6:
- // if (!cpr || *cpr) break;
- case 2:
- if (n + 1 + n1 + l1 >= size)
- return -1;
- mf->info.copyright.add_string_n((char*)(track+n+n1+2),l1);
- mf->info.copyright.add_string("\x0d\x0a");
- break;
- case 5:
- is_blah=1;
- break;
- case 3:
- case 1:
- if (is_kar((char*)track+n+n1+2,_l)) is_blah=1;
- case 4:
- if (name.length()==0)
- {
- name.add_string_n((char*)(track+n+n1+2),l1);
- }
- break;
- }
- size_t n_increment;
- if (SizeTAdd(2, n1, &n_increment) != S_OK || SizeTAdd(n_increment, _l, &n_increment) != S_OK || SizeTAdd(n_increment, n, &n) != S_OK)
- return -1;
- }
- }
- else if ((track[n]&0xF0)==0xF0)
- {
- if (track[n]==0xF0)
- {
- _res=res;
- UINT s=ReadSysex(&track[n],size-n);
- smap->AddEvent(&track[n],s,cpos+res);
- n+=s;
- if (s_track==-1) s_track=c_track;
- else if (s_track!=c_track) s_track=-2;
- }
- else //hack...
- if (track[n]==0xF7) n++;
- else
- {
- #ifdef BLAH
- char tmp[32] = {0};
- wsprintf(tmp,"invalid Fx event at %x",n);
- MessageBox(0,tmp,0,0);
- #endif
- return -1;
- }
- }
- else
- {
- lc1=track[n];
- // if (lc1 == 0) return -1;
- if ((lc1&0x80)==0)
- {
- if (lastcom==0)
- return -1;
- run=1;
- lc1=lastcom;
- n--;
-
- } else run=0;
- _res=res;
- switch(lc1&0xF0)
- {
- case 0x80:
- case 0x90:
- if (!(got_notes&(1<<(lc1&0xF))))
- {
- nch++;
- got_notes|=1<<(lc1&0xF);
- }
- case 0xB0:
- if (track[n+1]==cfg_loop_ctrl && loop==-1)
- loop=res;
- case 0xA0:
- case 0xE0:
- n+=3;
- lastcom=lc1;
- break;
- case 0xC0:
- case 0xD0:
- n+=2;
- lastcom=lc1;
- break;
- default:
- return -1;
- }
- }
- }
- return _res;
- }
- bool GetMidiInfo(MIDI_file* mf)
- {
- CGetInfo i;
- return i.Run(mf);
- }
- bool CGetInfo::Run(MIDI_file* _mf)
- {
- mf=_mf;
- nch=0;
- s_track=-1;
- is_blah=0;
- max_ff_track=max_ff_num=0;
- MIDIHEADER hd = *(MIDIHEADER*)(mf->data+8);
- tmap=tmap_create();
- if (!tmap) return 0;
- smap=smap_create();
- ttmap=0;
- mf->tmap=tmap;//avoid stupid memleaks
- mf->smap=smap;
- loop=-1;
- tmap->AddEntry(0,500000);
- DWORD sz = mf->size-14;
- FixHeader(hd);
- got_notes=0;
- nch=0;
-
- const BYTE* trax=mf->data+14;
- const BYTE* ntrak=trax;
- if (hd.trax>0x100 || hd.fmt>2) return 0;
- f2=hd.fmt==2;
- int n,tmp;
- int size=0;
- mf->info.traxnames = new string[hd.trax];
- for(c_track=0;c_track<hd.trax;c_track++)
- {
- if (!ttmap) ttmap=tmap_create();
- if ((UINT)(ntrak-trax)>=(UINT)sz || *((DWORD*)ntrak)!='krTM' || (tmp=rev32(*((DWORD*)ntrak+1)))+ntrak>sz+trax) return 0;
- cur_track_start=ntrak-mf->data;
- tmp=DoTrack(ntrak+8,tmp,mf->info.traxnames[c_track],f2 ? size : 0);
- if (tmp==-1)
- {
- /* ntrak[8]=0;
- ntrak[9]=0xFF;
- ntrak[10]=0x2F;
- ntrak[11]=0;*/
- #ifdef BLAH
- {
- char e[128] = {0};
- wsprintf(e,"Bad track #%u",c_track);
- MessageBox(0,e,ERROR,0);
- }
- #endif
- }
- else
- {
- if (f2) size+=tmp;
- else if (tmp>size) size=tmp;
- if (ttmap->pos)
- {
- mf->tmap=tmap=tmap_merge(tmap,ttmap);
- ttmap=0;
- }
-
- }
- ntrak+=rev32(*((DWORD*)ntrak+1))+8;
- }
- if (ttmap) delete ttmap;
- if (!tmap) return 0;
- mf->tix=MulDiv(size+50,768,hd.dtx);
- DWORDLONG res=0;
- for(n=0;n<tmap->pos-1 && tmap->data[n].pos<size;n++)
- {
- res+=UInt32x32To64(tmap->data[n].tm,tmap->data[n+1].pos-tmap->data[n].pos);
- }
- if (tmap->data[n].pos<size) res+=UInt32x32To64(tmap->data[n].tm,size-tmap->data[n].pos);
- mf->len=(DWORD)(res/(hd.dtx*1000));
-
- if (loop!=-1 && loop<size)
- {
- mf->loopstart=loop;
- }
- mf->info.channels=nch;
- mf->info.fmt=hd.fmt;
- mf->info.ntrax=hd.trax;
- mf->info.tix=size;
- if (mf->loopstart)
- {
- mf->loopstart_t=mf->loopstart;
- mf->loopstart=MulDiv(mf->loopstart,768,hd.dtx);
- mf->loopend=MulDiv(size+15,768,hd.dtx);
- }
- else mf->loopstart_t=-1;
- if (!f2 && smap && s_track==-2) smap->CleanUp(); //todo: optimize this shit...
- /* mf->tmap=tmap;
- mf->smap=smap;*/
- mf->info.e_type=smap->GetType();
- if (is_blah)
- {
- mf->kar_track=max_ff_track;
- }
- return 1;
- }
|