123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- #include "main.h"
- #pragma warning(disable:4200)
- extern BYTE ff7loopstart[12];
- extern BYTE ff7loopend[10];
- extern cfg_int cfg_hack_xg_drums, cfg_hack_dls_instruments, cfg_hack_dls_drums, cfg_ff7loopz;
- typedef union
- {
- BYTE b[4];
- DWORD dw;
- } b_dw;
- typedef struct
- {
- DWORD pos, tm, sz;
- BYTE le;
- BYTE data[];
- }
- TRACK;
- DWORD _fastcall rev32(DWORD);
- //WORD _fastcall rev16(WORD);
- int test_drum_kit(DWORD no, IDirectMusicCollection* dls);
- void do_dls_check(DWORD * i, IDirectMusicCollection * dls);
- class CCleaner
- {
- public:
- INSTRUMENT_DESC* instr, **instr_ptr;
- BYTE ctab[16][128];
- // UINT dm_vol;
- grow_buf outbuf;
- UINT ntrax, ntrax1;
- UINT maxvol;
- TRACK** in_trax;
- TRACK* out_trax[16];
- DWORD ct;
- UINT tf;
- MIDI_file* mf;
- DWORD vol_set;
- bool drumfix, insfix;
- b_dw ins[16], ins_set[16];
- bool f2, tr1, dm, only_ins, ins_no_lsb;
- bool hasnotes[16];
- void check_ins(UINT msb, UINT lsb, UINT patch, UINT note, BOOL drum, UINT ch) //called on note
- {
- if (ins_no_lsb) lsb = 0;
- INSTRUMENT_DESC * d = instr;
- while (d)
- {
- if (d->bank_hi == msb && d->bank_lo == lsb && d->patch == patch && d->drum == drum) break;
- d = d->next;
- }
- if (d)
- {
- d->count++;
- if (d->note_max < note) d->note_max = note;
- if (d->note_min > note) d->note_min = note;
- d->channels |= 1 << ch;
- }
- else
- {
- d = new INSTRUMENT_DESC;
- *instr_ptr = d;
- instr_ptr = &d->next;
- d->next = 0;
- d->note_min = d->note_max = note;
- d->bank_hi = msb;
- d->bank_lo = lsb;
- d->patch = patch;
- d->count = 1;
- d->drum = drum;
- d->user = 0;
- d->channels = 1 << ch;
- }
- }
- void AdvanceTime(TRACK* t);
- void AddEvent(BYTE ev, BYTE* data);
- void WriteTrack(TRACK* t);
- int Run(MIDI_file* mf, DWORD, void ** out_data, int * out_size);
- void do_shit(UINT n);
- UINT get_next_time()
- {
- UINT t = -1;
- UINT n;
- for (n = 0;n < ntrax;n++)
- {
- UINT t1 = in_trax[n]->tm;
- if (t1 < t) t = t1;
- }
- return t;
- }
- BOOL event_ok(BYTE e, BYTE* p)
- {
- BYTE _c = e & 0xF0;
- BYTE ch = e & 0xF;
- if (_c == 0xB0)
- {
- if (cfg_hack_xg_drums && ch == 9 && p[1] == 0 && (p[0] == 0 || p[0] == 0x20))
- return 0;
- if (p[0] > 127)
- return 0;
- ctab[ch][p[0]] = p[1];
- if (p[0] == 0)
- {
- ins[ch].b[2] = p[1];
- if (insfix) return 0;
- }
- if (p[0] == 0x20)
- {
- ins[ch].b[1] = p[1];
- if (insfix) return 0;
- }
- if (dm) //keep dm drivers happy...
- {
- if (p[0] >= 0x20 && p[0] < 0x40) //lsb values
- {
- return 0;
- }
- else if (p[0] < 0x20)
- {
- BYTE data[2] = {(BYTE)(p[0] + 0x20),ctab[ch][p[0] + 0x20]};
- AddEvent(e, data);
- }
- }
- return 1;
- }
- else if (_c == 0xC0)
- {
- if (ch == 9)
- {
- if (drumfix && !test_drum_kit(p[0], mf->pDLS)) return 0;
- ins[ch].b[0] = p[0];
- }
- else
- {
- ins[ch].b[0] = p[0];
- if (insfix) return 0;
- }
- }
- else if (_c == 0x90 && p[1])
- {
- if (only_ins)
- check_ins(ins[ch].b[2], ins[ch].b[1], ins[ch].b[0], p[0], ch == 9, ch);
- if (ch != 9 && insfix)
- {
- if (ins_set[ch].dw != ins[ch].dw)
- {
- do_dls_check(&ins[ch].dw, mf->pDLS);
- if (ins_set[ch].b[1] != ins[ch].b[1])
- {
- BYTE t[2] = {0x20, ins[ch].b[1]};
- AddEvent(0xB0 | ch, t);
- }
- if (ins_set[ch].b[2] != ins[ch].b[2])
- {
- BYTE t[2] = {0, ins[ch].b[2]};
- AddEvent(0xB0 | ch, t);
- }
- AddEvent(0xC0 | ch, ins[ch].b);
- ins_set[ch].dw = ins[ch].dw;
- }
- }
- }
- return 1;
- }
- CCleaner()
- {
- memset(ins, 0, sizeof(ins));
- memset(ins_set, -1, sizeof(ins_set));
- memset(hasnotes, 0, sizeof(hasnotes));
- memset(out_trax, 0, sizeof(out_trax));
- in_trax = 0;
- }
- ~CCleaner()
- {
- UINT n;
- if (in_trax)
- {
- for (n = 0;n < ntrax;n++)
- if (in_trax[n]) {free(in_trax[n]);in_trax[n] = 0;}
- free(in_trax);
- }
- for (n = 0;n < 16;n++)
- {
- if (out_trax[n])
- {
- free(out_trax[n]);
- out_trax[n] = 0;
- }
- }
- }
- };
- void CCleaner::do_shit(UINT n)
- {
- BYTE ce = 0;
- TRACK* t = in_trax[n];
- if (!t) return ;
- while (t->tm == ct)
- {
- if (t->pos >= t->sz)
- {
- t->pos = -1;
- t->tm = -1;
- tf++;
- break;
- }
- BYTE c0 = t->data[t->pos];
- if (c0 == 0xFF) //Meta-events
- {
- if (cfg_ff7loopz
- && (t->sz - t->pos) >= sizeof(ff7loopend) // bounds check
- && !memcmp(t->data + t->pos, ff7loopend, sizeof(ff7loopend)))
- {
- // MessageBox(GetActiveWindow(),"blah",0,0);
- // AdvanceTime(t);
- tf = ntrax;
- // return;
- }
- BYTE c1 = t->data[t->pos + 1];
- if (c1 == 0x2F)
- {
- t->pos += 3;
- t->tm = -1;
- tf++;
- }
- {
- t->pos += 2;
- if (t->pos < t->sz)
- {
- unsigned int _d;
- t->pos += DecodeDelta(t->data + t->pos, &_d, t->sz - t->pos);
- t->pos += _d;
- }
- }
- } else if (c0 == 0xF0)
- {
- t->pos += ReadSysex(&t->data[t->pos], t->sz - t->pos);
- }
- else if (c0 == 0xF7) t->pos++;
- else if ((c0&0xF0) == 0xF0) //WTF?
- {
- t->pos = -1;
- t->tm = -1;
- tf++;
- break;
- }
- else
- {
- if (c0&0x80)
- {
- ce = c0;
- t->pos++;
- }
- else ce = t->le;
- if (event_ok(ce, &t->data[t->pos])) AddEvent(ce, &t->data[t->pos]);
- if ((ce&0xF0) == 0xC0 || (ce&0xF0) == 0xD0) t->pos++;
- else t->pos += 2;
- t->le = ce;
- }
- if (t->tm != -1 && t->pos >= t->sz)
- {
- t->pos = -1;
- t->tm = -1;
- tf++;
- break;
- }
- AdvanceTime(t);
- }
- }
- #define WriteBuf(A,B) outbuf.write(A,B)
- #pragma pack(push)
- #pragma pack(1)
- typedef struct
- {
- WORD t, n, d;
- }
- MHD;
- typedef struct
- {
- DWORD c, s;
- }
- CHD;
- #pragma pack(pop)
- void CCleaner::AdvanceTime(TRACK* t)
- {
- if (t->tm != -1)
- {
- unsigned int d;
- UINT _n = DecodeDelta(t->data + t->pos, &d, t->sz - t->pos);
- if (_n < 4) t->tm += d;
- t->pos += _n;
- }
- }
- void CCleaner::AddEvent(BYTE ev, BYTE* data)
- {
- if (only_ins) return ;
- BYTE nt = ev & 0xF;
- BYTE ec = ev & 0xF0;
- if (tr1) nt = 0;
- TRACK *t = out_trax[nt];
- ZeroMemory(ctab, sizeof(ctab));
- if (!t)
- {
- t = out_trax[nt] = (TRACK*)malloc(sizeof(TRACK) + 0x1000);
- if (!t) return ;
- ZeroMemory(t, 16);
- t->sz = 0x1000;
- t->tm = 0;
- }
- else if (t->pos > t->sz - 0x10)
- {
- t->sz *= 2;
- out_trax[nt] = (TRACK*)realloc(t, sizeof(TRACK) + t->sz);
- if (!out_trax[nt])
- {
- free(t);
- return ;
- }
- t = out_trax[nt];
- }
- if (t->tm < ct)
- {
- t->pos += EncodeDelta(&t->data[t->pos], ct - t->tm);
- t->tm = ct;
- }
- else
- {
- t->data[t->pos++] = 0;
- }
- if (ec == 0x90)
- {
- hasnotes[nt] = 1;
- data[0] &= 0x7F; /* don't allow 8bit note numbers */
- }
- else if (ec == 0x80)
- {
- data[0] &= 0x7F; /* don't allow 8bit note numbers */
- }
- /*if (ev!=t->le) */{t->data[t->pos++] = ev;t->le = ev;}
- t->data[t->pos++] = data[0];
- if (ec != 0xC0 && ec != 0xD0) t->data[t->pos++] = data[1];
- }
- void CCleaner::WriteTrack(TRACK* t)
- {
- CHD chd;
- chd.c = 'krTM';
- chd.s = rev32(t->pos);
- WriteBuf(&chd, 8);
- WriteBuf(&t->data, t->pos);
- ntrax1++;
- }
- int DoCleanUp(MIDI_file* mf, DWORD mode, void** out_data, int * out_size)
- {
- CCleaner c;
- c.only_ins = 0;
- return c.Run(mf, mode, out_data, out_size);
- }
- int CCleaner::Run(MIDI_file* _mf, DWORD _md, void ** out_data, int * out_size)
- {
- f2 = *(WORD*)(_mf->data + 8) == 0x0200;
- maxvol = 90;
- vol_set = 0;
- dm = (_md & CLEAN_DM) ? 1 : 0;
- tr1 = (_md & CLEAN_1TRACK) ? 1 : 0;
- if (_md&CLEAN_DLS)
- {
- drumfix = dm && cfg_hack_dls_drums;
- insfix = dm && cfg_hack_dls_instruments;
- }
- else
- {
- drumfix = insfix = 0;
- }
- mf = _mf;
- instr_ptr = &instr;
- instr = 0;
- UINT n;
- ct = 0;
- tf = 0;
- ntrax = ntrax1 = 0;
- CHD chd;
- MHD mhd;
- DWORD ptr = 8;
- mhd = *(MHD*)(mf->data + 8);
- ptr += 6;
- mhd.t = rev16(mhd.t);
- mhd.n = rev16(mhd.n);
- if (mhd.t > 2)
- goto fail;
- ntrax = mhd.n;
- n = 0;
- in_trax = (TRACK**)malloc(sizeof(void*) * ntrax);
- for (;n < ntrax && ptr < (UINT)mf->size;n++)
- {
- chd = *(CHD*)(mf->data + ptr);
- ptr += 8;
- if (chd.c != 'krTM' || ptr > (UINT)mf->size)
- {
- ntrax = n;
- break;
- }
- chd.s = rev32(chd.s);
- //if (ptr+chd.s>(UINT)mf->size)
- if (chd.s > ((UINT)mf->size - ptr))
- {
- chd.s = mf->size - ptr;
- }
- //goto fail;
- in_trax[n] = (TRACK*)malloc(16 + chd.s);
- in_trax[n]->sz = chd.s;
- in_trax[n]->tm = 0;
- in_trax[n]->le = 0;
- in_trax[n]->pos = 0;
- memcpy(in_trax[n]->data, mf->data + ptr, chd.s);
- ptr += chd.s;
- AdvanceTime(in_trax[n]);
- }
- if (f2)
- {
- for (n = 0;n < ntrax;n++)
- {
- in_trax[n]->tm = ct;
- while (tf <= n)
- {
- do_shit(n);
- if (in_trax[n]->tm != -1) ct = in_trax[n]->tm;
- }
- }
- }
- else
- {
- while (tf < ntrax)
- {
- UINT nt = get_next_time(); //ct++;
- if (nt == -1) break;
- ct = nt;
- for (n = 0;n < ntrax && tf < ntrax;n++)
- {
- do_shit(n);
- }
- }
- }
- if (!only_ins)
- {
- mhd.t = 0x0100;
- mhd.n = 0; //rev16(ntrax1);
- chd.c = 'dhTM';
- chd.s = 0x06000000;
- WriteBuf(&chd, 8);
- WriteBuf(&mhd, 6);
- if (!(_md&CLEAN_NOTEMPO) && mf->tmap)
- {
- /* BYTE *tt=mf->tmap->BuildTrack();
- if (tt)
- {
- WriteBuf(tt,rev32(*(DWORD*)(tt+4))+8);
- ntrax1++;
- free(tt);
- }*/
- if (mf->tmap->BuildTrack(outbuf))
- {
- ntrax1++;
- }
- }
- if (!(_md&CLEAN_NOSYSEX) && mf->smap)
- {
- /* BYTE *st=mf->smap->BuildTrack();
- if (st)
- {
- WriteBuf(st,rev32(*(DWORD*)(st+4))+8);
- ntrax1++;
- free(st);
- }*/
- if (mf->smap->BuildTrack(outbuf))
- {
- ntrax1++;
- }
- }
- for (n = 0;n < 16;n++) if (out_trax[n] && hasnotes[n] && out_trax[n]->pos)
- {
- TRACK *t = out_trax[n];
- t->pos += EncodeDelta(t->data + t->pos, ct - t->tm);
- t->data[t->pos++] = 0xFF;
- t->data[t->pos++] = 0x2F;
- t->data[t->pos++] = 0;
- WriteTrack(t);
- }
- {
- WORD t = rev16(ntrax1);
- outbuf.write_ptr(&t, 2, 10);
- }
- if (out_size) *out_size = outbuf.get_size();
- if (out_data) *out_data = outbuf.finish();
- #if 0
- {
- HANDLE f = CreateFile("c:\\dump.mid", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
- DWORD bw = 0;
- WriteFile(f, rv, bs, &bw, 0);
- CloseHandle(f);
- }
- #endif
- }
- return 1;
- fail:
- // ErrorBox("WARNING: cleaner messed up");
- return 0;
- //TO DESTRUCTOR
- }
- INSTRUMENT_DESC* GetInstruments(MIDI_file* mf, BOOL do_lsb)
- {
- CCleaner c;
- c.only_ins = 1;
- c.ins_no_lsb = !do_lsb;
- c.Run(mf, 0, 0, 0);
- return c.instr;
- }
|