aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_midi/xmi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Input/in_midi/xmi.cpp')
-rw-r--r--Src/Plugins/Input/in_midi/xmi.cpp310
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