From 2ef09c5a2be39b74f233c4b83a70db7d4258beee Mon Sep 17 00:00:00 2001 From: AArt1256 Date: Sat, 11 Jan 2025 20:09:19 +0300 Subject: [PATCH 1/7] add ipod .tone support --- CMakeLists.txt | 1 + src/engine/engine.h | 1 + src/engine/export.cpp | 4 + src/engine/export.h | 1 + src/engine/export/ipod.cpp | 202 +++++++++++++++++++++++++++++++++++++ src/engine/export/ipod.h | 38 +++++++ src/engine/exportDef.cpp | 10 ++ 7 files changed, 257 insertions(+) create mode 100644 src/engine/export/ipod.cpp create mode 100644 src/engine/export/ipod.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 67d2db363f..280770a034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -812,6 +812,7 @@ src/engine/export/amigaValidation.cpp src/engine/export/sapr.cpp src/engine/export/tiuna.cpp src/engine/export/zsm.cpp +src/engine/export/ipod.cpp src/engine/effect/abstract.cpp src/engine/effect/dummy.cpp diff --git a/src/engine/engine.h b/src/engine/engine.h index c64268dd85..65432a0a37 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -675,6 +675,7 @@ class DivEngine { friend class DivExportSAPR; friend class DivExportTiuna; friend class DivExportZSM; + friend class DivExportiPod; public: DivSong song; diff --git a/src/engine/export.cpp b/src/engine/export.cpp index 59201faa4c..20713db561 100644 --- a/src/engine/export.cpp +++ b/src/engine/export.cpp @@ -23,6 +23,7 @@ #include "export/sapr.h" #include "export/tiuna.h" #include "export/zsm.h" +#include "export/ipod.h" DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { DivROMExport* exporter=NULL; @@ -39,6 +40,9 @@ DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { case DIV_ROM_SAP_R: exporter=new DivExportSAPR; break; + case DIV_ROM_IPOD: + exporter=new DivExportiPod; + break; default: exporter=new DivROMExport; break; diff --git a/src/engine/export.h b/src/engine/export.h index 4971169956..202ce3fcf5 100644 --- a/src/engine/export.h +++ b/src/engine/export.h @@ -32,6 +32,7 @@ enum DivROMExportOptions { DIV_ROM_ZSM, DIV_ROM_TIUNA, DIV_ROM_SAP_R, + DIV_ROM_IPOD, DIV_ROM_MAX }; diff --git a/src/engine/export/ipod.cpp b/src/engine/export/ipod.cpp new file mode 100644 index 0000000000..14a16f5a47 --- /dev/null +++ b/src/engine/export/ipod.cpp @@ -0,0 +1,202 @@ +/** + * 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. + */ + +// thanks asiekierka! +// I have ported your code to this ROM export framework. + +#include "ipod.h" +#include "../engine.h" +#include "../ta-log.h" +#include +#include +#include + +constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; +constexpr int MASTER_CLOCK_MASK=(sizeof(void*)==8)?0xff:0; + +void DivExportiPod::run() { + int BEEPER=-1; + int IGNORED=0; + + // Locate system index. + for (int i=0; isong.systemLen; i++) { + if (e->song.system[i] == DIV_SYSTEM_PCSPKR) { + if (BEEPER>=0) { + IGNORED++; + logAppendf("Ignoring duplicate Beeper id %d",i); + break; + } + BEEPER=i; + logAppendf("PC Speaker detected as chip id %d",i); + break; + } else { + IGNORED++; + logAppendf("Ignoring chip id %d, system id %d",i,(int)e->song.system[i]); + break; + } + } + if (BEEPER<0) { + logAppendf("ERROR: Could not find PC Speaker/Beeper"); + failed=true; + running=false; + return; + } + if (IGNORED>0) { + logAppendf("WARNING: iPod .tone export ignoring %d unsupported system%c",IGNORED,IGNORED>1?'s':' '); + } + + size_t tickCount=0; + + double rate = 1000.0; + + e->stop(); + e->repeatPattern=false; + e->setOrder(0); + + logAppend("playing and logging register writes..."); + + int oldFreq = 0; + int freq = 0; + + e->synchronizedSoft([&]() { + double origRate = e->got.rate; + e->got.rate=rate; + + // Determine loop point. + int loopOrder=0; + int loopRow=0; + int loopEnd=0; + e->walkSong(loopOrder,loopRow,loopEnd); + logAppendf("loop point: %d %d",loopOrder,loopRow); + e->warnings=""; + + auto w = new SafeWriter; + w->init(); + + w->writeText(fmt::sprintf("%s\n", e->song.name)); + + // Reset the playback state. + e->curOrder=0; + e->freelance=false; + e->playing=false; + e->extValuePresent=false; + e->remainingLoops=-1; + + e->disCont[BEEPER].dispatch->toggleRegisterDump(true); + + // Prepare to write song data. + e->playSub(false); + bool done=false; + int fracWait=0; // accumulates fractional ticks + + logAppend("writing data..."); + progress[0].amount=0.15f; + + int wait_ms = 0; + + while (!done) { + if (e->nextTick(false,true) || !e->playing) { + done=true; + } + + // get register dumps + uint8_t* regPool = e->disCont[BEEPER].dispatch->getRegisterPool(); + int chipClock = e->disCont[BEEPER].dispatch->chipClock; + freq = (int)(regPool[0]|(regPool[1]<<8)); + if (freq > 0) freq = chipClock/freq; + + // write wait + tickCount++; + int totalWait=e->cycles>>MASTER_CLOCK_PREC; + fracWait+=e->cycles&MASTER_CLOCK_MASK; + totalWait+=fracWait>>MASTER_CLOCK_PREC; + fracWait&=MASTER_CLOCK_MASK; + if (totalWait>0 && !done) { + while (totalWait) { + wait_ms++; + if (freq != oldFreq) { + w->writeText(fmt::sprintf("%d %d\n", oldFreq, wait_ms)); + oldFreq = freq; + wait_ms = 0; + } + totalWait--; + tickCount++; + } + } + } + // end of song + + // done - close out. + e->got.rate=origRate; + e->disCont[BEEPER].dispatch->getRegisterWrites().clear(); + e->disCont[BEEPER].dispatch->toggleRegisterDump(false); + + e->remainingLoops=-1; + e->playing=false; + e->freelance=false; + e->extValuePresent=false; + + output.push_back(DivROMExportOutput("export.tone",w)); + }); + + + progress[0].amount=1.0f; + + logAppend("finished!"); + + running=false; +} + +bool DivExportiPod::go(DivEngine* eng) { + progress[0].name="Progress"; + progress[0].amount=0.0f; + + e=eng; + running=true; + failed=false; + mustAbort=false; + exportThread=new std::thread(&DivExportiPod::run,this); + return true; +} + +void DivExportiPod::wait() { + if (exportThread!=NULL) { + logV("waiting for export thread..."); + exportThread->join(); + delete exportThread; + } +} + +void DivExportiPod::abort() { + mustAbort=true; + wait(); +} + +bool DivExportiPod::isRunning() { + return running; +} + +bool DivExportiPod::hasFailed() { + return failed; +} + +DivROMExportProgress DivExportiPod::getProgress(int index) { + if (index<0 || index>1) return progress[1]; + return progress[index]; +} diff --git a/src/engine/export/ipod.h b/src/engine/export/ipod.h new file mode 100644 index 0000000000..a1c55c0726 --- /dev/null +++ b/src/engine/export/ipod.h @@ -0,0 +1,38 @@ +/** + * 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 + +class DivExportiPod: 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); + ~DivExportiPod() {} +}; diff --git a/src/engine/exportDef.cpp b/src/engine/exportDef.cpp index 4288753801..7c6a52ab38 100644 --- a/src/engine/exportDef.cpp +++ b/src/engine/exportDef.cpp @@ -119,4 +119,14 @@ void DivEngine::registerROMExports() { }, false, DIV_REQPOL_EXACT ); + + romExportDefs[DIV_ROM_IPOD]=new DivROMExportDef( + "iPod .tone alarm", "AArt1256", + "this is very cursed...", + "alarm tone files", ".tone", + { + DIV_SYSTEM_PCSPKR + }, + false, DIV_REQPOL_ANY + ); } From bfe2019d23e2a0c88c982f1ed0fd5d5cdc3cbee2 Mon Sep 17 00:00:00 2001 From: AArt1256 Date: Sun, 30 Mar 2025 12:20:45 +0300 Subject: [PATCH 2/7] added basic GRUB_INIT_TUNE export --- CMakeLists.txt | 1 + extern/portaudio | 1 + src/engine/engine.h | 1 + src/engine/export.cpp | 4 + src/engine/export.h | 1 + src/engine/export/grub.cpp | 197 +++++++++++++++++++++++++++++++++++++ src/engine/export/grub.h | 38 +++++++ src/engine/export/ipod.cpp | 8 +- src/engine/exportDef.cpp | 15 ++- 9 files changed, 259 insertions(+), 7 deletions(-) create mode 160000 extern/portaudio create mode 100644 src/engine/export/grub.cpp create mode 100644 src/engine/export/grub.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a10a3cb08..cc7142dac4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -815,6 +815,7 @@ src/engine/export/sapr.cpp src/engine/export/tiuna.cpp src/engine/export/zsm.cpp src/engine/export/ipod.cpp +src/engine/export/grub.cpp src/engine/effect/abstract.cpp src/engine/effect/dummy.cpp diff --git a/extern/portaudio b/extern/portaudio new file mode 160000 index 0000000000..6ee9836a08 --- /dev/null +++ b/extern/portaudio @@ -0,0 +1 @@ +Subproject commit 6ee9836a08d201c118b4715d4d70242816584000 diff --git a/src/engine/engine.h b/src/engine/engine.h index 141264971c..da160b3af6 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -676,6 +676,7 @@ class DivEngine { friend class DivExportTiuna; friend class DivExportZSM; friend class DivExportiPod; + friend class DivExportGRUB; public: DivSong song; diff --git a/src/engine/export.cpp b/src/engine/export.cpp index a8ec2a0d0d..c50bb71328 100644 --- a/src/engine/export.cpp +++ b/src/engine/export.cpp @@ -24,6 +24,7 @@ #include "export/tiuna.h" #include "export/zsm.h" #include "export/ipod.h" +#include "export/grub.h" DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { DivROMExport* exporter=NULL; @@ -43,6 +44,9 @@ DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { case DIV_ROM_IPOD: exporter=new DivExportiPod; break; + case DIV_ROM_GRUB: + exporter=new DivExportGRUB; + break; default: exporter=new DivROMExport; break; diff --git a/src/engine/export.h b/src/engine/export.h index e13380aa37..fc05ed9490 100644 --- a/src/engine/export.h +++ b/src/engine/export.h @@ -33,6 +33,7 @@ enum DivROMExportOptions { DIV_ROM_TIUNA, DIV_ROM_SAP_R, DIV_ROM_IPOD, + DIV_ROM_GRUB, DIV_ROM_MAX }; diff --git a/src/engine/export/grub.cpp b/src/engine/export/grub.cpp new file mode 100644 index 0000000000..626de0762e --- /dev/null +++ b/src/engine/export/grub.cpp @@ -0,0 +1,197 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2025 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 "grub.h" +#include "../engine.h" +#include "../ta-log.h" +#include +#include +#include + +constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; +constexpr int MASTER_CLOCK_MASK=(sizeof(void*)==8)?0xff:0; + +void DivExportGRUB::run() { + int BEEPER=-1; + int IGNORED=0; + + // Locate system index. + for (int i=0; isong.systemLen; i++) { + if (e->song.system[i] == DIV_SYSTEM_PCSPKR) { + if (BEEPER>=0) { + IGNORED++; + logAppendf("Ignoring duplicate Beeper id %d",i); + break; + } + BEEPER=i; + logAppendf("PC Speaker detected as chip id %d",i); + break; + } else { + IGNORED++; + logAppendf("Ignoring chip id %d, system id %d",i,(int)e->song.system[i]); + break; + } + } + if (BEEPER<0) { + logAppendf("ERROR: Could not find PC Speaker/Beeper"); + failed=true; + running=false; + return; + } + if (IGNORED>0) { + logAppendf("WARNING: iPod .tone export ignoring %d unsupported system%c",IGNORED,IGNORED>1?'s':' '); + } + + size_t tickCount=0; + + e->stop(); + e->repeatPattern=false; + e->setOrder(0); + + logAppend("playing and logging register writes..."); + + int oldFreq = 0; + int freq = 0; + + e->synchronizedSoft([&]() { + double origRate = e->got.rate; + double rate = MIN(e->got.rate,1000.0); + logAppendf("export rate is %d hz",(int)rate); + int tempo = (int)(60000.0/(1000.0/rate)); + e->got.rate=rate; + + // Determine loop point. + int loopOrder=0; + int loopRow=0; + int loopEnd=0; + e->walkSong(loopOrder,loopRow,loopEnd); + logAppendf("loop point: %d %d",loopOrder,loopRow); + e->warnings=""; + + auto w = new SafeWriter; + w->init(); + + // Reset the playback state. + e->curOrder=0; + e->freelance=false; + e->playing=false; + e->extValuePresent=false; + e->remainingLoops=-1; + + e->disCont[BEEPER].dispatch->toggleRegisterDump(true); + + // Prepare to write song data. + e->playSub(false); + bool done=false; + + logAppend("writing data..."); + progress[0].amount=0.15f; + + int wait_tempo = 0; + w->writeText(fmt::sprintf("%d",tempo)); // write tempo + + while (!done) { + if (e->nextTick(false,true) || !e->playing) { + done=true; + } + + // get register dumps + uint8_t* regPool = e->disCont[BEEPER].dispatch->getRegisterPool(); + int chipClock = e->disCont[BEEPER].dispatch->chipClock; + freq = (int)(regPool[0]|(regPool[1]<<8)); + if (freq > 0) freq = chipClock/freq; + + // write wait + tickCount++; + int totalWait=e->cycles; + if (totalWait>0 && !done) { + while (totalWait) { + wait_tempo++; + if (freq != oldFreq) { + w->writeText(fmt::sprintf(" %d %d", oldFreq, wait_tempo)); + oldFreq = freq; + wait_tempo = 0; + } + totalWait--; + tickCount++; + } + } + } + + w->writeText(fmt::sprintf("\n")); // end song + // end of song + + // done - close out. + e->got.rate=origRate; + e->disCont[BEEPER].dispatch->getRegisterWrites().clear(); + e->disCont[BEEPER].dispatch->toggleRegisterDump(false); + + e->remainingLoops=-1; + e->playing=false; + e->freelance=false; + e->extValuePresent=false; + + output.push_back(DivROMExportOutput("export.txt",w)); + }); + + + progress[0].amount=1.0f; + + logAppend("finished!"); + + running=false; +} + +bool DivExportGRUB::go(DivEngine* eng) { + progress[0].name="Progress"; + progress[0].amount=0.0f; + + e=eng; + running=true; + failed=false; + mustAbort=false; + exportThread=new std::thread(&DivExportGRUB::run,this); + return true; +} + +void DivExportGRUB::wait() { + if (exportThread!=NULL) { + logV("waiting for export thread..."); + exportThread->join(); + delete exportThread; + } +} + +void DivExportGRUB::abort() { + mustAbort=true; + wait(); +} + +bool DivExportGRUB::isRunning() { + return running; +} + +bool DivExportGRUB::hasFailed() { + return failed; +} + +DivROMExportProgress DivExportGRUB::getProgress(int index) { + if (index<0 || index>1) return progress[1]; + return progress[index]; +} diff --git a/src/engine/export/grub.h b/src/engine/export/grub.h new file mode 100644 index 0000000000..422ddf1549 --- /dev/null +++ b/src/engine/export/grub.h @@ -0,0 +1,38 @@ +/** + * 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 + +class DivExportGRUB: 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); + ~DivExportGRUB() {} +}; diff --git a/src/engine/export/ipod.cpp b/src/engine/export/ipod.cpp index 14a16f5a47..26b8a402fa 100644 --- a/src/engine/export/ipod.cpp +++ b/src/engine/export/ipod.cpp @@ -1,6 +1,6 @@ /** * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2024 tildearrow and contributors + * Copyright (C) 2021-2025 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 @@ -103,7 +103,6 @@ void DivExportiPod::run() { // Prepare to write song data. e->playSub(false); bool done=false; - int fracWait=0; // accumulates fractional ticks logAppend("writing data..."); progress[0].amount=0.15f; @@ -123,10 +122,7 @@ void DivExportiPod::run() { // write wait tickCount++; - int totalWait=e->cycles>>MASTER_CLOCK_PREC; - fracWait+=e->cycles&MASTER_CLOCK_MASK; - totalWait+=fracWait>>MASTER_CLOCK_PREC; - fracWait&=MASTER_CLOCK_MASK; + int totalWait=e->cycles; if (totalWait>0 && !done) { while (totalWait) { wait_ms++; diff --git a/src/engine/exportDef.cpp b/src/engine/exportDef.cpp index e2b8a778fd..8f5d81128d 100644 --- a/src/engine/exportDef.cpp +++ b/src/engine/exportDef.cpp @@ -122,11 +122,24 @@ void DivEngine::registerROMExports() { romExportDefs[DIV_ROM_IPOD]=new DivROMExportDef( "iPod .tone alarm", "AArt1256", - "this is very cursed...", + "iPod Beeper (.tone) Alarm export\n" + "for playback, you can drag the resulting file\n" + "into iPod_Control/Tones to your iPod IN DISK MODE", "alarm tone files", ".tone", { DIV_SYSTEM_PCSPKR }, false, DIV_REQPOL_ANY ); + + romExportDefs[DIV_ROM_GRUB]=new DivROMExportDef( + "GRUB_INIT_TUNE", "AArt1256", + "GRUB_INIT_TUNE export\n" + "for use with the GRUB bootloader", + "Text files", ".txt", + { + DIV_SYSTEM_PCSPKR + }, + false, DIV_REQPOL_ANY + ); } From e39c4ab7c79c76fd2791580083a6f0e32c4435b8 Mon Sep 17 00:00:00 2001 From: AArt1256 Date: Sun, 30 Mar 2025 12:21:50 +0300 Subject: [PATCH 3/7] aaa --- extern/portaudio | 1 - 1 file changed, 1 deletion(-) delete mode 160000 extern/portaudio diff --git a/extern/portaudio b/extern/portaudio deleted file mode 160000 index 6ee9836a08..0000000000 --- a/extern/portaudio +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ee9836a08d201c118b4715d4d70242816584000 From 4323d7cd86ca95fb0eeae9897580f3cb48690bfc Mon Sep 17 00:00:00 2001 From: AArt1256 Date: Sun, 30 Mar 2025 17:25:09 +0300 Subject: [PATCH 4/7] fixed refresh rate with GRUB tune export --- src/engine/export/grub.cpp | 22 ++++++++++++++++------ src/engine/exportDef.cpp | 4 ++-- src/gui/exportOptions.cpp | 10 ++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/engine/export/grub.cpp b/src/engine/export/grub.cpp index 626de0762e..44b8418ca4 100644 --- a/src/engine/export/grub.cpp +++ b/src/engine/export/grub.cpp @@ -28,6 +28,8 @@ constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; constexpr int MASTER_CLOCK_MASK=(sizeof(void*)==8)?0xff:0; void DivExportGRUB::run() { + bool grubExportBin=conf.getBool("exportBin",false); + int BEEPER=-1; int IGNORED=0; @@ -71,7 +73,7 @@ void DivExportGRUB::run() { e->synchronizedSoft([&]() { double origRate = e->got.rate; - double rate = MIN(e->got.rate,1000.0); + double rate = MIN(e->curSubSong->hz,1000.0); logAppendf("export rate is %d hz",(int)rate); int tempo = (int)(60000.0/(1000.0/rate)); e->got.rate=rate; @@ -104,7 +106,10 @@ void DivExportGRUB::run() { progress[0].amount=0.15f; int wait_tempo = 0; - w->writeText(fmt::sprintf("%d",tempo)); // write tempo + if (grubExportBin) + w->writeI(tempo); // write tempo + else + w->writeText(fmt::sprintf("%d",tempo)); // write tempo while (!done) { if (e->nextTick(false,true) || !e->playing) { @@ -123,8 +128,13 @@ void DivExportGRUB::run() { if (totalWait>0 && !done) { while (totalWait) { wait_tempo++; - if (freq != oldFreq) { - w->writeText(fmt::sprintf(" %d %d", oldFreq, wait_tempo)); + if (freq != oldFreq || wait_tempo == 65535) { + if (grubExportBin) { + w->writeS(oldFreq); // pitch + w->writeS(wait_tempo); // duration + } else { + w->writeText(fmt::sprintf(" %d %d", oldFreq, wait_tempo)); + } oldFreq = freq; wait_tempo = 0; } @@ -134,7 +144,7 @@ void DivExportGRUB::run() { } } - w->writeText(fmt::sprintf("\n")); // end song + if (!grubExportBin) w->writeText(fmt::sprintf("\n")); // end song // end of song // done - close out. @@ -147,7 +157,7 @@ void DivExportGRUB::run() { e->freelance=false; e->extValuePresent=false; - output.push_back(DivROMExportOutput("export.txt",w)); + output.push_back(DivROMExportOutput(grubExportBin?"export.bin":"export.txt",w)); }); diff --git a/src/engine/exportDef.cpp b/src/engine/exportDef.cpp index 8f5d81128d..31766f954d 100644 --- a/src/engine/exportDef.cpp +++ b/src/engine/exportDef.cpp @@ -135,8 +135,8 @@ void DivEngine::registerROMExports() { romExportDefs[DIV_ROM_GRUB]=new DivROMExportDef( "GRUB_INIT_TUNE", "AArt1256", "GRUB_INIT_TUNE export\n" - "for use with the GRUB bootloader", - "Text files", ".txt", + "for use with the GRUB bootloader using the \"play\" command", + "Text/Binary files", NULL, { DIV_SYSTEM_PCSPKR }, diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index 0e17a112e1..b33e6597c5 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -342,6 +342,16 @@ void FurnaceGUI::drawExportROM(bool onWindow) { } break; } + case DIV_ROM_GRUB: { + bool grubExportBin=romConfig.getBool("exportBin",false); + if (ImGui::Checkbox(_("export binary file"),&grubExportBin)) { + altered=true; + } + if (altered) { + romConfig.set("exportBin",grubExportBin); + } + break; + } case DIV_ROM_ABSTRACT: ImGui::TextWrapped("%s",_("select a target from the menu at the top of this dialog.")); break; From fb008d7e543e4018938b78ee0f9d0f8e466ff70b Mon Sep 17 00:00:00 2001 From: AArt1256 Date: Sun, 30 Mar 2025 17:29:11 +0300 Subject: [PATCH 5/7] forgot to add myself to the credits before --- src/gui/about.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 7f0fdcdf2e..b3634e99c4 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -34,6 +34,7 @@ const char* aboutLine[]={ "", _N("-- program --"), "tildearrow", + "AArt1256", _N("A M 4 N (intro tune)"), "Adam Lederer", "akumanatt", From 649ed63708e918d279f87d4fe4d44a4bcc55946c Mon Sep 17 00:00:00 2001 From: AArt1256 Date: Sun, 30 Mar 2025 17:32:03 +0300 Subject: [PATCH 6/7] fix 2024 year in some ROM export headers --- src/engine/export/grub.h | 2 +- src/engine/export/ipod.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/export/grub.h b/src/engine/export/grub.h index 422ddf1549..bb5efa76c8 100644 --- a/src/engine/export/grub.h +++ b/src/engine/export/grub.h @@ -1,6 +1,6 @@ /** * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2024 tildearrow and contributors + * Copyright (C) 2021-2025 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 diff --git a/src/engine/export/ipod.h b/src/engine/export/ipod.h index a1c55c0726..4d3d5e7942 100644 --- a/src/engine/export/ipod.h +++ b/src/engine/export/ipod.h @@ -1,6 +1,6 @@ /** * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2024 tildearrow and contributors + * Copyright (C) 2021-2025 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 From 3921637a497a8b97143c8465854035bca36b5e7b Mon Sep 17 00:00:00 2001 From: AArt1256 Date: Sun, 30 Mar 2025 17:40:03 +0300 Subject: [PATCH 7/7] removed some unused variables --- src/engine/export/grub.cpp | 3 --- src/engine/export/ipod.cpp | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/engine/export/grub.cpp b/src/engine/export/grub.cpp index 44b8418ca4..d299ed2a0c 100644 --- a/src/engine/export/grub.cpp +++ b/src/engine/export/grub.cpp @@ -24,9 +24,6 @@ #include #include -constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; -constexpr int MASTER_CLOCK_MASK=(sizeof(void*)==8)?0xff:0; - void DivExportGRUB::run() { bool grubExportBin=conf.getBool("exportBin",false); diff --git a/src/engine/export/ipod.cpp b/src/engine/export/ipod.cpp index 26b8a402fa..729e29f014 100644 --- a/src/engine/export/ipod.cpp +++ b/src/engine/export/ipod.cpp @@ -27,9 +27,6 @@ #include #include -constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; -constexpr int MASTER_CLOCK_MASK=(sizeof(void*)==8)?0xff:0; - void DivExportiPod::run() { int BEEPER=-1; int IGNORED=0;