stuff
This commit is contained in:
parent
27cde60f0b
commit
873bad1613
|
@ -273,7 +273,7 @@ int DivCS::getInsLength(unsigned char ins, unsigned char ext, unsigned char* spe
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writePackedCommandValues(SafeWriter* w, const DivCommand& c) {
|
void writeCommandValues(SafeWriter* w, const DivCommand& c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON:
|
case DIV_CMD_NOTE_ON:
|
||||||
if (c.value==DIV_NOTE_NULL) {
|
if (c.value==DIV_NOTE_NULL) {
|
||||||
|
@ -562,6 +562,8 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) {
|
||||||
logW("unimplemented command %s!",cmdName[c.cmd]);
|
logW("unimplemented command %s!",cmdName[c.cmd]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// padding (TODO: optimize)
|
||||||
|
while (w->tell()&7) w->writeC(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _EXT(b,x,l) (((size_t)((x)+1)<(size_t)(l))?(b[(x)+1]):0)
|
#define _EXT(b,x,l) (((size_t)((x)+1)<(size_t)(l))?(b[(x)+1]):0)
|
||||||
|
@ -608,19 +610,181 @@ SafeWriter* stripNops(SafeWriter* s, unsigned char* speedDial) {
|
||||||
|
|
||||||
// prepare address map
|
// prepare address map
|
||||||
size_t addr=0;
|
size_t addr=0;
|
||||||
for (size_t i=0; i<oldStream->size();) {
|
for (size_t i=0; i<oldStream->size(); i+=8) {
|
||||||
int insLen=getInsLength(buf[i],_EXT(buf,i,oldStream->size()),speedDial);
|
|
||||||
if (insLen<1) {
|
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
addrTable[i]=addr;
|
addrTable[i]=addr;
|
||||||
if (buf[i]!=0xf1) addr+=insLen;
|
if (buf[i]!=0xf1) addr+=8;
|
||||||
i+=insLen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate addresses
|
// translate addresses
|
||||||
for (size_t i=0; i<oldStream->size();) {
|
for (size_t i=0; i<oldStream->size(); i+=8) {
|
||||||
|
switch (buf[i]) {
|
||||||
|
case 0xf5: // calli
|
||||||
|
case 0xfa: { // jmp
|
||||||
|
unsigned int addr=buf[i+1]|(buf[i+2]<<8)|(buf[i+3]<<16)|(buf[i+4]<<24);
|
||||||
|
try {
|
||||||
|
addr=addrTable[addr];
|
||||||
|
buf[i+1]=addr&0xff;
|
||||||
|
buf[i+2]=(addr>>8)&0xff;
|
||||||
|
buf[i+3]=(addr>>16)&0xff;
|
||||||
|
buf[i+4]=(addr>>24)&0xff;
|
||||||
|
} catch (std::out_of_range& e) {
|
||||||
|
logW("address %x is not mappable!",addr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xf8: { // call
|
||||||
|
unsigned int addr=buf[i+1]|(buf[i+2]<<8);
|
||||||
|
try {
|
||||||
|
addr=addrTable[addr];
|
||||||
|
buf[i+1]=addr&0xff;
|
||||||
|
buf[i+2]=(addr>>8)&0xff;
|
||||||
|
} catch (std::out_of_range& e) {
|
||||||
|
logW("address %x is not mappable!",addr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf[i]!=0xf1) {
|
||||||
|
s->write(&buf[i],8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oldStream->finish();
|
||||||
|
delete oldStream;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlocks, unsigned char* speedDial) {
|
||||||
|
unsigned char* buf=stream->getFinalBuf();
|
||||||
|
|
||||||
|
for (size_t groupSize=stream->size()>>1; groupSize>=32; groupSize-=8) {
|
||||||
|
bool foundSomething=false;
|
||||||
|
logV("...try size %d",groupSize);
|
||||||
|
for (size_t searchPos=0; (searchPos+groupSize)<stream->size();) {
|
||||||
|
const unsigned char* group=&buf[searchPos];
|
||||||
|
size_t groupLen=0;
|
||||||
|
size_t groupInsCount=0;
|
||||||
|
size_t subBlockID=subBlocks.size();
|
||||||
|
bool haveSub=false;
|
||||||
|
bool onlyCalls=true;
|
||||||
|
|
||||||
|
// register this block
|
||||||
|
for (size_t i=0; i<groupSize && i<stream->size(); i+=8) {
|
||||||
|
if (buf[searchPos+i]!=0xf4) onlyCalls=false;
|
||||||
|
if (groupLen+8>groupSize) break;
|
||||||
|
groupLen+=8;
|
||||||
|
groupInsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't do anything if we don't have a block large enough
|
||||||
|
if (groupLen<24) {
|
||||||
|
searchPos+=8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't do anything if this is just one or two commands
|
||||||
|
// TODO: this is a duplicate of the previous statement now that all commands are 8 bytes long
|
||||||
|
if (groupInsCount<3) {
|
||||||
|
searchPos+=8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't do anything if this block only consists of calls
|
||||||
|
if (onlyCalls) {
|
||||||
|
logW("nothing but calls.");
|
||||||
|
searchPos+=8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find identical blocks
|
||||||
|
for (size_t i=searchPos+groupLen; i+groupLen<stream->size();) {
|
||||||
|
// compare next block to group
|
||||||
|
if (memcmp(&buf[i],group,groupLen)==0) {
|
||||||
|
// we have a sub-block
|
||||||
|
if (!haveSub) {
|
||||||
|
// isolate this sub-block
|
||||||
|
SafeWriter* newBlock=new SafeWriter;
|
||||||
|
newBlock->init();
|
||||||
|
newBlock->write(group,groupLen);
|
||||||
|
newBlock->writeC(0xf9); // ret
|
||||||
|
// padding
|
||||||
|
newBlock->writeC(0);
|
||||||
|
newBlock->writeC(0);
|
||||||
|
newBlock->writeC(0);
|
||||||
|
newBlock->writeC(0);
|
||||||
|
newBlock->writeC(0);
|
||||||
|
newBlock->writeC(0);
|
||||||
|
newBlock->writeC(0);
|
||||||
|
subBlocks.push_back(newBlock);
|
||||||
|
haveSub=true;
|
||||||
|
logD("- SUB %x (size %d):",searchPos,groupLen);
|
||||||
|
}
|
||||||
|
logD(" - %x",i);
|
||||||
|
// insert call
|
||||||
|
buf[i]=0xf4;
|
||||||
|
buf[i+1]=subBlockID&0xff;
|
||||||
|
buf[i+2]=(subBlockID>>8)&0xff;
|
||||||
|
buf[i+3]=(subBlockID>>16)&0xff;
|
||||||
|
buf[i+4]=(subBlockID>>24)&0xff;
|
||||||
|
|
||||||
|
// replace the rest with nop
|
||||||
|
for (size_t j=i+8; j<i+groupLen; j++) {
|
||||||
|
buf[j]=0xf1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue search from end of block
|
||||||
|
i+=groupLen;
|
||||||
|
} else {
|
||||||
|
// next
|
||||||
|
i+=8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (haveSub) {
|
||||||
|
// insert call on the original block
|
||||||
|
buf[searchPos]=0xf4;
|
||||||
|
buf[searchPos+1]=subBlockID&0xff;
|
||||||
|
buf[searchPos+2]=(subBlockID>>8)&0xff;
|
||||||
|
buf[searchPos+3]=(subBlockID>>16)&0xff;
|
||||||
|
buf[searchPos+4]=(subBlockID>>24)&0xff;
|
||||||
|
|
||||||
|
// replace the rest with nop
|
||||||
|
for (size_t j=searchPos+8; j<searchPos+groupLen; j++) {
|
||||||
|
buf[j]=0xf1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip this block (it's isolated now)
|
||||||
|
searchPos+=groupLen;
|
||||||
|
foundSomething=true;
|
||||||
|
} else {
|
||||||
|
// try again somewhere else
|
||||||
|
searchPos+=8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundSomething) {
|
||||||
|
stream=stripNops(stream,speedDial);
|
||||||
|
buf=stream->getFinalBuf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeWriter* packStream(SafeWriter* s, unsigned char* speedDial) {
|
||||||
|
std::unordered_map<unsigned int,unsigned int> addrTable;
|
||||||
|
SafeWriter* oldStream=s;
|
||||||
|
unsigned char* buf=oldStream->getFinalBuf();
|
||||||
|
s=new SafeWriter;
|
||||||
|
s->init();
|
||||||
|
|
||||||
|
// prepare address map
|
||||||
|
size_t addr=0;
|
||||||
|
for (size_t i=0; i<oldStream->size(); i+=8) {
|
||||||
|
addrTable[i]=addr;
|
||||||
|
addr+=getInsLength(buf[i],_EXT(buf,i,oldStream->size()),speedDial);
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate addresses and write stream
|
||||||
|
for (size_t i=0; i<oldStream->size(); i+=8) {
|
||||||
int insLen=getInsLength(buf[i],_EXT(buf,i,oldStream->size()),speedDial);
|
int insLen=getInsLength(buf[i],_EXT(buf,i,oldStream->size()),speedDial);
|
||||||
if (insLen<1) {
|
if (insLen<1) {
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
||||||
|
@ -653,143 +817,14 @@ SafeWriter* stripNops(SafeWriter* s, unsigned char* speedDial) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (buf[i]!=0xf1) {
|
|
||||||
s->write(&buf[i],insLen);
|
s->write(&buf[i],insLen);
|
||||||
}
|
}
|
||||||
i+=insLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
oldStream->finish();
|
oldStream->finish();
|
||||||
delete oldStream;
|
delete oldStream;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlocks, unsigned char* speedDial) {
|
|
||||||
unsigned char* buf=stream->getFinalBuf();
|
|
||||||
|
|
||||||
for (size_t groupSize=stream->size()>>1; groupSize>=8; groupSize--) {
|
|
||||||
//for (size_t groupSize=7; groupSize<=stream->size()>>1; groupSize++) {
|
|
||||||
bool foundSomething=false;
|
|
||||||
logV("...try size %d",groupSize);
|
|
||||||
for (size_t searchPos=0; (searchPos+groupSize)<stream->size();) {
|
|
||||||
const unsigned char* group=&buf[searchPos];
|
|
||||||
size_t groupLen=0;
|
|
||||||
size_t groupInsCount=0;
|
|
||||||
size_t subBlockID=subBlocks.size();
|
|
||||||
int insLen=getInsLength(buf[searchPos],_EXT(buf,searchPos,stream->size()),speedDial);
|
|
||||||
bool haveSub=false;
|
|
||||||
bool onlyCalls=true;
|
|
||||||
|
|
||||||
if (insLen<1) {
|
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[searchPos]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// register this block
|
|
||||||
for (size_t i=0; i<groupSize && i<stream->size();) {
|
|
||||||
if (buf[searchPos+i]!=0xf4) onlyCalls=false;
|
|
||||||
int insLenI=getInsLength(buf[searchPos+i],_EXT(buf,searchPos+i,stream->size()),speedDial);
|
|
||||||
if (insLenI<1) {
|
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[searchPos+i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i+=insLenI;
|
|
||||||
if (groupLen+insLenI>groupSize) break;
|
|
||||||
groupLen+=insLenI;
|
|
||||||
groupInsCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't do anything if we don't have a block large enough
|
|
||||||
if (groupLen<5) {
|
|
||||||
searchPos+=insLen;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't do anything if this is just one or two commands
|
|
||||||
if (groupInsCount<3) {
|
|
||||||
searchPos+=insLen;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't do anything if this block only consists of calls
|
|
||||||
if (onlyCalls) {
|
|
||||||
logW("nothing but calls.");
|
|
||||||
searchPos+=insLen;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find identical blocks
|
|
||||||
for (size_t i=searchPos+groupLen; i+groupLen<stream->size();) {
|
|
||||||
int insLenI=getInsLength(buf[i],_EXT(buf,i,stream->size()),speedDial);
|
|
||||||
if (insLenI<1) {
|
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compare next block to group
|
|
||||||
if (memcmp(&buf[i],group,groupLen)==0) {
|
|
||||||
// we have a sub-block
|
|
||||||
if (!haveSub) {
|
|
||||||
// isolate this sub-block
|
|
||||||
SafeWriter* newBlock=new SafeWriter;
|
|
||||||
newBlock->init();
|
|
||||||
newBlock->write(group,groupLen);
|
|
||||||
newBlock->writeC(0xf9); // ret
|
|
||||||
subBlocks.push_back(newBlock);
|
|
||||||
haveSub=true;
|
|
||||||
logD("- SUB %x (size %d):",searchPos,groupLen);
|
|
||||||
}
|
|
||||||
logD(" - %x",i);
|
|
||||||
// insert call
|
|
||||||
buf[i]=0xf4;
|
|
||||||
buf[i+1]=subBlockID&0xff;
|
|
||||||
buf[i+2]=(subBlockID>>8)&0xff;
|
|
||||||
buf[i+3]=(subBlockID>>16)&0xff;
|
|
||||||
buf[i+4]=(subBlockID>>24)&0xff;
|
|
||||||
|
|
||||||
// replace the rest with nop
|
|
||||||
for (size_t j=i+5; j<i+groupLen; j++) {
|
|
||||||
buf[j]=0xf1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// continue search from end of block
|
|
||||||
i+=groupLen;
|
|
||||||
} else {
|
|
||||||
// next
|
|
||||||
i+=insLenI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (haveSub) {
|
|
||||||
// insert call on the original block
|
|
||||||
buf[searchPos]=0xf4;
|
|
||||||
buf[searchPos+1]=subBlockID&0xff;
|
|
||||||
buf[searchPos+2]=(subBlockID>>8)&0xff;
|
|
||||||
buf[searchPos+3]=(subBlockID>>16)&0xff;
|
|
||||||
buf[searchPos+4]=(subBlockID>>24)&0xff;
|
|
||||||
|
|
||||||
// replace the rest with nop
|
|
||||||
for (size_t j=searchPos+5; j<searchPos+groupLen; j++) {
|
|
||||||
buf[j]=0xf1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip this block (it's isolated now)
|
|
||||||
searchPos+=groupLen;
|
|
||||||
foundSomething=true;
|
|
||||||
} else {
|
|
||||||
// try again somewhere else
|
|
||||||
searchPos+=insLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (foundSomething) {
|
|
||||||
stream=stripNops(stream,speedDial);
|
|
||||||
buf=stream->getFinalBuf();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disablePasses) {
|
SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disablePasses) {
|
||||||
stop();
|
stop();
|
||||||
repeatPattern=false;
|
repeatPattern=false;
|
||||||
|
@ -867,6 +902,11 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
chanStream[i]->writeC(0x00);
|
chanStream[i]->writeC(0x00);
|
||||||
chanStream[i]->writeC(0x00);
|
chanStream[i]->writeC(0x00);
|
||||||
chanStream[i]->writeC(0x00);
|
chanStream[i]->writeC(0x00);
|
||||||
|
// padding
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -880,6 +920,10 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
curDivider=divider;
|
curDivider=divider;
|
||||||
chanStream[0]->writeC(0xfb);
|
chanStream[0]->writeC(0xfb);
|
||||||
chanStream[0]->writeI((int)(curDivider*65536));
|
chanStream[0]->writeI((int)(curDivider*65536));
|
||||||
|
// padding
|
||||||
|
chanStream[0]->writeC(0x00);
|
||||||
|
chanStream[0]->writeC(0x00);
|
||||||
|
chanStream[0]->writeC(0x00);
|
||||||
}
|
}
|
||||||
for (DivCommand& i: cmdStream) {
|
for (DivCommand& i: cmdStream) {
|
||||||
switch (i.cmd) {
|
switch (i.cmd) {
|
||||||
|
@ -894,19 +938,35 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cmdPopularity[i.cmd]++;
|
cmdPopularity[i.cmd]++;
|
||||||
writePackedCommandValues(chanStream[i.chan],i);
|
writeCommandValues(chanStream[i.chan],i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmdStream.clear();
|
cmdStream.clear();
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
chanStream[i]->writeC(0xfe);
|
chanStream[i]->writeC(0xfe);
|
||||||
|
// padding
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
}
|
}
|
||||||
tick++;
|
tick++;
|
||||||
}
|
}
|
||||||
if (!playing || loopTick<0) {
|
if (!playing || loopTick<0) {
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
chanStream[i]->writeC(0xff);
|
chanStream[i]->writeC(0xff);
|
||||||
|
// padding
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
|
@ -914,9 +974,21 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
chanStream[i]->writeC(0xfa);
|
chanStream[i]->writeC(0xfa);
|
||||||
chanStream[i]->writeI(tickPos[i][loopTick]);
|
chanStream[i]->writeI(tickPos[i][loopTick]);
|
||||||
logD("chan %d loop addr: %x",i,tickPos[i][loopTick]);
|
logD("chan %d loop addr: %x",i,tickPos[i][loopTick]);
|
||||||
|
// padding
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
} else {
|
} else {
|
||||||
logW("chan %d unable to find loop addr!",i);
|
logW("chan %d unable to find loop addr!",i);
|
||||||
chanStream[i]->writeC(0xff);
|
chanStream[i]->writeC(0xff);
|
||||||
|
// padding
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
|
chanStream[i]->writeC(0x00);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -956,28 +1028,20 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
// set speed dial commands
|
// set speed dial commands
|
||||||
for (int h=0; h<chans; h++) {
|
for (int h=0; h<chans; h++) {
|
||||||
unsigned char* buf=chanStream[h]->getFinalBuf();
|
unsigned char* buf=chanStream[h]->getFinalBuf();
|
||||||
for (size_t i=0; i<chanStream[h]->size();) {
|
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
|
||||||
int insLen=getInsLength(buf[i],_EXT(buf,i,chanStream[h]->size()),sortedCmd);
|
|
||||||
if (insLen<1) {
|
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (buf[i]==0xf7) {
|
if (buf[i]==0xf7) {
|
||||||
// find whether this command is in speed dial
|
// find whether this command is in speed dial
|
||||||
for (int j=0; j<16; j++) {
|
for (int j=0; j<16; j++) {
|
||||||
if (buf[i+1]==sortedCmd[j]) {
|
if (buf[i+1]==sortedCmd[j]) {
|
||||||
buf[i]=0xd0+j;
|
buf[i]=0xd0+j;
|
||||||
// move everything to the left
|
// move everything to the left
|
||||||
for (int k=i+2; k<(int)i+insLen; k++) {
|
for (int k=i+2; k<(int)i+8; k++) {
|
||||||
buf[k-1]=buf[k];
|
buf[k-1]=buf[k];
|
||||||
}
|
}
|
||||||
// put a nop
|
|
||||||
buf[i+insLen-1]=0xf1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i+=insLen;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -988,12 +1052,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
for (int h=0; h<chans; h++) {
|
for (int h=0; h<chans; h++) {
|
||||||
unsigned char* buf=chanStream[h]->getFinalBuf();
|
unsigned char* buf=chanStream[h]->getFinalBuf();
|
||||||
int delayCount=0;
|
int delayCount=0;
|
||||||
for (size_t i=0; i<chanStream[h]->size();) {
|
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
|
||||||
int insLen=getInsLength(buf[i],_EXT(buf,i,chanStream[h]->size()),sortedCmd);
|
|
||||||
if (insLen<1) {
|
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (buf[i]==0xfe) {
|
if (buf[i]==0xfe) {
|
||||||
delayCount++;
|
delayCount++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1002,7 +1061,6 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
}
|
}
|
||||||
delayCount=0;
|
delayCount=0;
|
||||||
}
|
}
|
||||||
i+=insLen;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1035,12 +1093,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
int delayPos=-1;
|
int delayPos=-1;
|
||||||
int delayCount=0;
|
int delayCount=0;
|
||||||
int delayLast=0;
|
int delayLast=0;
|
||||||
for (size_t i=0; i<chanStream[h]->size();) {
|
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
|
||||||
int insLen=getInsLength(buf[i],_EXT(buf,i,chanStream[h]->size()),sortedCmd);
|
|
||||||
if (insLen<1) {
|
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (buf[i]==0xfe) {
|
if (buf[i]==0xfe) {
|
||||||
if (delayPos==-1) delayPos=i;
|
if (delayPos==-1) delayPos=i;
|
||||||
delayCount++;
|
delayCount++;
|
||||||
|
@ -1081,7 +1134,6 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
delayCount=0;
|
delayCount=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i+=insLen;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1140,6 +1192,8 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
} else {
|
} else {
|
||||||
// write sub-block
|
// write sub-block
|
||||||
blockOff.push_back(chanStream[h]->tell());
|
blockOff.push_back(chanStream[h]->tell());
|
||||||
|
logV("block size: %d",(int)block->size());
|
||||||
|
assert(!(block->size()&7));
|
||||||
chanStream[h]->write(block->getFinalBuf(),block->size());
|
chanStream[h]->write(block->getFinalBuf(),block->size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1152,39 +1206,26 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
|
|
||||||
// resolve symbols
|
// resolve symbols
|
||||||
unsigned char* buf=chanStream[h]->getFinalBuf();
|
unsigned char* buf=chanStream[h]->getFinalBuf();
|
||||||
for (size_t j=0; j<chanStream[h]->size();) {
|
for (size_t j=0; j<chanStream[h]->size(); j+=8) {
|
||||||
int insLen=getInsLength(buf[j],_EXT(buf,j,chanStream[h]->size()),sortedCmd);
|
|
||||||
if (insLen<1) {
|
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[j]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (buf[j]==0xf4) { // callsym
|
if (buf[j]==0xf4) { // callsym
|
||||||
unsigned int addr=buf[j+1]|(buf[j+2]<<8)|(buf[j+3]<<16)|(buf[j+4]<<24);
|
unsigned int addr=buf[j+1]|(buf[j+2]<<8)|(buf[j+3]<<16)|(buf[j+4]<<24);
|
||||||
if (addr<blockOff.size()) {
|
if (addr<blockOff.size()) {
|
||||||
// turn it into call
|
// turn it into call
|
||||||
addr=blockOff[addr];
|
addr=blockOff[addr];
|
||||||
if (addr<=0xffff) {
|
|
||||||
buf[j]=0xf8;
|
|
||||||
buf[j+1]=addr&0xff;
|
|
||||||
buf[j+2]=(addr>>8)&0xff;
|
|
||||||
buf[j+3]=0xf1;
|
|
||||||
buf[j+4]=0xf1;
|
|
||||||
} else {
|
|
||||||
buf[j]=0xf5;
|
buf[j]=0xf5;
|
||||||
buf[j+1]=addr&0xff;
|
buf[j+1]=addr&0xff;
|
||||||
buf[j+2]=(addr>>8)&0xff;
|
buf[j+2]=(addr>>8)&0xff;
|
||||||
buf[j+3]=(addr>>16)&0xff;
|
buf[j+3]=(addr>>16)&0xff;
|
||||||
buf[j+4]=(addr>>24)&0xff;
|
buf[j+4]=(addr>>24)&0xff;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
logE("requested symbol %d is out of bounds!",addr);
|
logE("requested symbol %d is out of bounds!",addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
j+=insLen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t afterSize=chanStream[h]->size();
|
size_t afterSize=chanStream[h]->size();
|
||||||
logI("(before: %d - after: %d)",(int)beforeSize,(int)afterSize);
|
logI("(before: %d - after: %d)",(int)beforeSize,(int)afterSize);
|
||||||
|
assert(!(chanStream[h]->size()&7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1193,6 +1234,11 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, unsigned int disable
|
||||||
chanStream[h]=stripNops(chanStream[h],sortedCmd);
|
chanStream[h]=stripNops(chanStream[h],sortedCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS 6: pack streams
|
||||||
|
for (int h=0; h<chans; h++) {
|
||||||
|
chanStream[h]=packStream(chanStream[h],sortedCmd);
|
||||||
|
}
|
||||||
|
|
||||||
// write results
|
// write results
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
chanStreamOff[i]=w->tell();
|
chanStreamOff[i]=w->tell();
|
||||||
|
|
|
@ -206,7 +206,7 @@ void FurnaceGUI::drawCSPlayer() {
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button(_("Burn Current Song"))) {
|
if (ImGui::Button(_("Burn Current Song"))) {
|
||||||
SafeWriter* w=e->saveCommand();
|
SafeWriter* w=e->saveCommand(NULL,csExportDisablePass);
|
||||||
if (w!=NULL) {
|
if (w!=NULL) {
|
||||||
if (!e->playStream(w->getFinalBuf(),w->size())) {
|
if (!e->playStream(w->getFinalBuf(),w->size())) {
|
||||||
showError(e->getLastError());
|
showError(e->getLastError());
|
||||||
|
@ -218,12 +218,21 @@ void FurnaceGUI::drawCSPlayer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||||
|
ImGui::OpenPopup("CSOptions");
|
||||||
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (e->isHalted()) {
|
if (e->isHalted()) {
|
||||||
if (ImGui::Button("Resume")) e->resume();
|
if (ImGui::Button("Resume")) e->resume();
|
||||||
} else {
|
} else {
|
||||||
if (ImGui::Button("Pause")) e->halt();
|
if (ImGui::Button("Pause")) e->halt();
|
||||||
}
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Button(_("Burn Options"));
|
||||||
|
if (ImGui::BeginPopupContextItem("CSOptions",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||||
|
commandExportOptions();
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
DivCSPlayer* cs=e->getStreamPlayer();
|
DivCSPlayer* cs=e->getStreamPlayer();
|
||||||
if (cs) {
|
if (cs) {
|
||||||
|
|
|
@ -380,16 +380,38 @@ void FurnaceGUI::drawExportText(bool onWindow) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FurnaceGUI::commandExportOptions() {
|
||||||
|
bool noCmdCallOpt=(csExportDisablePass&1);
|
||||||
|
bool noDelayCondense=(csExportDisablePass&2);
|
||||||
|
bool noSubBlock=(csExportDisablePass&4);
|
||||||
|
|
||||||
|
if (ImGui::Checkbox(_("Don't optimize command calls"),&noCmdCallOpt)) {
|
||||||
|
csExportDisablePass&=~1;
|
||||||
|
csExportDisablePass|=noCmdCallOpt?1:0;
|
||||||
|
}
|
||||||
|
if (ImGui::Checkbox(_("Don't condense delays"),&noDelayCondense)) {
|
||||||
|
csExportDisablePass&=~2;
|
||||||
|
csExportDisablePass|=noDelayCondense?2:0;
|
||||||
|
}
|
||||||
|
if (ImGui::Checkbox(_("Don't perform sub-block search"),&noSubBlock)) {
|
||||||
|
csExportDisablePass&=~4;
|
||||||
|
csExportDisablePass|=noSubBlock?4:0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FurnaceGUI::drawExportCommand(bool onWindow) {
|
void FurnaceGUI::drawExportCommand(bool onWindow) {
|
||||||
exitDisabledTimer=1;
|
exitDisabledTimer=1;
|
||||||
|
|
||||||
ImGui::Text(_(
|
ImGui::Text(_(
|
||||||
"this option exports a text or binary file which\n"
|
"this option exports a binary file which\n"
|
||||||
"contains a dump of the internal command stream\n"
|
"contains a dump of the internal command stream\n"
|
||||||
"produced when playing the song.\n\n"
|
"produced when playing the song.\n\n"
|
||||||
|
|
||||||
"technical/development use only!"
|
"technical/development use only!"
|
||||||
));
|
));
|
||||||
|
|
||||||
|
commandExportOptions();
|
||||||
|
|
||||||
if (onWindow) {
|
if (onWindow) {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::Button(_("Cancel"),ImVec2(200.0f*dpiScale,0))) ImGui::CloseCurrentPopup();
|
if (ImGui::Button(_("Cancel"),ImVec2(200.0f*dpiScale,0))) ImGui::CloseCurrentPopup();
|
||||||
|
|
|
@ -8877,6 +8877,7 @@ FurnaceGUI::FurnaceGUI():
|
||||||
curTutorialStep(0),
|
curTutorialStep(0),
|
||||||
dmfExportVersion(0),
|
dmfExportVersion(0),
|
||||||
curExportType(GUI_EXPORT_NONE),
|
curExportType(GUI_EXPORT_NONE),
|
||||||
|
csExportDisablePass(0),
|
||||||
romTarget(DIV_ROM_ABSTRACT),
|
romTarget(DIV_ROM_ABSTRACT),
|
||||||
romMultiFile(false),
|
romMultiFile(false),
|
||||||
romExportSave(false),
|
romExportSave(false),
|
||||||
|
|
|
@ -2761,6 +2761,8 @@ class FurnaceGUI {
|
||||||
DivAudioExportOptions audioExportOptions;
|
DivAudioExportOptions audioExportOptions;
|
||||||
int dmfExportVersion;
|
int dmfExportVersion;
|
||||||
FurnaceGUIExportTypes curExportType;
|
FurnaceGUIExportTypes curExportType;
|
||||||
|
unsigned int csExportDisablePass;
|
||||||
|
DivCSProgress csProgress;
|
||||||
|
|
||||||
// ROM export specific
|
// ROM export specific
|
||||||
DivROMExportOptions romTarget;
|
DivROMExportOptions romTarget;
|
||||||
|
@ -2778,6 +2780,8 @@ class FurnaceGUI {
|
||||||
|
|
||||||
std::vector<String> randomDemoSong;
|
std::vector<String> randomDemoSong;
|
||||||
|
|
||||||
|
void commandExportOptions();
|
||||||
|
|
||||||
void drawExportAudio(bool onWindow=false);
|
void drawExportAudio(bool onWindow=false);
|
||||||
void drawExportVGM(bool onWindow=false);
|
void drawExportVGM(bool onWindow=false);
|
||||||
void drawExportROM(bool onWindow=false);
|
void drawExportROM(bool onWindow=false);
|
||||||
|
|
Loading…
Reference in a new issue