From 93e26d415bd7edf10efe32a453dffe74b86be464 Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Mon, 26 Jan 2026 03:34:28 +0700 Subject: [PATCH] Add an another TIA export --- CMakeLists.txt | 3 +- src/engine/engine.h | 5 +- src/engine/export.cpp | 10 +- src/engine/export.h | 5 +- .../export/{saxotone.cpp => tiasaxotone.cpp} | 40 +++--- src/engine/export/tiasaxotone.h | 38 ++++++ src/engine/export/tiatriplet.cpp | 115 ++++++++++++++++++ .../export/{saxotone.h => tiatriplet.h} | 4 +- src/engine/exportDef.cpp | 22 +++- 9 files changed, 207 insertions(+), 35 deletions(-) rename src/engine/export/{saxotone.cpp => tiasaxotone.cpp} (91%) create mode 100644 src/engine/export/tiasaxotone.h create mode 100644 src/engine/export/tiatriplet.cpp rename src/engine/export/{saxotone.h => tiatriplet.h} (93%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c57f052c..c36da1559 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -896,7 +896,8 @@ src/engine/export/tiuna.cpp src/engine/export/zsm.cpp src/engine/export/ipod.cpp src/engine/export/grub.cpp -src/engine/export/saxotone.cpp +src/engine/export/tiasaxotone.cpp +src/engine/export/tiatriplet.cpp src/engine/effect/abstract.cpp src/engine/effect/dummy.cpp diff --git a/src/engine/engine.h b/src/engine/engine.h index 408296c2c..15ad4b7e5 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -535,7 +535,7 @@ class DivEngine { void loadFF(SafeReader& reader, std::vector& ret, String& stripPath); void loadWOPL(SafeReader& reader, std::vector& ret, String& stripPath); void loadWOPN(SafeReader& reader, std::vector& ret, String& stripPath); - + //sample banks void loadP(SafeReader& reader, std::vector& ret, String& stripPath); void loadPPC(SafeReader& reader, std::vector& ret, String& stripPath); @@ -585,7 +585,8 @@ class DivEngine { friend class DivExportZSM; friend class DivExportiPod; friend class DivExportGRUB; - friend class DivExportSaxotone; + friend class DivExportTIASaxotone; + friend class DivExportTIATriplet; public: DivSong song; diff --git a/src/engine/export.cpp b/src/engine/export.cpp index 65355939a..a44e40cb1 100644 --- a/src/engine/export.cpp +++ b/src/engine/export.cpp @@ -25,7 +25,8 @@ #include "export/zsm.h" #include "export/ipod.h" #include "export/grub.h" -#include "export/saxotone.h" +#include "export/tiasaxotone.h" +#include "export/tiatriplet.h" DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { DivROMExport* exporter=NULL; @@ -48,8 +49,11 @@ DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { case DIV_ROM_GRUB: exporter=new DivExportGRUB; break; - case DIV_ROM_SAXOTONE: - exporter=new DivExportSaxotone; + case DIV_ROM_TIA_SAXOTONE: + exporter=new DivExportTIASaxotone; + break; + case DIV_ROM_TIA_TRIPLET: + exporter=new DivExportTIATriplet; break; default: exporter=new DivROMExport; diff --git a/src/engine/export.h b/src/engine/export.h index b54f39a6d..b4862bc23 100644 --- a/src/engine/export.h +++ b/src/engine/export.h @@ -34,7 +34,8 @@ enum DivROMExportOptions { DIV_ROM_SAP_R, DIV_ROM_IPOD, DIV_ROM_GRUB, - DIV_ROM_SAXOTONE, + DIV_ROM_TIA_SAXOTONE, + DIV_ROM_TIA_TRIPLET, DIV_ROM_MAX }; @@ -42,7 +43,7 @@ enum DivROMExportOptions { struct DivROMExportOutput { String name; SafeWriter* data; - + DivROMExportOutput(String n, SafeWriter* d): name(n), data(d) {} diff --git a/src/engine/export/saxotone.cpp b/src/engine/export/tiasaxotone.cpp similarity index 91% rename from src/engine/export/saxotone.cpp rename to src/engine/export/tiasaxotone.cpp index 2de098e81..e9e604b24 100644 --- a/src/engine/export/saxotone.cpp +++ b/src/engine/export/tiasaxotone.cpp @@ -17,28 +17,28 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "saxotone.h" +#include "tiasaxotone.h" #include "../engine.h" #include "../ta-log.h" #include #include #include -void saxotone_write_table_lo(SafeWriter *w, unsigned int *offs, size_t off_amt) { +static void saxotone_write_table_lo(SafeWriter *w, unsigned int *offs, size_t off_amt) { w->writeText(".byte "); for (size_t i = 0; i < off_amt; i++) { w->writeText(fmt::sprintf("<($%04x+sample_dir)%c",offs[i],i==(off_amt-1)?'\n':',')); } } -void saxotone_write_table_hi(SafeWriter *w, unsigned int *offs, size_t off_amt) { +static void saxotone_write_table_hi(SafeWriter *w, unsigned int *offs, size_t off_amt) { w->writeText(".byte "); for (size_t i = 0; i < off_amt; i++) { w->writeText(fmt::sprintf("<($%04x+sample_dir)%c",offs[i],i==(off_amt-1)?'\n':',')); } } -void DivExportSaxotone::run() { +void DivExportTIASaxotone::run() { int SAXOTONE=-1; int TIA=-1; int IGNORED=0; @@ -48,11 +48,11 @@ void DivExportSaxotone::run() { if (e->song.system[i] == DIV_SYSTEM_SAXOTONE) { if (SAXOTONE>=0) { IGNORED++; - logAppendf("Ignoring duplicate Saxotone id %d",i); + logAppendf("Ignoring duplicate SAXotone id %d",i); continue; } SAXOTONE=i; - logAppendf("Saxotone detected as chip id %d",i); + logAppendf("SAXotone detected as chip id %d",i); continue; } else if (e->song.system[i] == DIV_SYSTEM_TIA) { if (TIA>=0) { @@ -70,7 +70,7 @@ void DivExportSaxotone::run() { } } if (SAXOTONE<0) { - logAppendf("ERROR: Could not find Saxotone"); + logAppendf("ERROR: Could not find SAXotone"); failed=true; running=false; return; @@ -94,7 +94,7 @@ void DivExportSaxotone::run() { e->warnings=""; auto w = new SafeWriter; w->init(); - + e->disCont[SAXOTONE].dispatch->renderSamples(0); const DivMemoryComposition *memCompo = e->disCont[SAXOTONE].dispatch->getMemCompo(0); unsigned int wtOff[256]; @@ -111,7 +111,7 @@ void DivExportSaxotone::run() { samp_ind++; } } - + // wavetab O // samptab O // samptabend O @@ -165,7 +165,7 @@ void DivExportSaxotone::run() { // if one-shot, set the loop point the last wave macro position if (wave_loop == 0xFF) wave_loop = wave_len-1; for (int x = 0; x < wave_len; x++) { - w->writeText(fmt::sprintf("$%02x,", e->song.ins[i]->std.waveMacro.val[x]+1)); + w->writeText(fmt::sprintf("$%02x,", e->song.ins[i]->std.waveMacro.val[x]+1)); } w->writeText(fmt::sprintf("$00,$%02x\n", wave_loop)); // loop } @@ -185,7 +185,7 @@ void DivExportSaxotone::run() { for (int i = 0; i < 256; i++) used_note_index[i] = -1; unsigned char note_ind = 0; int ord_len = e->curSubSong->ordersLen; - // order pointers + // order pointers // TOOD: what to do for the TIA channel? for (int ch = 0; ch < 4; ch++) { int pat_amt = 0; @@ -234,7 +234,7 @@ void DivExportSaxotone::run() { } else { note = 0; } - + // get instrument byte unsigned char inst = cur_row[DIV_PAT_INS]; if (inst == -1) inst = 0; @@ -266,13 +266,13 @@ void DivExportSaxotone::run() { progress[0].amount=0.95f; progress[0].amount=1.0f; - + logAppend("finished!"); running=false; } -bool DivExportSaxotone::go(DivEngine* eng) { +bool DivExportTIASaxotone::go(DivEngine* eng) { progress[0].name="Progress"; progress[0].amount=0.0f; @@ -280,11 +280,11 @@ bool DivExportSaxotone::go(DivEngine* eng) { running=true; failed=false; mustAbort=false; - exportThread=new std::thread(&DivExportSaxotone::run,this); + exportThread=new std::thread(&DivExportTIASaxotone::run,this); return true; } -void DivExportSaxotone::wait() { +void DivExportTIASaxotone::wait() { if (exportThread!=NULL) { logV("waiting for export thread..."); exportThread->join(); @@ -292,20 +292,20 @@ void DivExportSaxotone::wait() { } } -void DivExportSaxotone::abort() { +void DivExportTIASaxotone::abort() { mustAbort=true; wait(); } -bool DivExportSaxotone::isRunning() { +bool DivExportTIASaxotone::isRunning() { return running; } -bool DivExportSaxotone::hasFailed() { +bool DivExportTIASaxotone::hasFailed() { return failed; } -DivROMExportProgress DivExportSaxotone::getProgress(int index) { +DivROMExportProgress DivExportTIASaxotone::getProgress(int index) { if (index<0 || index>1) return progress[1]; return progress[index]; } diff --git a/src/engine/export/tiasaxotone.h b/src/engine/export/tiasaxotone.h new file mode 100644 index 000000000..3125f419d --- /dev/null +++ b/src/engine/export/tiasaxotone.h @@ -0,0 +1,38 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2026 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 + +class DivExportTIASaxotone: public DivROMExport { + DivEngine* e; + std::thread* exportThread; + DivROMExportProgress progress[2]; + bool running, failed, mustAbort; + void run(); + public: + bool go(DivEngine* e); + bool isRunning(); + bool hasFailed(); + void abort(); + void wait(); + DivROMExportProgress getProgress(int index=0); + ~DivExportTIASaxotone() {} +}; diff --git a/src/engine/export/tiatriplet.cpp b/src/engine/export/tiatriplet.cpp new file mode 100644 index 000000000..0c358a783 --- /dev/null +++ b/src/engine/export/tiatriplet.cpp @@ -0,0 +1,115 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2026 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 "tiatriplet.h" +#include "../engine.h" +#include "../ta-log.h" +#include +#include +#include + +void DivExportTIATriplet::run() { + int TIA=-1; + int IGNORED=0; + + // Locate system index. + for (int i=0; isong.systemLen; i++) { + if (e->song.system[i] == DIV_SYSTEM_TIA) { + if (TIA>=0) { + IGNORED++; + logAppendf("Ignoring duplicate TIA id %d",i); + continue; + } + TIA=i; + logAppendf("TIA detected as chip id %d",i); + continue; + } else { + IGNORED++; + logAppendf("Ignoring chip id %d, system id %d",i,(int)e->song.system[i]); + continue; + } + } + if (TIA<0) { + logAppendf("ERROR: Could not find TIA"); + failed=true; + running=false; + return; + } + if (IGNORED>0) { + logAppendf("WARNING: ASM export ignoring %d unsupported system%c",IGNORED,IGNORED>1?'s':' '); + } + + e->stop(); + e->setOrder(0); + + logAppend("playing and logging register writes..."); + + e->synchronizedSoft([&]() { + e->warnings=""; + auto w = new SafeWriter; + w->init(); + + // TODO + + output.push_back(DivROMExportOutput("music.asm",w)); + }); + + progress[0].amount=1.0f; + logAppend("finished!"); + + running=false; +} + +bool DivExportTIATriplet::go(DivEngine* eng) { + progress[0].name="Progress"; + progress[0].amount=0.0f; + + e=eng; + running=true; + failed=false; + mustAbort=false; + exportThread=new std::thread(&DivExportTIATriplet::run,this); + return true; +} + +void DivExportTIATriplet::wait() { + if (exportThread!=NULL) { + logV("waiting for export thread..."); + exportThread->join(); + delete exportThread; + } +} + +void DivExportTIATriplet::abort() { + mustAbort=true; + wait(); +} + +bool DivExportTIATriplet::isRunning() { + return running; +} + +bool DivExportTIATriplet::hasFailed() { + return failed; +} + +DivROMExportProgress DivExportTIATriplet::getProgress(int index) { + if (index<0 || index>1) return progress[1]; + return progress[index]; +} diff --git a/src/engine/export/saxotone.h b/src/engine/export/tiatriplet.h similarity index 93% rename from src/engine/export/saxotone.h rename to src/engine/export/tiatriplet.h index 68f5e9941..05be018ab 100644 --- a/src/engine/export/saxotone.h +++ b/src/engine/export/tiatriplet.h @@ -21,7 +21,7 @@ #include -class DivExportSaxotone: public DivROMExport { +class DivExportTIATriplet: public DivROMExport { DivEngine* e; std::thread* exportThread; DivROMExportProgress progress[2]; @@ -34,5 +34,5 @@ class DivExportSaxotone: public DivROMExport { void abort(); void wait(); DivROMExportProgress getProgress(int index=0); - ~DivExportSaxotone() {} + ~DivExportTIATriplet() {} }; diff --git a/src/engine/exportDef.cpp b/src/engine/exportDef.cpp index 2a552906b..54b2a3649 100644 --- a/src/engine/exportDef.cpp +++ b/src/engine/exportDef.cpp @@ -143,14 +143,26 @@ void DivEngine::registerROMExports() { false, DIV_REQPOL_ANY ); - romExportDefs[DIV_ROM_SAXOTONE]=new DivROMExportDef( - "Saxotone", "Natt & AArt1256", - "Saxotone export\n" - "for use with the Saxotone Atari 2600 beeper engine", - "Text/Binary files", NULL, + romExportDefs[DIV_ROM_TIA_SAXOTONE]=new DivROMExportDef( + "Atari 2600 (SAXotone)", "Natt Akuma and AArt1256", + "for use with SAXotone, an advanced beeper driver\n" + "used in the final part of the Triplet demo.\n" + "only channel 1 of TIA will be used.", + "assembly files", ".asm", { DIV_SYSTEM_SAXOTONE, DIV_SYSTEM_TIA }, false, DIV_REQPOL_ANY ); + + romExportDefs[DIV_ROM_TIA_TRIPLET]=new DivROMExportDef( + "Atari 2600 (Triplet)", "Natt Akuma", + "for use with the compressed register dump driver\n" + "used in the main part of the Triplet demo.", + "assembly files", ".asm", + { + DIV_SYSTEM_TIA + }, + false, DIV_REQPOL_ANY + ); }