winamp/Src/Plugins/Input/in_midi/utils.cpp
2024-09-24 14:54:57 +02:00

1065 lines
19 KiB
C++

#include "main.h"
#include "../Agave/language/api_language.h"
#include <commdlg.h>
#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+s<buf_s)
{
memcpy(buf+buf_wp,b,s);
buf_wp+=s;
}
else
{
UINT d=buf_s-buf_wp;
memcpy(buf+buf_wp,b,d);
memcpy(buf,(BYTE*)b+d,s-d);
buf_wp=s-d;
}
buf_n+=s;
}
sec.leave();
}
UINT CPipe::ReadData(void* _b,UINT s,bool* ks)
{
UINT rv=0;
BYTE * b=(BYTE*)_b;
sec.enter();
while(1)
{
UINT d=s;
if (d>buf_n) d=buf_n;
if (d)
{
if (buf_rp+d<buf_s)
{
memcpy(b,buf+buf_rp,d);
buf_rp+=d;
}
else
{
UINT d1=buf_s-buf_rp;
memcpy(b,buf+buf_rp,d1);
memcpy(b+d1,buf,d-d1);
buf_rp=d-d1;
}
buf_n-=d;
s-=d;
rv+=d;
b+=d;
}
if (closed || !s || *ks) break;
sec.leave();
MIDI_callback::Idle();
sec.enter();
}
sec.leave();
return rv;
}
#ifdef USE_LOG
static HANDLE hLog;
void log_start()
{
hLog=CreateFile("c:\\in_midi.log",GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_ALWAYS,0,0);
SetFilePointer(hLog,0,0,FILE_END);
log_write("opening log");
}
void log_quit() {log_write("closing log");log_write("");log_write("");CloseHandle(hLog);}
void log_write(char* t)
{
DWORD bw;
WriteFile(hLog,t,strlen(t),&bw,0);
char _t[2]={13,10};
WriteFile(hLog,_t,2,&bw,0);
FlushFileBuffers(hLog);
}
#endif
//tempo map object
CTempoMap* tmap_create()
{
CTempoMap* m=new CTempoMap;
if (m)
{
m->pos=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<ml)
{
r++;
if (src[r]==0xF7) return r+1;
}
unsigned int d;
r=1+DecodeDelta(src+1,&d);
r+=d;
return r;
}
unsigned int DecodeDelta(const BYTE* src,unsigned int* _d, unsigned int limit)
{
unsigned int l=0;
unsigned int d=0;
BYTE b;
do
{
if (l >= 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<pos;n++)
{
DWORD t=data[n].pos;
gb_write_delta(out,t-ct);
ct=t;
t=data[n].tm;
t_event[3]=(BYTE)(t>>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<pos)
{
pos_tx=events[n].pos;
int d=pos_tx-p_t;
p_t=pos_tx;
while(t_pos<ntm && pos_tx+d>=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;n<pos;n++)
{
DWORD t=events[n].pos;
gb_write_delta(out,t-ct);
ct=t;
out.write_byte(0xF0);
gb_write_delta(out,events[n].len-1);
out.write(data+events[n].ofs+1,events[n].len-1);
}
out.write_dword(0x002FFF00);
out.write_dword_ptr(rev32(out.get_size()-(start+8)),start+4);
return 1;
}
const char* CSysexMap::GetType()
{
int ret=0;
int n;
for(n=0;n<pos;n++)
{
ret=data[events[n].ofs+1];
if (ret!=0x7E) break;
}
switch(ret)
{
case 0x7E:
return "GM";
case 0x43:
return "XG";
case 0x42:
return "X5";
case 0x41:
return "GS";
}
return 0;
}
void CSysexMap::CleanUp()
{
if (!pos) return;
int n,m;
for(n=0;n<pos-1;n++)
{
for(m=n+1;m<pos;m++)
{
if (events[n].pos>events[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<smap_pos)
{
d=track_pos-pos;
ev=(*(DWORD*)(track+n))&0xFFFFFF;
if ((ev&0xF0)==0xF0)
{
track_pos=-1;
continue;
}
if ((ev&0xF0)==0xC0 || (ev&0xF0)==0xD0)
{
ev&=0xFFFF;n+=2;
}
else
{
n+=3;
}
if ((ev&0xFF00F0)==0x90)
{
ev=(ev&0xFF0F)|0x7F0080;
}
unsigned int _d;
n+=DecodeDelta(track+n,&_d);
track_pos+=_d;
if (n >= (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<ntm && pos+d>=(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(p1<m1->pos && p2<m2->pos)
{
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(p1<m1->pos)
{
ret->AddEntry(m1->data[p1].pos,m1->data[p1].tm);
p1++;
}
while(p2<m2->pos)
{
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(track<track_end)
{
unsigned int d;
track+=DecodeDelta(track,&d);
time+=d;
if (*track==0xFF) //meta
{
BYTE type=track[1];
track+=2;
track+=DecodeDelta(track,&d);
char * ptr=(char*)track;
track+=d;
if ((type==0x5 || type==0x1) && d && *ptr!='@') //lyrics
{
te.time=time;
te.foo=1;
unsigned int n;
te.start=b_data.get_size();
for(n=0;n<d;n++)
{
switch(ptr[n])
{
// case '@':
case '\\':
case '/':
case 0x0D:
b_data.write("\x0d\x0a",2);
break;
case 0x0A:
break;
default:
te.foo=0;
b_data.write_byte(ptr[n]);
break;
}
}
te.end=b_data.get_size();
if (te.start<te.end) b_map.write(&te,sizeof(te));
}
}
else if (*track==0xF0)
{
track++;
track+=DecodeDelta(track,&d);
track+=d;
}
else if ((*track&0xF0)==0xF0)
{
track++;//hack
}
else
{
if (*track&0x80) lc=*(track++)&0xF0;
if (lc==0 || lc==0xC0 || lc==0xD0) track++;
else track+=2;
}
}
int map_siz = b_map.get_size();
KAR_ENTRY * map=(KAR_ENTRY*)b_map.finish();
map_siz/=sizeof(KAR_ENTRY);
if (num) *num=map_siz;
if (text)
{
b_data.write_byte(0);
*text=(char*)b_data.finish();
}
else b_data.reset();
if (map)
{
int n;
time=0;
CTempoMap* tmap=mf->tmap;
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;n<map_siz;n++)
{
int d=0;
d=map[n].time-time;
while(t_pos<tmap->pos && 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;n<size2;n++)
{
wsprintfA(out," %02X",data[n]);
out+=3;
}
if (size!=size2)
{
strcpy(out,"...");
}
return 1;
}
void sysex_table::print_edit(int idx,HWND wnd) const
{
BYTE* data;
int size,time;
if (!get_entry(idx,&data,&size,&time)) {SetWindowTextA(wnd,"");return;}
if (size<=2) {SetWindowTextA(wnd,"");return;}
char *temp = (char*)malloc(3*size);
char *ptr = temp;
int n;
for(n=1;n<size-1;n++)
{
wsprintfA(ptr,"%02X ",data[n]);
ptr+=3;
}
ptr[-1]=0;
SetWindowTextA(wnd,temp);
free(temp);
}
void sysex_table::copy(const sysex_table & src)
{
reset();
int idx=0;
BYTE * data;
int size,time;
while(src.get_entry(idx++,&data,&size,&time))//ASS SLOW
insert_entry(idx,data,size,time);
}
//special sysex table cfg_var hack
class cfg_var_sysex : private cfg_var
{
private:
sysex_table * tab;
virtual void read(HKEY hk)
{
int size=reg_get_struct_size(hk);
if (size>0)
{
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);