port TIunA to export framework, part 1

part 2 includes progress bars and options
This commit is contained in:
tildearrow 2024-08-13 16:50:13 -05:00
parent aad42210d7
commit bb5ad38fb6
12 changed files with 318 additions and 318 deletions

View file

@ -711,7 +711,6 @@ src/engine/wavOps.cpp
src/engine/vgmOps.cpp src/engine/vgmOps.cpp
src/engine/zsmOps.cpp src/engine/zsmOps.cpp
src/engine/zsm.cpp src/engine/zsm.cpp
src/engine/tiunaOps.cpp
src/engine/platform/abstract.cpp src/engine/platform/abstract.cpp
src/engine/platform/genesis.cpp src/engine/platform/genesis.cpp
@ -789,6 +788,7 @@ src/engine/platform/dummy.cpp
src/engine/export/abstract.cpp src/engine/export/abstract.cpp
src/engine/export/amigaValidation.cpp src/engine/export/amigaValidation.cpp
src/engine/export/tiuna.cpp
src/engine/effect/abstract.cpp src/engine/effect/abstract.cpp
src/engine/effect/dummy.cpp src/engine/effect/dummy.cpp

View file

@ -3589,6 +3589,12 @@ void DivEngine::synchronized(const std::function<void()>& what) {
BUSY_END; BUSY_END;
} }
void DivEngine::synchronizedSoft(const std::function<void()>& what) {
BUSY_BEGIN_SOFT;
what();
BUSY_END;
}
void DivEngine::lockSave(const std::function<void()>& what) { void DivEngine::lockSave(const std::function<void()>& what) {
saveLock.lock(); saveLock.lock();
what(); what();

View file

@ -657,6 +657,7 @@ class DivEngine {
// add every export method here // add every export method here
friend class DivROMExport; friend class DivROMExport;
friend class DivExportAmigaValidation; friend class DivExportAmigaValidation;
friend class DivExportTiuna;
public: public:
DivSong song; DivSong song;
@ -1299,6 +1300,9 @@ class DivEngine {
// perform secure/sync operation // perform secure/sync operation
void synchronized(const std::function<void()>& what); void synchronized(const std::function<void()>& what);
// perform secure/sync operation (soft)
void synchronizedSoft(const std::function<void()>& what);
// perform secure/sync song operation // perform secure/sync song operation
void lockSave(const std::function<void()>& what); void lockSave(const std::function<void()>& what);

View file

@ -20,6 +20,7 @@
#include "engine.h" #include "engine.h"
#include "export/amigaValidation.h" #include "export/amigaValidation.h"
#include "export/tiuna.h"
DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) {
DivROMExport* exporter=NULL; DivROMExport* exporter=NULL;
@ -27,6 +28,9 @@ DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) {
case DIV_ROM_AMIGA_VALIDATION: case DIV_ROM_AMIGA_VALIDATION:
exporter=new DivExportAmigaValidation; exporter=new DivExportAmigaValidation;
break; break;
case DIV_ROM_TIUNA:
exporter=new DivExportTiuna;
break;
default: default:
exporter=new DivROMExport; exporter=new DivROMExport;
break; break;

View file

@ -72,6 +72,8 @@ class DivROMExport {
virtual ~DivROMExport() {} virtual ~DivROMExport() {}
}; };
#define logAppendf(...) logAppend(fmt::sprintf(__VA_ARGS__))
enum DivROMExportReqPolicy { enum DivROMExportReqPolicy {
// exactly these chips. // exactly these chips.
DIV_REQPOL_EXACT=0, DIV_REQPOL_EXACT=0,
@ -85,14 +87,18 @@ struct DivROMExportDef {
const char* name; const char* name;
const char* author; const char* author;
const char* description; const char* description;
const char* fileType;
const char* fileExt;
std::vector<DivSystem> requisites; std::vector<DivSystem> requisites;
bool multiOutput; bool multiOutput;
DivROMExportReqPolicy requisitePolicy; DivROMExportReqPolicy requisitePolicy;
DivROMExportDef(const char* n, const char* a, const char* d, std::initializer_list<DivSystem> req, bool multiOut, DivROMExportReqPolicy reqPolicy): DivROMExportDef(const char* n, const char* a, const char* d, const char* ft, const char* fe, std::initializer_list<DivSystem> req, bool multiOut, DivROMExportReqPolicy reqPolicy):
name(n), name(n),
author(a), author(a),
description(d), description(d),
fileType(ft),
fileExt(fe),
multiOutput(multiOut), multiOutput(multiOut),
requisitePolicy(reqPolicy) { requisitePolicy(reqPolicy) {
requisites=req; requisites=req;

View file

@ -17,13 +17,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "tiuna.h"
#include "../engine.h"
#include "../ta-log.h"
#include <fmt/printf.h>
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "engine.h"
#include "../fileutils.h"
#include "../ta-log.h"
struct TiunaNew { struct TiunaNew {
short pitch; short pitch;
@ -180,140 +181,156 @@ static void writeCmd(std::vector<TiunaBytes>& cmds, TiunaCmd& cmd, unsigned char
} }
} }
SafeWriter* DivEngine::saveTiuna(const bool* sysToExport, const char* baseLabel, int firstBankSize, int otherBankSize) { void DivExportTiuna::run() {
stop(); int loopOrder, loopOrderRow, loopEnd;
repeatPattern=false; int tiaIdx;
shallStop=false;
setOrder(0);
BUSY_BEGIN_SOFT;
// determine loop point
// bool stopped=false;
int loopOrder=0;
int loopOrderRow=0;
int loopEnd=0;
walkSong(loopOrder,loopOrderRow,loopEnd);
logI("loop point: %d %d",loopOrder,loopOrderRow);
SafeWriter* w=new SafeWriter;
w->init();
int tiaIdx=-1;
for (int i=0; i<song.systemLen; i++) {
if (sysToExport!=NULL && !sysToExport[i]) continue;
if (song.system[i]==DIV_SYSTEM_TIA) {
tiaIdx=i;
disCont[i].dispatch->toggleRegisterDump(true);
break;
}
}
if (tiaIdx<0) {
lastError="selected TIA system not found";
return NULL;
}
// write patterns
// bool writeLoop=false;
bool done=false;
playSub(false);
int tick=0; int tick=0;
// int loopTick=-1; SafeWriter* w;
TiunaLast last[2];
TiunaNew news[2];
std::map<int,TiunaCmd> allCmds[2]; std::map<int,TiunaCmd> allCmds[2];
while (!done) {
// TODO implement loop
// if (loopTick<0 && loopOrder==curOrder && loopOrderRow==curRow
// && (ticks-((tempoAccum+virtualTempoN)/virtualTempoD))<=0
// ) {
// writeLoop=true;
// loopTick=tick;
// // invalidate last register state so it always force an absolute write after loop
// for (int i=0; i<2; i++) {
// last[i]=TiunaLast();
// last[i].pitch=-1;
// last[i].ins=-1;
// last[i].vol=-1;
// }
// }
if (nextTick(false,true) || !playing) {
// stopped=!playing;
done=true;
break;
}
for (int i=0; i<2; i++) {
news[i]=TiunaNew();
}
// get register dumps
std::vector<DivRegWrite>& writes=disCont[tiaIdx].dispatch->getRegisterWrites();
for (const DivRegWrite& i: writes) {
switch (i.addr) {
case 0xfffe0000:
case 0xfffe0001:
news[i.addr&1].pitch=i.val;
break;
case 0xfffe0002:
news[0].sync=i.val;
break;
case 0x15:
case 0x16:
news[i.addr-0x15].ins=i.val;
break;
case 0x19:
case 0x1a:
news[i.addr-0x19].vol=i.val;
break;
default: break;
}
}
writes.clear();
// collect changes
for (int i=0; i<2; i++) {
TiunaCmd cmds;
bool hasCmd=false;
if (news[i].pitch>=0 && (last[i].forcePitch || news[i].pitch!=last[i].pitch)) {
int dt=news[i].pitch-last[i].pitch;
if (!last[i].forcePitch && abs(dt)<=16) {
if (dt<0) cmds.pitchChange=15-dt;
else cmds.pitchChange=dt-1;
}
else cmds.pitchSet=news[i].pitch;
last[i].pitch=news[i].pitch;
last[i].forcePitch=false;
hasCmd=true;
}
if (news[i].ins>=0 && news[i].ins!=last[i].ins) {
cmds.ins=news[i].ins;
last[i].ins=news[i].ins;
hasCmd=true;
}
if (news[i].vol>=0 && news[i].vol!=last[i].vol) {
cmds.vol=(news[i].vol-last[i].vol)&0xf;
last[i].vol=news[i].vol;
hasCmd=true;
}
if (news[i].sync>=0) {
cmds.sync=news[i].sync;
hasCmd=true;
}
if (hasCmd) allCmds[i][tick]=cmds;
}
cmdStream.clear();
tick++;
}
for (int i=0; i<song.systemLen; i++) {
disCont[i].dispatch->getRegisterWrites().clear();
disCont[i].dispatch->toggleRegisterDump(false);
}
remainingLoops=-1; // config
playing=false; int* sysToExport=NULL;
freelance=false; String baseLabel=conf.getString("baseLabel","song");
extValuePresent=false; int firstBankSize=conf.getInt("firstBankSize",3072);
BUSY_END; int otherBankSize=conf.getInt("otherBankSize",4096-48);
e->stop();
e->repeatPattern=false;
e->shallStop=false;
e->setOrder(0);
e->synchronizedSoft([&]() {
// determine loop point
// bool stopped=false;
loopOrder=0;
loopOrderRow=0;
loopEnd=0;
e->walkSong(loopOrder,loopOrderRow,loopEnd);
logAppendf("loop point: %d %d",loopOrder,loopOrderRow);
w=new SafeWriter;
w->init();
tiaIdx=-1;
for (int i=0; i<e->song.systemLen; i++) {
if (sysToExport!=NULL && !sysToExport[i]) continue;
if (e->song.system[i]==DIV_SYSTEM_TIA) {
tiaIdx=i;
e->disCont[i].dispatch->toggleRegisterDump(true);
break;
}
}
if (tiaIdx<0) {
logAppend("ERROR: selected TIA system not found");
failed=true;
running=false;
return;
}
// write patterns
// bool writeLoop=false;
logAppend("recording sequence...");
bool done=false;
e->playSub(false);
// int loopTick=-1;
TiunaLast last[2];
TiunaNew news[2];
while (!done) {
// TODO implement loop
// if (loopTick<0 && loopOrder==curOrder && loopOrderRow==curRow
// && (ticks-((tempoAccum+virtualTempoN)/virtualTempoD))<=0
// ) {
// writeLoop=true;
// loopTick=tick;
// // invalidate last register state so it always force an absolute write after loop
// for (int i=0; i<2; i++) {
// last[i]=TiunaLast();
// last[i].pitch=-1;
// last[i].ins=-1;
// last[i].vol=-1;
// }
// }
if (e->nextTick(false,true) || !e->playing) {
// stopped=!playing;
done=true;
break;
}
for (int i=0; i<2; i++) {
news[i]=TiunaNew();
}
// get register dumps
std::vector<DivRegWrite>& writes=e->disCont[tiaIdx].dispatch->getRegisterWrites();
for (const DivRegWrite& i: writes) {
switch (i.addr) {
case 0xfffe0000:
case 0xfffe0001:
news[i.addr&1].pitch=i.val;
break;
case 0xfffe0002:
news[0].sync=i.val;
break;
case 0x15:
case 0x16:
news[i.addr-0x15].ins=i.val;
break;
case 0x19:
case 0x1a:
news[i.addr-0x19].vol=i.val;
break;
default: break;
}
}
writes.clear();
// collect changes
for (int i=0; i<2; i++) {
TiunaCmd cmds;
bool hasCmd=false;
if (news[i].pitch>=0 && (last[i].forcePitch || news[i].pitch!=last[i].pitch)) {
int dt=news[i].pitch-last[i].pitch;
if (!last[i].forcePitch && abs(dt)<=16) {
if (dt<0) cmds.pitchChange=15-dt;
else cmds.pitchChange=dt-1;
}
else cmds.pitchSet=news[i].pitch;
last[i].pitch=news[i].pitch;
last[i].forcePitch=false;
hasCmd=true;
}
if (news[i].ins>=0 && news[i].ins!=last[i].ins) {
cmds.ins=news[i].ins;
last[i].ins=news[i].ins;
hasCmd=true;
}
if (news[i].vol>=0 && news[i].vol!=last[i].vol) {
cmds.vol=(news[i].vol-last[i].vol)&0xf;
last[i].vol=news[i].vol;
hasCmd=true;
}
if (news[i].sync>=0) {
cmds.sync=news[i].sync;
hasCmd=true;
}
if (hasCmd) allCmds[i][tick]=cmds;
}
e->cmdStream.clear();
tick++;
}
for (int i=0; i<e->song.systemLen; i++) {
e->disCont[i].dispatch->getRegisterWrites().clear();
e->disCont[i].dispatch->toggleRegisterDump(false);
}
e->remainingLoops=-1;
e->playing=false;
e->freelance=false;
e->extValuePresent=false;
});
if (failed) return;
// render commands // render commands
logAppend("rendering commands...");
std::vector<TiunaBytes> renderedCmds; std::vector<TiunaBytes> renderedCmds;
w->writeText(fmt::format( w->writeText(fmt::format(
"; Generated by Furnace " DIV_VERSION "\n" "; Generated by Furnace " DIV_VERSION "\n"
@ -321,7 +338,7 @@ SafeWriter* DivEngine::saveTiuna(const bool* sysToExport, const char* baseLabel,
"; Author: {}\n" "; Author: {}\n"
"; Album: {}\n" "; Album: {}\n"
"; Subsong #{}: {}\n\n", "; Subsong #{}: {}\n\n",
song.name,song.author,song.category,curSubSongIndex+1,curSubSong->name e->song.name,e->song.author,e->song.category,e->curSubSongIndex+1,e->curSubSong->name
)); ));
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
TiunaCmd lastCmd; TiunaCmd lastCmd;
@ -349,11 +366,20 @@ SafeWriter* DivEngine::saveTiuna(const bool* sysToExport, const char* baseLabel,
int cmdSize=renderedCmds.size(); int cmdSize=renderedCmds.size();
bool* processed=new bool[cmdSize]; bool* processed=new bool[cmdSize];
memset(processed,0,cmdSize*sizeof(bool)); memset(processed,0,cmdSize*sizeof(bool));
logI("max cmId: %d",(MAX(firstBankSize/1024,1))*256); logAppend("compressing! this may take a while.");
logAppendf("max cmId: %d",(MAX(firstBankSize/1024,1))*256);
while (firstBankSize>768 && cmId<(MAX(firstBankSize/1024,1))*256) { while (firstBankSize>768 && cmId<(MAX(firstBankSize/1024,1))*256) {
logI("start CM %04x...",cmId); if (mustAbort) {
logAppend("aborted!");
failed=true;
running=false;
delete[] processed;
return;
}
logAppendf("start CM %04x...",cmId);
std::map<int,TiunaMatches> potentialMatches; std::map<int,TiunaMatches> potentialMatches;
logD("scan %d size...",cmdSize-1); logAppendf("scan %d size...",cmdSize-1);
for (int i=0; i<cmdSize-1;) { for (int i=0; i<cmdSize-1;) {
// continue and skip if it's part of previous confirmed matches // continue and skip if it's part of previous confirmed matches
while (i<cmdSize-1 && processed[i]) i++; while (i<cmdSize-1 && processed[i]) i++;
@ -427,12 +453,12 @@ SafeWriter* DivEngine::saveTiuna(const bool* sysToExport, const char* baseLabel,
i++; i++;
} }
if (potentialMatches.empty()) { if (potentialMatches.empty()) {
logV("potentialMatches is empty"); logAppend("potentialMatches is empty");
break; break;
} }
int maxPMIdx=0; int maxPMIdx=0;
int maxPMVal=0; int maxPMVal=0;
logV("looking through potentialMatches..."); logAppend("looking through potentialMatches...");
for (const auto& i: potentialMatches) { for (const auto& i: potentialMatches) {
if (i.second.bytesSaved>maxPMVal) { if (i.second.bytesSaved>maxPMVal) {
maxPMVal=i.second.bytesSaved; maxPMVal=i.second.bytesSaved;
@ -440,16 +466,16 @@ SafeWriter* DivEngine::saveTiuna(const bool* sysToExport, const char* baseLabel,
} }
} }
int maxPMLen=potentialMatches[maxPMIdx].length; int maxPMLen=potentialMatches[maxPMIdx].length;
logV("the other step...");
for (const int i: potentialMatches[maxPMIdx].pos) { for (const int i: potentialMatches[maxPMIdx].pos) {
confirmedMatches.push_back({i,i+maxPMLen,0,cmId}); confirmedMatches.push_back({i,i+maxPMLen,0,cmId});
memset(processed+i,1,maxPMLen); memset(processed+i,1,maxPMLen);
//std::fill(processed.begin()+i,processed.begin()+(i+maxPMLen),true); //std::fill(processed.begin()+i,processed.begin()+(i+maxPMLen),true);
} }
callTicks.push_back(potentialMatches[maxPMIdx].ticks); callTicks.push_back(potentialMatches[maxPMIdx].ticks);
logI("CM %04x added: pos=%d,len=%d,matches=%d,saved=%d",cmId,maxPMIdx,maxPMLen,potentialMatches[maxPMIdx].pos.size(),maxPMVal); logAppendf("CM %04x added: pos=%d,len=%d,matches=%d,saved=%d",cmId,maxPMIdx,maxPMLen,potentialMatches[maxPMIdx].pos.size(),maxPMVal);
cmId++; cmId++;
} }
logAppend("generating data...");
delete[] processed; delete[] processed;
std::sort(confirmedMatches.begin(),confirmedMatches.end(),[](const TiunaMatch& l, const TiunaMatch& r){ std::sort(confirmedMatches.begin(),confirmedMatches.end(),[](const TiunaMatch& l, const TiunaMatch& r){
return l.pos<r.pos; return l.pos<r.pos;
@ -460,8 +486,10 @@ SafeWriter* DivEngine::saveTiuna(const bool* sysToExport, const char* baseLabel,
// overlap check // overlap check
for (int i=1; i<(int)confirmedMatches.size(); i++) { for (int i=1; i<(int)confirmedMatches.size(); i++) {
if (confirmedMatches[i-1].endPos<=confirmedMatches[i].pos) continue; if (confirmedMatches[i-1].endPos<=confirmedMatches[i].pos) continue;
lastError="impossible overlap found in matches list, please report"; logAppend("ERROR: impossible overlap found in matches list, please report");
return NULL; failed=true;
running=false;
return;
} }
SafeWriter dbg; SafeWriter dbg;
dbg.init(); dbg.init();
@ -510,8 +538,10 @@ SafeWriter* DivEngine::saveTiuna(const bool* sysToExport, const char* baseLabel,
} }
w->writeC('\n'); w->writeC('\n');
if (totalSize>firstBankSize) { if (totalSize>firstBankSize) {
lastError="first bank is not large enough to contain call table"; logAppend("ERROR: first bank is not large enough to contain call table");
return NULL; failed=true;
running=false;
return;
} }
int curBank=0; int curBank=0;
@ -572,13 +602,40 @@ SafeWriter* DivEngine::saveTiuna(const bool* sysToExport, const char* baseLabel,
} }
w->writeText(" .text x\"e0\"\n .endsection\n"); w->writeText(" .text x\"e0\"\n .endsection\n");
totalSize++; totalSize++;
logI("total size: %d bytes (%d banks)",totalSize,curBank+1); logAppendf("total size: %d bytes (%d banks)",totalSize,curBank+1);
//FILE* f=ps_fopen("confirmedMatches.txt","wb"); output.push_back(DivROMExportOutput("export.asm",w));
//if (f!=NULL) {
// fwrite(dbg.getFinalBuf(),1,dbg.size(),f);
// fclose(f);
//}
return w; logAppend("finished!");
running=false;
}
bool DivExportTiuna::go(DivEngine* eng) {
e=eng;
running=true;
failed=false;
mustAbort=false;
exportThread=new std::thread(&DivExportTiuna::run,this);
return true;
}
void DivExportTiuna::wait() {
if (exportThread!=NULL) {
exportThread->join();
delete exportThread;
}
}
void DivExportTiuna::abort() {
mustAbort=true;
wait();
}
bool DivExportTiuna::isRunning() {
return running;
}
bool DivExportTiuna::hasFailed() {
return failed;
} }

36
src/engine/export/tiuna.h Normal file
View file

@ -0,0 +1,36 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../export.h"
#include <thread>
class DivExportTiuna: public DivROMExport {
DivEngine* e;
std::thread* exportThread;
bool running, failed, mustAbort;
void run();
public:
bool go(DivEngine* e);
bool isRunning();
bool hasFailed();
void abort();
void wait();
~DivExportTiuna() {}
};

View file

@ -31,6 +31,7 @@ void DivEngine::registerROMExports() {
romExportDefs[DIV_ROM_AMIGA_VALIDATION]=new DivROMExportDef( romExportDefs[DIV_ROM_AMIGA_VALIDATION]=new DivROMExportDef(
"Amiga Validation", "tildearrow", "Amiga Validation", "tildearrow",
"a test export for ensuring Amiga emulation is accurate. do not use!", "a test export for ensuring Amiga emulation is accurate. do not use!",
NULL, NULL,
{DIV_SYSTEM_AMIGA}, {DIV_SYSTEM_AMIGA},
true, DIV_REQPOL_EXACT true, DIV_REQPOL_EXACT
); );
@ -42,19 +43,21 @@ void DivEngine::registerROMExports() {
"- https://github.com/mooinglemur/zsmkit (development)\n" "- https://github.com/mooinglemur/zsmkit (development)\n"
"- https://github.com/mooinglemur/melodius (player)\n" "- https://github.com/mooinglemur/melodius (player)\n"
"- https://github.com/ZeroByteOrg/calliope (player)\n", "- https://github.com/ZeroByteOrg/calliope (player)\n",
"ZSM file", ".zsm",
{ {
DIV_SYSTEM_YM2151, DIV_SYSTEM_VERA DIV_SYSTEM_YM2151, DIV_SYSTEM_VERA
}, },
true, DIV_REQPOL_LAX false, DIV_REQPOL_LAX
); );
romExportDefs[DIV_ROM_TIUNA]=new DivROMExportDef( romExportDefs[DIV_ROM_TIUNA]=new DivROMExportDef(
"Atari 2600 (TIunA)", "Natt Akuma", "Atari 2600 (TIunA)", "Natt Akuma",
"advanced driver with software tuning support.\n" "advanced driver with software tuning support.\n"
"see https://github.com/AYCEdemo/twin-tiuna for code.", "see https://github.com/AYCEdemo/twin-tiuna for code.",
"assembly files", ".asm",
{ {
DIV_SYSTEM_TIA DIV_SYSTEM_TIA
}, },
true, DIV_REQPOL_ANY false, DIV_REQPOL_ANY
); );
} }

View file

@ -252,6 +252,13 @@ void FurnaceGUI::drawExportROM(bool onWindow) {
if (ImGui::Selectable(newDef->name)) { if (ImGui::Selectable(newDef->name)) {
romTarget=(DivROMExportOptions)i; romTarget=(DivROMExportOptions)i;
romMultiFile=newDef->multiOutput; romMultiFile=newDef->multiOutput;
if (newDef->fileExt==NULL) {
romFilterName="";
romFilterExt="";
} else {
romFilterName=newDef->fileType;
romFilterExt=newDef->fileExt;
}
} }
} }
} }
@ -264,6 +271,36 @@ void FurnaceGUI::drawExportROM(bool onWindow) {
ImGui::TextWrapped("%s",def->description); ImGui::TextWrapped("%s",def->description);
} }
/*
ImGui::InputText(_("base song label name"),&asmBaseLabel); // TODO: validate label
if (ImGui::InputInt(_("max size in first bank"),&tiunaFirstBankSize,1,100)) {
if (tiunaFirstBankSize<0) tiunaFirstBankSize=0;
if (tiunaFirstBankSize>4096) tiunaFirstBankSize=4096;
}
if (ImGui::InputInt(_("max size in other banks"),&tiunaOtherBankSize,1,100)) {
if (tiunaOtherBankSize<16) tiunaOtherBankSize=16;
if (tiunaOtherBankSize>4096) tiunaOtherBankSize=4096;
}
ImGui::Text(_("chips to export:"));
int selected=0;
for (int i=0; i<e->song.systemLen; i++) {
DivSystem sys=e->song.system[i];
bool isTIA=sys==DIV_SYSTEM_TIA;
ImGui::BeginDisabled((!isTIA) || (selected>=1));
ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i]);
ImGui::EndDisabled();
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
if (!isTIA) {
ImGui::SetTooltip(_("this chip is not supported by the file format!"));
} else if (selected>=1) {
ImGui::SetTooltip(_("only one Atari TIA is supported!"));
}
}
if (isTIA && willExport[i]) selected++;
}
*/
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();
@ -297,56 +334,6 @@ void FurnaceGUI::drawExportZSM(bool onWindow) {
} }
} }
void FurnaceGUI::drawExportTiuna(bool onWindow) {
exitDisabledTimer=1;
ImGui::Text(_("for use with TIunA driver. outputs asm source."));
ImGui::InputText(_("base song label name"),&asmBaseLabel); // TODO: validate label
if (ImGui::InputInt(_("max size in first bank"),&tiunaFirstBankSize,1,100)) {
if (tiunaFirstBankSize<0) tiunaFirstBankSize=0;
if (tiunaFirstBankSize>4096) tiunaFirstBankSize=4096;
}
if (ImGui::InputInt(_("max size in other banks"),&tiunaOtherBankSize,1,100)) {
if (tiunaOtherBankSize<16) tiunaOtherBankSize=16;
if (tiunaOtherBankSize>4096) tiunaOtherBankSize=4096;
}
ImGui::Text(_("chips to export:"));
int selected=0;
for (int i=0; i<e->song.systemLen; i++) {
DivSystem sys=e->song.system[i];
bool isTIA=sys==DIV_SYSTEM_TIA;
ImGui::BeginDisabled((!isTIA) || (selected>=1));
ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i]);
ImGui::EndDisabled();
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
if (!isTIA) {
ImGui::SetTooltip(_("this chip is not supported by the file format!"));
} else if (selected>=1) {
ImGui::SetTooltip(_("only one Atari TIA is supported!"));
}
}
if (isTIA && willExport[i]) selected++;
}
if (selected>0) {
if (onWindow) {
ImGui::Separator();
if (ImGui::Button(_("Cancel"),ImVec2(200.0f*dpiScale,0))) ImGui::CloseCurrentPopup();
ImGui::SameLine();
}
if (ImGui::Button(_("Export"),ImVec2(200.0f*dpiScale,0))) {
openFileDialog(GUI_FILE_EXPORT_TIUNA);
ImGui::CloseCurrentPopup();
}
} else {
ImGui::Text(_("nothing to export"));
if (onWindow) {
ImGui::Separator();
if (ImGui::Button(_("Cancel"),ImVec2(400.0f*dpiScale,0))) ImGui::CloseCurrentPopup();
}
}
}
void FurnaceGUI::drawExportText(bool onWindow) { void FurnaceGUI::drawExportText(bool onWindow) {
exitDisabledTimer=1; exitDisabledTimer=1;
@ -437,19 +424,6 @@ void FurnaceGUI::drawExport() {
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
} }
bool hasTiunaCompat=false;
for (int i=0; i<e->song.systemLen; i++) {
if (e->song.system[i]==DIV_SYSTEM_TIA) {
hasTiunaCompat=true;
break;
}
}
if (hasTiunaCompat) {
if (ImGui::BeginTabItem("TIunA")) {
drawExportTiuna(true);
ImGui::EndTabItem();
}
}
if (ImGui::BeginTabItem(_("Text"))) { if (ImGui::BeginTabItem(_("Text"))) {
drawExportText(true); drawExportText(true);
ImGui::EndTabItem(); ImGui::EndTabItem();
@ -477,9 +451,6 @@ void FurnaceGUI::drawExport() {
case GUI_EXPORT_ZSM: case GUI_EXPORT_ZSM:
drawExportZSM(true); drawExportZSM(true);
break; break;
case GUI_EXPORT_TIUNA:
drawExportTiuna(true);
break;
case GUI_EXPORT_TEXT: case GUI_EXPORT_TEXT:
drawExportText(true); drawExportText(true);
break; break;

View file

@ -1950,15 +1950,6 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
(settings.autoFillSave)?shortName:"" (settings.autoFillSave)?shortName:""
); );
break; break;
case GUI_FILE_EXPORT_TIUNA:
if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir();
hasOpened=fileDialog->openSave(
"Export TIunA",
{"assembly files", "*.asm"},
workingDirROMExport,
dpiScale
);
break;
case GUI_FILE_EXPORT_TEXT: case GUI_FILE_EXPORT_TEXT:
if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir(); if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir();
hasOpened=fileDialog->openSave( hasOpened=fileDialog->openSave(
@ -1990,7 +1981,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
} else { } else {
hasOpened=fileDialog->openSave( hasOpened=fileDialog->openSave(
_("Export ROM"), _("Export ROM"),
{romFilterName, romFilterExt}, {romFilterName, "*"+romFilterExt},
workingDirROMExport, workingDirROMExport,
dpiScale, dpiScale,
(settings.autoFillSave)?shortName:"" (settings.autoFillSave)?shortName:""
@ -4324,19 +4315,6 @@ bool FurnaceGUI::loop() {
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
bool hasTiunaCompat=false;
for (int i=0; i<e->song.systemLen; i++) {
if (e->song.system[i]==DIV_SYSTEM_TIA) {
hasTiunaCompat=true;
break;
}
}
if (hasTiunaCompat) {
if (ImGui::BeginMenu(_("export TIunA..."))) {
drawExportTiuna();
ImGui::EndMenu();
}
}
if (ImGui::BeginMenu(_("export text..."))) { if (ImGui::BeginMenu(_("export text..."))) {
drawExportText(); drawExportText();
ImGui::EndMenu(); ImGui::EndMenu();
@ -4372,19 +4350,6 @@ bool FurnaceGUI::loop() {
displayExport=true; displayExport=true;
} }
} }
bool hasTiunaCompat=false;
for (int i=0; i<e->song.systemLen; i++) {
if (e->song.system[i]==DIV_SYSTEM_TIA) {
hasTiunaCompat=true;
break;
}
}
if (hasTiunaCompat) {
if (ImGui::MenuItem(_("export TIunA..."))) {
curExportType=GUI_EXPORT_TIUNA;
displayExport=true;
}
}
if (ImGui::MenuItem(_("export text..."))) { if (ImGui::MenuItem(_("export text..."))) {
curExportType=GUI_EXPORT_TEXT; curExportType=GUI_EXPORT_TEXT;
displayExport=true; displayExport=true;
@ -4968,7 +4933,6 @@ bool FurnaceGUI::loop() {
workingDirZSMExport=fileDialog->getPath()+DIR_SEPARATOR_STR; workingDirZSMExport=fileDialog->getPath()+DIR_SEPARATOR_STR;
break; break;
case GUI_FILE_EXPORT_ROM: case GUI_FILE_EXPORT_ROM:
case GUI_FILE_EXPORT_TIUNA:
case GUI_FILE_EXPORT_TEXT: case GUI_FILE_EXPORT_TEXT:
case GUI_FILE_EXPORT_CMDSTREAM: case GUI_FILE_EXPORT_CMDSTREAM:
workingDirROMExport=fileDialog->getPath()+DIR_SEPARATOR_STR; workingDirROMExport=fileDialog->getPath()+DIR_SEPARATOR_STR;
@ -5527,27 +5491,6 @@ bool FurnaceGUI::loop() {
} }
break; break;
} }
case GUI_FILE_EXPORT_TIUNA: {
SafeWriter* w=e->saveTiuna(willExport,asmBaseLabel.c_str(),tiunaFirstBankSize,tiunaOtherBankSize);
if (w!=NULL) {
FILE* f=ps_fopen(copyOfName.c_str(),"wb");
if (f!=NULL) {
fwrite(w->getFinalBuf(),1,w->size(),f);
fclose(f);
pushRecentSys(copyOfName.c_str());
} else {
showError("could not open file!");
}
w->finish();
delete w;
if (!e->getWarnings().empty()) {
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
}
} else {
showError(fmt::sprintf("Could not write TIunA! (%s)",e->getLastError()));
}
break;
}
case GUI_FILE_EXPORT_ROM: case GUI_FILE_EXPORT_ROM:
romExportPath=copyOfName; romExportPath=copyOfName;
pendingExport=e->buildROM(romTarget); pendingExport=e->buildROM(romTarget);
@ -5833,6 +5776,7 @@ bool FurnaceGUI::loop() {
pendingExport->abort(); pendingExport->abort();
delete pendingExport; delete pendingExport;
pendingExport=NULL; pendingExport=NULL;
romExportSave=false;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
} else { } else {

View file

@ -599,7 +599,6 @@ enum FurnaceGUIFileDialogs {
GUI_FILE_EXPORT_AUDIO_PER_CHANNEL, GUI_FILE_EXPORT_AUDIO_PER_CHANNEL,
GUI_FILE_EXPORT_VGM, GUI_FILE_EXPORT_VGM,
GUI_FILE_EXPORT_ZSM, GUI_FILE_EXPORT_ZSM,
GUI_FILE_EXPORT_TIUNA,
GUI_FILE_EXPORT_CMDSTREAM, GUI_FILE_EXPORT_CMDSTREAM,
GUI_FILE_EXPORT_TEXT, GUI_FILE_EXPORT_TEXT,
GUI_FILE_EXPORT_ROM, GUI_FILE_EXPORT_ROM,
@ -653,7 +652,6 @@ enum FurnaceGUIExportTypes {
GUI_EXPORT_VGM, GUI_EXPORT_VGM,
GUI_EXPORT_ROM, GUI_EXPORT_ROM,
GUI_EXPORT_ZSM, GUI_EXPORT_ZSM,
GUI_EXPORT_TIUNA,
GUI_EXPORT_CMD_STREAM, GUI_EXPORT_CMD_STREAM,
GUI_EXPORT_TEXT, GUI_EXPORT_TEXT,
GUI_EXPORT_DMF GUI_EXPORT_DMF
@ -2698,7 +2696,6 @@ class FurnaceGUI {
void drawExportVGM(bool onWindow=false); void drawExportVGM(bool onWindow=false);
void drawExportROM(bool onWindow=false); void drawExportROM(bool onWindow=false);
void drawExportZSM(bool onWindow=false); void drawExportZSM(bool onWindow=false);
void drawExportTiuna(bool onWindow=false);
void drawExportText(bool onWindow=false); void drawExportText(bool onWindow=false);
void drawExportCommand(bool onWindow=false); void drawExportCommand(bool onWindow=false);
void drawExportDMF(bool onWindow=false); void drawExportDMF(bool onWindow=false);

View file

@ -87,7 +87,6 @@ String outName;
String vgmOutName; String vgmOutName;
String zsmOutName; String zsmOutName;
String cmdOutName; String cmdOutName;
String tiunaOutName;
int benchMode=0; int benchMode=0;
int subsong=-1; int subsong=-1;
DivAudioExportOptions exportOptions; DivAudioExportOptions exportOptions;
@ -112,9 +111,6 @@ bool infoMode=false;
bool noReportError=false; bool noReportError=false;
int tiunaFirstBankSize=3072;
int tiunaOtherBankSize=4096-48;
std::vector<TAParam> params; std::vector<TAParam> params;
#ifdef HAVE_LOCALE #ifdef HAVE_LOCALE
@ -445,12 +441,6 @@ TAParamResult pCmdOut(String val) {
return TA_PARAM_SUCCESS; return TA_PARAM_SUCCESS;
} }
TAParamResult pTiunaOut(String val) {
tiunaOutName=val;
e.setAudio(DIV_AUDIO_DUMMY);
return TA_PARAM_SUCCESS;
}
bool needsValue(String param) { bool needsValue(String param) {
for (size_t i=0; i<params.size(); i++) { for (size_t i=0; i<params.size(); i++) {
if (params[i].name==param) { if (params[i].name==param) {
@ -469,7 +459,6 @@ void initParams() {
params.push_back(TAParam("D","direct",false,pDirect,"","set VGM export direct stream mode")); params.push_back(TAParam("D","direct",false,pDirect,"","set VGM export direct stream mode"));
params.push_back(TAParam("Z","zsmout",true,pZSMOut,"<filename>","output .zsm data for Commander X16 Zsound")); params.push_back(TAParam("Z","zsmout",true,pZSMOut,"<filename>","output .zsm data for Commander X16 Zsound"));
params.push_back(TAParam("C","cmdout",true,pCmdOut,"<filename>","output command stream")); params.push_back(TAParam("C","cmdout",true,pCmdOut,"<filename>","output command stream"));
params.push_back(TAParam("T","tiunaout",true,pTiunaOut,"<filename>","output .asm data with TIunA sound data (TIA only)"));
params.push_back(TAParam("L","loglevel",true,pLogLevel,"debug|info|warning|error","set the log level (info by default)")); 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)")); params.push_back(TAParam("v","view",true,pView,"pattern|commands|nothing","set visualization (nothing by default)"));
params.push_back(TAParam("i","info",false,pInfo,"","get info about a song")); params.push_back(TAParam("i","info",false,pInfo,"","get info about a song"));
@ -573,7 +562,6 @@ int main(int argc, char** argv) {
vgmOutName=""; vgmOutName="";
zsmOutName=""; zsmOutName="";
cmdOutName=""; cmdOutName="";
tiunaOutName="";
// load config for locale // load config for locale
e.prePreInit(); e.prePreInit();
@ -741,14 +729,14 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
if (fileName.empty() && (benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="" || tiunaOutName!="")) { if (fileName.empty() && (benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="")) {
logE("provide a file!"); logE("provide a file!");
return 1; return 1;
} }
#ifdef HAVE_GUI #ifdef HAVE_GUI
if (e.preInit(consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="" || tiunaOutName!="")) { if (e.preInit(consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="")) {
if (consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="" || tiunaOutName!="") { if (consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="") {
logW("engine wants safe mode, but Furnace GUI is not going to start."); logW("engine wants safe mode, but Furnace GUI is not going to start.");
} else { } else {
safeMode=true; safeMode=true;
@ -760,7 +748,7 @@ int main(int argc, char** argv) {
} }
#endif #endif
if (safeMode && (consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="" || tiunaOutName!="")) { if (safeMode && (consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="")) {
logE("you can't use safe mode and console/export mode together."); logE("you can't use safe mode and console/export mode together.");
return 1; return 1;
} }
@ -769,7 +757,7 @@ int main(int argc, char** argv) {
e.setAudio(DIV_AUDIO_DUMMY); e.setAudio(DIV_AUDIO_DUMMY);
} }
if (!fileName.empty() && ((!e.getConfBool("tutIntroPlayed",TUT_INTRO_PLAYED)) || e.getConfInt("alwaysPlayIntro",0)!=3 || consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="" || tiunaOutName!="")) { if (!fileName.empty() && ((!e.getConfBool("tutIntroPlayed",TUT_INTRO_PLAYED)) || e.getConfInt("alwaysPlayIntro",0)!=3 || consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="")) {
logI("loading module..."); logI("loading module...");
FILE* f=ps_fopen(fileName.c_str(),"rb"); FILE* f=ps_fopen(fileName.c_str(),"rb");
if (f==NULL) { if (f==NULL) {
@ -861,7 +849,7 @@ int main(int argc, char** argv) {
return 0; return 0;
} }
if (outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="" || tiunaOutName!="") { if (outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="") {
if (cmdOutName!="") { if (cmdOutName!="") {
SafeWriter* w=e.saveCommand(); SafeWriter* w=e.saveCommand();
if (w!=NULL) { if (w!=NULL) {
@ -911,22 +899,6 @@ int main(int argc, char** argv) {
reportError(fmt::sprintf(_("could not write ZSM! (%s)"),e.getLastError())); reportError(fmt::sprintf(_("could not write ZSM! (%s)"),e.getLastError()));
} }
} }
if (tiunaOutName!="") {
SafeWriter* w=e.saveTiuna(NULL,"asmBaseLabel",tiunaFirstBankSize,tiunaOtherBankSize);
if (w!=NULL) {
FILE* f=ps_fopen(tiunaOutName.c_str(),"wb");
if (f!=NULL) {
fwrite(w->getFinalBuf(),1,w->size(),f);
fclose(f);
} else {
reportError(fmt::sprintf(_("could not open file! (%s)"),e.getLastError()));
}
w->finish();
delete w;
} else {
reportError(fmt::sprintf("could not write TIunA! (%s)",e.getLastError()));
}
}
if (outName!="") { if (outName!="") {
e.setConsoleMode(true); e.setConsoleMode(true);
e.saveAudio(outName.c_str(),exportOptions); e.saveAudio(outName.c_str(),exportOptions);