aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_midi/midiinfo.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Input/in_midi/midiinfo.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Input/in_midi/midiinfo.cpp')
-rw-r--r--Src/Plugins/Input/in_midi/midiinfo.cpp326
1 files changed, 326 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_midi/midiinfo.cpp b/Src/Plugins/Input/in_midi/midiinfo.cpp
new file mode 100644
index 00000000..e14b0563
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/midiinfo.cpp
@@ -0,0 +1,326 @@
+#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;
+} \ No newline at end of file