-romout command line export

consolidate DivEngine::isROMExportViable function from FurnaceGUI::updateROMExportAvail to avoid copy-paste
This commit is contained in:
bbbradsmith 2024-12-13 03:44:52 -05:00 committed by tildearrow
parent addb50e384
commit 55a189444f
5 changed files with 118 additions and 51 deletions

View file

@ -81,6 +81,10 @@ the following parameters may be used:
- `-cmdout path`: output command stream dump to `path`.
- you must provide a file, otherwise Furnace will quit.
- `-romout path`: output ROM file export to `path`.
- you must provide a file, otherwise Furnace will quit.
- there must be an available ROM export target for the system.
- `-txtout path`: output text file export to `path`.
- you must provide a file, otherwise Furnace will quit.

View file

@ -908,6 +908,8 @@ class DivEngine {
// get ROM export definition
const DivROMExportDef* getROMExportDef(DivROMExportOptions opt);
// check whether ROM export option is viable for current song
bool isROMExportViable(DivROMExportOptions opt);
// convert sample rate format
int fileToDivRate(int frate);

View file

@ -25,6 +25,51 @@ const DivROMExportDef* DivEngine::getROMExportDef(DivROMExportOptions opt) {
return romExportDefs[opt];
}
bool DivEngine::isROMExportViable(DivROMExportOptions opt)
{
const DivROMExportDef* newDef=getROMExportDef(opt);
if (newDef==NULL) {
return false;
}
unsigned char sysReqCount[DIV_SYSTEM_MAX];
memset(sysReqCount,0,DIV_SYSTEM_MAX);
for (int i=0; i<song.systemLen; i++) {
sysReqCount[song.system[i]]++;
}
unsigned char defReqCount[DIV_SYSTEM_MAX];
memset(defReqCount,0,DIV_SYSTEM_MAX);
for (DivSystem j: newDef->requisites) {
defReqCount[j]++;
}
switch (newDef->requisitePolicy) {
case DIV_REQPOL_EXACT:
for (int j=0; j<DIV_SYSTEM_MAX; j++) {
if (defReqCount[j]!=sysReqCount[j]) {
return false;
}
}
break;
case DIV_REQPOL_ANY:
for (int j=0; j<DIV_SYSTEM_MAX; j++) {
if (defReqCount[j]>sysReqCount[j]) {
return false;
}
}
break;
case DIV_REQPOL_LAX:
for (DivSystem j: newDef->requisites) {
if (defReqCount[j]<=sysReqCount[j]) {
return true;
}
}
return false;
}
return true;
}
void DivEngine::registerROMExports() {
logD("registering ROM exports...");

View file

@ -769,60 +769,13 @@ void FurnaceGUI::autoDetectSystem() {
}
void FurnaceGUI::updateROMExportAvail() {
unsigned char sysReqCount[DIV_SYSTEM_MAX];
unsigned char defReqCount[DIV_SYSTEM_MAX];
memset(sysReqCount,0,DIV_SYSTEM_MAX);
for (int i=0; i<e->song.systemLen; i++) {
sysReqCount[e->song.system[i]]++;
}
memset(romExportAvail,0,sizeof(bool)*DIV_ROM_MAX);
romExportExists=false;
for (int i=0; i<DIV_ROM_MAX; i++) {
const DivROMExportDef* newDef=e->getROMExportDef((DivROMExportOptions)i);
if (newDef!=NULL) {
// check for viability
bool viable=true;
memset(defReqCount,0,DIV_SYSTEM_MAX);
for (DivSystem j: newDef->requisites) {
defReqCount[j]++;
}
switch (newDef->requisitePolicy) {
case DIV_REQPOL_EXACT:
for (int j=0; j<DIV_SYSTEM_MAX; j++) {
if (defReqCount[j]!=sysReqCount[j]) {
viable=false;
break;
}
}
break;
case DIV_REQPOL_ANY:
for (int j=0; j<DIV_SYSTEM_MAX; j++) {
if (defReqCount[j]>sysReqCount[j]) {
viable=false;
break;
}
}
break;
case DIV_REQPOL_LAX:
viable=false;
for (DivSystem j: newDef->requisites) {
if (defReqCount[j]<=sysReqCount[j]) {
viable=true;
break;
}
}
break;
}
if (viable) {
romExportAvail[i]=true;
romExportExists=true;
}
if (e->isROMExportViable((DivROMExportOptions)i)) {
romExportAvail[i]=true;
romExportExists=true;
}
}

View file

@ -86,6 +86,7 @@ FurnaceCLI cli;
String outName;
String vgmOutName;
String cmdOutName;
String romOutName;
String txtOutName;
int benchMode=0;
int subsong=-1;
@ -438,6 +439,12 @@ TAParamResult pCmdOut(String val) {
return TA_PARAM_SUCCESS;
}
TAParamResult pROMOut(String val) {
romOutName=val;
e.setAudio(DIV_AUDIO_DUMMY);
return TA_PARAM_SUCCESS;
}
TAParamResult pTxtOut(String val) {
txtOutName=val;
e.setAudio(DIV_AUDIO_DUMMY);
@ -461,6 +468,7 @@ void initParams() {
params.push_back(TAParam("O","vgmout",true,pVGMOut,"<filename>","output .vgm data"));
params.push_back(TAParam("D","direct",false,pDirect,"","set VGM export direct stream mode"));
params.push_back(TAParam("C","cmdout",true,pCmdOut,"<filename>","output command stream"));
params.push_back(TAParam("r","romout",true,pROMOut,"<filename>","export ROM file"));
params.push_back(TAParam("t","txtout",true,pTxtOut,"<filename>","export as text file"));
params.push_back(TAParam("L","loglevel",true,pLogLevel,"debug|info|warning|error","set the log level (info by default)"));
params.push_back(TAParam("v","view",true,pView,"pattern|commands|nothing","set visualization (nothing by default)"));
@ -557,6 +565,7 @@ int main(int argc, char** argv) {
outName="";
vgmOutName="";
cmdOutName="";
romOutName="";
txtOutName="";
// load config for locale
@ -725,7 +734,7 @@ int main(int argc, char** argv) {
return 1;
}
const bool outputMode = outName!="" || vgmOutName!="" || cmdOutName!="" || txtOutName!="";
const bool outputMode = outName!="" || vgmOutName!="" || cmdOutName!="" || romOutName!="" || txtOutName!="";
if (fileName.empty() && (benchMode || infoMode || outputMode)) {
logE("provide a file!");
@ -893,6 +902,60 @@ int main(int argc, char** argv) {
e.saveAudio(outName.c_str(),exportOptions);
e.waitAudioFile();
}
if (romOutName!="") {
e.setConsoleMode(true);
// select ROM target type
DivROMExportOptions romTarget = DIV_ROM_ABSTRACT;
for (int i=0; i<DIV_ROM_MAX; i++) {
DivROMExportOptions opt = (DivROMExportOptions)i;
if (e.isROMExportViable(opt)) {
const DivROMExportDef* newDef=e.getROMExportDef((DivROMExportOptions)i);
if (newDef->fileExt &&
romOutName.length()>=strlen(newDef->fileExt) &&
!stricmp(newDef->fileExt,romOutName.c_str()+(romOutName.length()-strlen(newDef->fileExt)))) {
romTarget = opt;
break; // extension matched, stop searching
}
if (romTarget == DIV_ROM_ABSTRACT) {
romTarget = opt; // use first viable, but keep searching for extension match
}
}
}
if (romTarget > DIV_ROM_ABSTRACT && romTarget < DIV_ROM_MAX) {
DivConfig romConfig; // TODO: no current way to pass config, maybe serialize them to .fur file?
DivROMExport* pendingExport = e.buildROM(romTarget);
if (pendingExport==NULL) {
reportError(_("could not create exporter! you may want to report this issue..."));
} else {
pendingExport->setConf(romConfig);
if (pendingExport->go(&e)) {
pendingExport->wait();
if (!pendingExport->hasFailed()) {
for (DivROMExportOutput& i: pendingExport->getResult()) {
String path=romOutName;
if (e.getROMExportDef(romTarget)->multiOutput) {
path+=DIR_SEPARATOR_STR;
path+=i.name;
}
FILE* f=ps_fopen(path.c_str(),"wb");
if (f!=NULL) {
fwrite(i.data->getFinalBuf(),1,i.data->size(),f);
fclose(f);
} else {
reportError(fmt::sprintf(_("could not open file! (%s)"),strerror(errno)));
}
}
} else {
reportError(fmt::sprintf(_("ROM export failed! (%s)"),e.getLastError()));
}
} else {
reportError(_("could not begin exporting process! TODO: elaborate"));
}
}
} else {
reportError(_("no matching ROM export target is available."));
}
}
if (txtOutName!="") {
e.setConsoleMode(true);
SafeWriter* w=e.saveText(false);