diff options
Diffstat (limited to 'Src/Plugins/Input/in_midi/xmi.cpp')
-rw-r--r-- | Src/Plugins/Input/in_midi/xmi.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_midi/xmi.cpp b/Src/Plugins/Input/in_midi/xmi.cpp new file mode 100644 index 00000000..6f18ec87 --- /dev/null +++ b/Src/Plugins/Input/in_midi/xmi.cpp @@ -0,0 +1,310 @@ +#include "main.h" +#include "cvt.h" + +#pragma pack(push) +#pragma pack(1) +typedef struct +{ + DWORD mthd,hdsize; + MIDIHEADER mhd; +} FILEHEADER; + +typedef struct +{ + DWORD mtrk,size; +} TRACKHEADER; + +#pragma pack(pop) + +struct XMI_cvt +{ +public: + grow_buf out; + bool _end; + DWORD tr_sz; + DWORD cur_time,wr_time; +// DWORD loopstart; + bool hasevents; + void q_add(BYTE ch,BYTE note,DWORD tm); + void WriteDelta(DWORD _d); + void DoQueue(); + DWORD ProcessNote(const BYTE* e); + DWORD ProcessDelta(const BYTE* d); + DWORD WriteEvent(const BYTE* e); + bool run(MIDI_file* mf,const BYTE*,DWORD); +#pragma pack(push) +#pragma pack(1) +#define Q_MAX 512 + +struct +{ + DWORD time; + BYTE note; + BYTE channel; +} ch_q[Q_MAX]; + +#pragma pack(pop) + +}; + + +#define WriteBuf(A,B) out.write(A,B) +#define WriteBufB(A) out.write_byte(A) +#define WriteBufD(A) out.write_dword(A) + +//WORD _fastcall rev16(WORD); +DWORD _fastcall rev32(DWORD); + + +#define FixHeader(H) {(H).fmt=rev16((H).fmt);(H).trax=rev16((H).trax);(H).dtx=rev16((H).dtx);} +#define MThd 'dhTM' +#define MTrk 'krTM' +#define EVNT 'TNVE' + +void XMI_cvt::q_add(BYTE ch,BYTE note,DWORD tm) +{ + UINT n,_n=-1; + for(n=0;n<Q_MAX;n++) + { + if (ch_q[n].note==note && ch_q[n].channel==ch && ch_q[n].time!=-1) + { + /*if (ch_q[n].time>tm) */ch_q[n].time=tm; +// q_notes++; + return; + } + else if (ch_q[n].time==-1) _n=n; + } + if (_n!=-1) + { + ch_q[_n].channel=ch; + ch_q[_n].time=tm; + ch_q[_n].note=note; +// q_notes++; + } +} + +void XMI_cvt::WriteDelta(DWORD _d) +{ + DWORD d=_d-wr_time; + wr_time=_d; + int st=out.get_size(); + gb_write_delta(out,d); + tr_sz+=out.get_size()-st; +} + +DWORD _inline ReadDelta1(const BYTE* d,DWORD* _l) +{ + DWORD r=d[0],l=0; + while(!(d[l+1]&0x80)) + { + r+=d[++l]; + } + *_l=l+1; + return r; +} + +void XMI_cvt::DoQueue() +{ + while(1) + { + DWORD _i=-1; + DWORD _mt=-1; + UINT i; + for(i=0;i<Q_MAX;i++) + { + if (ch_q[i].time<_mt) {_i=i;_mt=ch_q[i].time;} + } + if (_mt<=cur_time) + { + WriteDelta(_mt); + BYTE t[3]={(BYTE)(0x80|ch_q[_i].channel),ch_q[_i].note,0}; + WriteBuf(t,3); + ch_q[_i].time=-1; + tr_sz+=3; +// q_notes--; + } + else break; + } +} + +DWORD XMI_cvt::ProcessNote(const BYTE* e) +{ + DoQueue(); + WriteDelta(cur_time); + + WriteBuf(e,3); + tr_sz+=3; + DWORD l=3; + unsigned int _d; + l+=DecodeDelta(e+l,&_d); + + + if (e[2]) q_add(e[0]&0xF,e[1],cur_time+_d); + + return l; +} + +DWORD XMI_cvt::ProcessDelta(const BYTE* d) +{ + DWORD l; + cur_time+=ReadDelta1(d,&l); + return l; +} + +DWORD XMI_cvt::WriteEvent(const BYTE* e) +{ + if ((e[0]&0xF0)==0xF0 && e[0]!=0xFF && e[0]!=0xF0)//hack + { + UINT l=1; + while(!(e[l]&0x80)) l++; + return l; + } + else if (e[0]==0xFF) + { + if (e[1]==0x2F) + { + DWORD _ct=cur_time; + cur_time=-2; + DoQueue(); + +// loopstart=_ct-wr_time; + cur_time=_ct; + DWORD _ev=0x002FFF00; + WriteBuf(&_ev,4); + tr_sz+=4; + _end=1; + return 3; + } + else + { + UINT l=e[2]; + if (l&0x80) + { + l=((l<<7)|e[3])+1; + } + return 3+l; + } + } + DoQueue(); + WriteDelta(cur_time); + if (e[0]==0xF0) + { + unsigned int d; + UINT l = 1 + DecodeDelta(e+1,&d); + l+=d; + WriteBuf(e,l); + tr_sz+=l; + return l; + } + DWORD l; + //hasevents=1; + if ((e[0]&0xF0)==0xC0 || (e[0]&0xF0)==0xD0) l=2; + else l=3; + WriteBuf(e,l); + tr_sz+=l; + return l; +} + +BYTE xmi_track0[19]={'M','T','r','k',0,0,0,11,0,0xFF,0x51,0x03,0x20,0x8d,0xb7,0,0xFF,0x2F,0}; + +void ReleaseObject(IUnknown* o); + +bool XMI_cvt::run(MIDI_file * mf,const BYTE* buf,DWORD sz) +{ +// q_notes=0; + FILEHEADER fhd= + { + MThd, + 0x06000000, + 0x0100,0x0000,0x0001 + }; + WriteBuf(&fhd,sizeof(fhd)); + UINT ptr=0x22; + DWORD _sz; + DWORD sp; + UINT ntrax=1; + WriteBuf(xmi_track0,sizeof(xmi_track0)); + while(ptr<sz-4 && *(DWORD*)(buf+ptr)!=EVNT) ptr++; + if (*(DWORD*)(buf+ptr)!=EVNT) goto fail; +// loopstart=0; +_track: + cur_time=wr_time=0; + WriteBufD(_rv('MTrk')); + sp=out.get_size(); + WriteBufD(0); + ntrax++; + tr_sz=0; + ptr+=4; + _sz=ptr+4+rev32(*(DWORD*)(buf+ptr)); + if (_sz>sz+1) goto fail; + ptr+=4; + _end=0; + { + UINT n; + for(n=0;n<Q_MAX;n++) ch_q[n].time=-1; + } + hasevents=0; + while(ptr<sz-1 && !_end) + { + if ((buf[ptr]&0x80)==0) + { + ptr+=ProcessDelta(buf+ptr); + } + if ((buf[ptr]&0xF0)==0x90) + { + hasevents=1; + ptr+=ProcessNote(buf+ptr); + } + else ptr+=WriteEvent(buf+ptr); + } + if (!hasevents) {out.truncate(sp-4);ntrax--;} + else out.write_dword_ptr(rev32(tr_sz),sp); + if (ptr&1) ptr++; + if (ptr>=sz) goto _e; + if (*(DWORD*)(buf+ptr)==_rv('FORM') && *(DWORD*)(buf+ptr+8)==_rv('XMID')) + { + ptr+=12; +_te: if (ptr&1) ptr++; + if (*(DWORD*)(buf+ptr)==_rv('EVNT')) goto _track; + else if (*(DWORD*)(buf+ptr)==_rv('TIMB')) + { + ptr+=8+rev32(*(DWORD*)(buf+ptr+4)); + if (ptr<sz) goto _te; + } + } +_e: + { + WORD w=rev16(ntrax); + out.write_ptr(&w,2,10); + if (ntrax>1) + w=0x200; + out.write_ptr(&w,2,8); + } + + mf->size = out.get_size(); + mf->data = (BYTE*)out.finish(); + if (!mf->data) return 0; + +// if (loopstart>0x10) mf->loopstart=loopstart; +#ifdef MF_USE_DMCRAP + if (sz>ptr+0x20 && *(DWORD*)(buf+ptr)==_rv('FORM') && *(DWORD*)(buf+ptr+8)==_rv('XDLS')) + { + DWORD rs=rev32(*(DWORD*)(buf+_sz+4)); + if (rs+12+_sz>sz) goto _ret; + if (*(DWORD*)(buf+ptr+0x14)!=_rv('DLS ')) goto _ret; + mf->DLSsize=rs; + mf->pDLSdata=(BYTE*)malloc(rs); + memcpy(mf->pDLSdata,buf+_sz+12,rs); + } +#endif +_ret: + return 1; +fail: + return 0; +} + +bool load_xmi(MIDI_file * mf,const BYTE* buf,size_t sz) +{ + XMI_cvt c; + return c.run(mf,buf,sz); +}
\ No newline at end of file |