#include "main.h" #include "../Agave/language/api_language.h" #include #include "resource.h" DWORD _fastcall rev32(DWORD d) {return _rv(d);} void CPipe::WriteData(void* b,UINT s) { if (closed) return; sec.enter(); if (buf_n+s>buf_s) { #ifdef USE_LOG log_write("buffer overflow"); #endif s=buf_s-buf_n; s-=s%align; } if (s) { if (buf_wp+sbuf_n) d=buf_n; if (d) { if (buf_rp+dpos=0; m->size=0x100; m->data=(TMAP_ENTRY*)malloc(m->size*sizeof(TMAP_ENTRY)); } return m; } void CTempoMap::AddEntry(int _p,int tm) { if (!data) {pos=size=0;return;} if (pos && _p<=data[pos-1].pos) {data[pos-1].tm=tm;return;} if (pos==size) { size*=2; data=(TMAP_ENTRY*)realloc(data,size*sizeof(TMAP_ENTRY)); if (!data) {pos=0;return;} } data[pos].pos=_p; data[pos].tm=tm; pos++; } int ReadSysex(const BYTE* src,int ml) { int r=1; while(r= limit) { *_d=0; return l; } b=src[l++]; d=(d<<7)|(b&0x7F); } while(b&0x80); *_d=d; return l; } int EncodeDelta(BYTE* dst,int d) { if (d==0) { dst[0]=0; return 1; } else { int r=0; int n=1; unsigned int temp=d; while (temp >>= 7) { n++; } do { n--; BYTE b=(BYTE)((d>>(7*n))&0x7F); if (n) b|=0x80; dst[r++]=b; } while(n); return r; } } int CTempoMap::BuildTrack(grow_buf & out) { if (!pos) return 0; int start=out.get_size(); //BYTE* trk=(BYTE*)malloc(8+4+pos*10); //if (!trk) return 0; out.write_dword(_rv('MTrk')); out.write_dword(0);//track size DWORD ct=0; int n; BYTE t_event[6]={0xFF,0x51,0x03,0,0,0}; for(n=0;n>16); t_event[4]=(BYTE)(t>>8); t_event[5]=(BYTE)(t); out.write(t_event,6); } out.write_dword(0x002FFF00); out.write_dword_ptr(rev32(out.get_size()-(start+8)),start+4); return 1; } //sysex map management void CSysexMap::AddEvent(const BYTE* e,DWORD s,DWORD t) { if (!data || !events) return; DWORD np=pos+1; if (np>=e_size) { do { e_size<<=1; } while(np>=e_size); events=(SYSEX_ENTRY*)realloc(events,e_size*sizeof(SYSEX_ENTRY)); if (!events) return; } DWORD nd=d_pos+s; if (nd>=d_size) { do { d_size<<=1; } while(nd>=d_size); data=(BYTE*)realloc(data,d_size); if (!data) return; } data[d_pos]=0xF0; unsigned int x; unsigned int sp=DecodeDelta(e+1,&x); if (sp >= s) return; memcpy(data+d_pos+1,e+1+sp,s-1-sp); events[pos].pos=t; events[pos].ofs=d_pos; events[pos].len=s-sp; d_pos=nd-sp; pos++; } CSysexMap* smap_create() { CSysexMap* s=new CSysexMap; if (s) { s->e_size=0x10; s->d_size=0x40; s->events=(SYSEX_ENTRY*)malloc(sizeof(SYSEX_ENTRY)*s->e_size); s->data=(BYTE*)malloc(s->d_size); s->d_pos=s->pos=0; } return s; } CSysexMap::~CSysexMap() { if (data) free(data); if (events) free(events); } BYTE d_GMReset[6]={0xF0,0x7E,0x7F,0x09,0x01,0xF7}; BYTE d_XGReset[9]={0xf0,0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,0xf7}; BYTE d_GSReset[11]={0xF0,0x41,0x10,0x42,0x12,0x40,0x00,0x7F,0x00,0x41,0xF7}; CSysexMap* CSysexMap::Translate(MIDI_file * mf) { CTempoMap* tmap=mf->tmap; if (!events || !data || !tmap) return 0; CSysexMap* nm=smap_create(); if (!nm) return 0; nm->d_size=d_size; nm->d_pos=d_pos; nm->data=(BYTE*)realloc(nm->data,nm->d_size); if (!nm->data) {delete nm;return 0;} memcpy(nm->data,data,d_pos); nm->e_size=e_size; nm->pos=pos; nm->events=(SYSEX_ENTRY*)realloc(nm->events,sizeof(SYSEX_ENTRY)*nm->e_size); if (!nm->events) {delete nm;return 0;} int pos_ms=0; int n=0; int cur_temp=0; int ntm=tmap->pos,t_pos=0; int p_t=0; int dtx = rev16(*(WORD*)(mf->data+12))*1000; int pos_tx=0; while(n=tmap->data[t_pos].pos) { DWORD d1=tmap->data[t_pos].pos-pos_tx; pos_ms+=MulDiv(cur_temp,d1<<8,dtx); cur_temp=tmap->data[t_pos].tm; t_pos++; pos_tx+=d1; d-=d1; } pos_ms+=MulDiv(cur_temp,d<<8,dtx); pos_tx+=d; nm->events[n].pos=pos_ms>>8; nm->events[n].ofs=events[n].ofs; nm->events[n].len=events[n].len; n++; } return nm; } int CSysexMap::BuildTrack(grow_buf & out) { if (!pos) return 0; int start=out.get_size(); out.write_dword(_rv('MTrk')); out.write_dword(0); int ct=0; int n; for(n=0;nevents[m].pos) { SYSEX_ENTRY t=events[n]; events[n]=events[m]; events[m]=t; } } } } char* BuildFilterString(UINT res_id, char* ext, int* len) { static char filterStr[256]; char *f = filterStr; ZeroMemory(filterStr,256); *len = 0; WASABI_API_LNGSTRING_BUF(res_id,filterStr,256); f += (*len = lstrlenA(filterStr) + 1); lstrcatA(f,"*."); f += 2; lstrcatA(f,ext); *(f + lstrlenA(ext)+1) = 0; *len += lstrlenA(ext)+3; return filterStr; } BOOL DoOpenFile(HWND w,char* fn,UINT res_id, char* ext,BOOL save) { int len = 0; OPENFILENAMEA ofn = {sizeof(ofn),0}; ofn.hwndOwner=w; ofn.lpstrFilter=BuildFilterString(res_id,ext,&len); ofn.lpstrFile=fn; ofn.nMaxFile=MAX_PATH; ofn.lpstrDefExt=ext; if (save) { ofn.Flags=OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY; return GetSaveFileNameA(&ofn); } else { ofn.Flags=OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY; return GetOpenFileNameA(&ofn); } } BOOL DoSaveFile(HWND w, char* fn, char* filt, char* ext) { OPENFILENAMEA ofn; ZeroMemory(&ofn,sizeof(ofn)); ofn.lStructSize=sizeof(ofn); ofn.hwndOwner=w; ofn.lpstrFilter=filt; ofn.lpstrFile=fn; ofn.nMaxFile=MAX_PATH; ofn.lpstrDefExt=ext; ofn.Flags=OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY; return GetOpenFileNameA(&ofn); } typedef void (*SYSEXFUNC)(void*,BYTE*,UINT); #define rsysex(X) f(i,X,sizeof(X)) #define _sysex(X,Y) f(i,X,Y) bool need_sysex_start() { return cfg_hardware_reset>0 || cfg_sysex_table.num_entries()>0 ; } void sysex_startup(SYSEXFUNC f,void* i) { if (cfg_hardware_reset>0) { switch(cfg_hardware_reset) { case 1:rsysex(d_GMReset);break; case 2:rsysex(d_GSReset);break; case 3:rsysex(d_XGReset);break; } MIDI_callback::Idle(200); } if (cfg_sysex_table.num_entries()>0) { int idx=0; BYTE * data; int size,time; while(cfg_sysex_table.get_entry(idx++,&data,&size,&time)) { _sysex(data,size); MIDI_callback::Idle(time); } } } MIDI_EVENT* do_table(MIDI_file * mf,UINT prec,UINT * size,UINT* _lstart,DWORD cflags) { BYTE * data_ptr = 0; int data_size = 0; if (!DoCleanUp(mf,CLEAN_1TRACK|CLEAN_NOSYSEX|CLEAN_NOTEMPO|cflags,(void**)&data_ptr,&data_size)) return 0; if (data_size<=0x0e) {free(data_ptr);return 0;} UINT ts; BYTE* track; UINT ntm; track=data_ptr+8+6+8; ts=rev32(*(DWORD*)(track-4)); CTempoMap* tmap=mf->tmap; UINT n=0; UINT pt=0; ntm=tmap->pos; CSysexMap* smap; if (!cfg_nosysex && mf->smap && mf->smap->pos) { smap=mf->smap; } else smap=0; n=0; DWORD pos=0; DWORD pos_ms=0; DWORD t_pos=0; DWORD cur_temp=0; UINT dtx=(UINT)rev16(*(WORD*)(data_ptr+8+4))*1000/prec; grow_buf boo; int ns=0; UINT track_pos=0,smap_pos=0; UINT loop_start=-1; { unsigned int _d; n+=DecodeDelta(track+n,&_d); track_pos+=_d; } if (smap) { smap_pos=smap->events[0].pos; } else smap_pos=-1; while(1) { DWORD ev=0; DWORD d=0; { if (n >= (data_size-26)) break; if (track_pos= (data_size-26)) break; } else if (smap_pos!=-1) { d=smap_pos-pos; ev=0x80000000|ns; ns++; if (ns==smap->pos) smap_pos=-1; else smap_pos=smap->events[ns].pos; } } if (!ev) break; while(t_pos=(UINT)tmap->data[t_pos].pos) { DWORD d1=tmap->data[t_pos].pos-pos; if (loop_start==-1 && (UINT)mf->loopstart_t<=pos+d1) loop_start=pos_ms+MulDiv(cur_temp,pos+d1-mf->loopstart_t,dtx); pos_ms+=MulDiv(cur_temp,d1,dtx); cur_temp=tmap->data[t_pos].tm; t_pos++; pos+=d1; d-=d1; } if (loop_start==-1 && (UINT)mf->loopstart_t<=pos+d) loop_start=pos_ms+MulDiv(cur_temp,d,dtx); pos_ms+=MulDiv(cur_temp,d,dtx); pos+=d; { MIDI_EVENT me={pos_ms,ev}; boo.write(&me,sizeof(me)); } } free(data_ptr); UINT sz=boo.get_size(); MIDI_EVENT* ret=(MIDI_EVENT*)boo.finish(); if (ret) { *size=sz>>3;//sz/sizeof(MIDI_EVENT); if (cfg_loop_type==2 && loop_start==-1) loop_start=0; else if (cfg_loop_type==0) loop_start=-1; if (_lstart) *_lstart=loop_start; } return ret; } void gb_write_delta(grow_buf & gb,DWORD d) { BYTE tmp[8] = {0}; gb.write(tmp,EncodeDelta(tmp,d)); } void do_messages(HWND w,bool* b) { MSG msg; while(b && *b) { BOOL b=GetMessage(&msg,w,0,0); if (b==-1 || !b) break; DispatchMessage(&msg); } } static wchar_t cb_class[]=TEXT("CallbackWndClass0"); ATOM do_callback_class(WNDPROC p) { cb_class[sizeof(cb_class)-2]++; WNDCLASS wc= { 0,p,0,4,MIDI_callback::GetInstance(),0,0,0,0,cb_class }; return RegisterClassW(&wc); } HWND create_callback_wnd(ATOM cl,void* p) { HWND w=CreateWindowA((char*)cl,0,0,0,0,0,0,MIDI_callback::GetMainWindow(),0,MIDI_callback::GetInstance(),0); if (w) SetWindowLong(w,0,(long)p); return w; } CTempoMap* tmap_merge(CTempoMap* m1,CTempoMap* m2) { int p1=0,p2=0; CTempoMap * ret=0; if (m1 && m2 && m1->data && m2->data) { ret=tmap_create(); if (ret) { while(p1pos && p2pos) { if (m1->data[p1].pos<=m2->data[p2].pos) { ret->AddEntry(m1->data[p1].pos,m1->data[p1].tm); p1++; } else { ret->AddEntry(m2->data[p2].pos,m2->data[p2].tm); p2++; } } while(p1pos) { ret->AddEntry(m1->data[p1].pos,m1->data[p1].tm); p1++; } while(p2pos) { ret->AddEntry(m2->data[p2].pos,m2->data[p2].tm); p2++; } } } if (m1) delete m1; if (m2) delete m2; return ret; } KAR_ENTRY * kmap_create(MIDI_file* mf,UINT prec,UINT * num,char** text) { if (!mf->kar_track) return 0; grow_buf b_data,b_map; KAR_ENTRY te; BYTE *track=(BYTE*)mf->data+mf->kar_track+8; BYTE *track_end = track+rev32(*(DWORD*)(mf->data+mf->kar_track+4)); int time=0; int ptr=0; BYTE lc=0; while(tracktmap; int pos_ms=0; int t_pos=0; int cur_temp=0; int dtx=(UINT)rev16(*(WORD*)(mf->data+8+4))*1000/prec; for(n=0;npos && time+d>=tmap->data[t_pos].pos) { DWORD d1=tmap->data[t_pos].pos-time; pos_ms+=MulDiv(cur_temp,d1,dtx); cur_temp=tmap->data[t_pos].tm; t_pos++; time+=d1; d-=d1; } pos_ms+=MulDiv(cur_temp,d,dtx); time+=d; map[n].time=pos_ms; } } return map; } int sysex_table::num_entries() const { int num=0; entry * ptr=entries; while(ptr) {ptr=ptr->next;num++;} return num; } int sysex_table::get_entry(int idx,BYTE ** p_data,int * p_size,int * p_time) const { entry * ptr=entries; while(ptr && idx>0) {ptr=ptr->next;idx--;} if (!ptr) return 0; if (p_data) *p_data = ptr->data; if (p_size) *p_size = ptr->size; if (p_time) *p_time = ptr->time; return 1; } void sysex_table::insert_entry(int idx,BYTE * data,int size,int time) { entry ** ptr = &entries; while(idx>0 && *ptr) { ptr = &(*ptr)->next; idx--; } entry * insert = new entry; insert->data = (BYTE*)malloc(size); memcpy(insert->data,data,size); insert->size = size; insert->time = time; insert->next = *ptr; *ptr = insert; } int sysex_table::remove_entry(int idx) { entry ** ptr = &entries; while(idx>0 && *ptr) { ptr = &(*ptr)->next; idx--; } if (!*ptr) return 0; entry * remove = *ptr; *ptr=remove->next; free(remove->data); delete remove; return 1; } int sysex_table::file_write(const char* file) const { HANDLE f=CreateFileA(file,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0); if (f==INVALID_HANDLE_VALUE) return 0; int size; void * ptr = memblock_write(&size); DWORD bw = 0; WriteFile(f,ptr,size,&bw,0); free(ptr); CloseHandle(f); return 1; } void * sysex_table::memblock_write(int * size) const { grow_buf wb; entry * ptr; //MAGIC:DWORD , NUM: DWORD,DATA_SIZE:DWORD, offsets, sleep,data DWORD temp; temp=MHP_MAGIC; wb.write(&temp,4); temp=num_entries(); wb.write(&temp,4); temp=0; for(ptr=entries;ptr;ptr=ptr->next) temp+=ptr->size; wb.write(&temp,4); temp=0; for(ptr=entries;ptr;ptr=ptr->next) { wb.write(&temp,4); temp+=ptr->size; } for(ptr=entries;ptr;ptr=ptr->next) { temp = ptr->time; wb.write(&temp,4); } for(ptr=entries;ptr;ptr=ptr->next) { wb.write(ptr->data,ptr->size); } if (size) *size = wb.get_size(); return wb.finish(); } int sysex_table::memblock_read(const void * block,int size) { entry * ptr; const BYTE * src = (const BYTE*)block; DWORD temp,total_size,total_num; if (*(DWORD*)src!=MHP_MAGIC) return 0; src+=4; temp=total_num=*(DWORD*)src; src+=4; if (total_num>0xFFFF) return 0; reset(); while(temp>0) { ptr=new entry; ptr->next=entries; entries = ptr; temp--; } total_size=*(DWORD*)src; UINT n; for(n=0,ptr=entries;ptr;ptr=ptr->next,n++) { //offset : 12 + 4 * n; //time : 12 + 4 * total_num + 4 * n; //data : 12 + 8 * total_num + offset DWORD offset,time,offset2; src = (const BYTE*)block + 12 + 4*n; offset=*(DWORD*)src; if (n!=total_num-1) offset2=*(DWORD*)(src+4); else offset2=total_size; ptr->size = offset2-offset; src = (const BYTE*)block + 12 + 4*total_num + 4*n; time = *(DWORD*)src; ptr->data = (BYTE*)malloc(offset2); src = (const BYTE*)block + 12 + 8*total_num + offset; memcpy(ptr->data,src,ptr->size); ptr->time = time; } return 1; } int sysex_table::file_read(const char* file) { HANDLE f=CreateFileA(file,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); if (f==INVALID_HANDLE_VALUE) return 0; int size = GetFileSize(f,0); void * temp = malloc(size); DWORD br = 0; ReadFile(f,temp,size,&br,0); CloseHandle(f); int rv = memblock_read(temp,size); free(temp); return rv; } int sysex_table::print_preview(int idx,char * out) const { BYTE* data; int size,time; if (!get_entry(idx,&data,&size,&time)) return 0; int size2=size; if (size2>10) size2=10; wsprintfA(out,WASABI_API_LNGSTRING(STRING_MS_FMT),time); while(out && *out) out++; int n; for(n=0;n0) { void * temp = malloc(size); if (temp) { reg_read_struct(hk,temp,size); tab->memblock_read(temp,size); free(temp); } } } virtual void write(HKEY hk) { void * data; int size; data = tab->memblock_write(&size); if (data) reg_write_struct(hk,data,size); } virtual void reset() {tab->reset();} public: cfg_var_sysex(const char * name,sysex_table * p_tab) : cfg_var(name) {tab=p_tab;} }; static cfg_var_sysex thevar("sysex_table",&cfg_sysex_table);