This commit is contained in:
tildearrow 2025-04-07 04:33:28 -05:00
parent 27cde60f0b
commit 873bad1613
5 changed files with 269 additions and 187 deletions

View file

@ -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]=0xf5;
buf[j]=0xf8; 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]=0xf1; buf[j+4]=(addr>>24)&0xff;
buf[j+4]=0xf1;
} else {
buf[j]=0xf5;
buf[j+1]=addr&0xff;
buf[j+2]=(addr>>8)&0xff;
buf[j+3]=(addr>>16)&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();

View file

@ -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) {

View file

@ -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();

View file

@ -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),

View file

@ -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);