diff --git a/CMakeLists.txt b/CMakeLists.txt index ca9e188..ac58d82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ set(LOADTRK_SOURCES src/help.cpp src/sound.cpp src/console.cpp + src/colors.cpp src/sid.cpp src/ltlog.cpp src/ltmidi.cpp @@ -81,6 +82,37 @@ set(DATAFILE_SOURCES set(DAT2INC_SOURCES src/tools/dat2inc.cpp) +set(LTRELOC_SOURCES + ${CMAKE_BINARY_DIR}/src/ltrkdata.cpp + src/tools/ltreloc.cpp + src/song.cpp + src/order.cpp + src/pattern.cpp + src/instr.cpp + src/table.cpp + src/play.cpp + src/display.cpp + src/file.cpp + src/reloc.cpp + src/console.cpp + src/colors.cpp + src/ltlog.cpp + src/asm/asm.tab.c + src/asm/chunkpool.c + src/asm/expr.c + src/asm/lex.yy.c + src/asm/log.c + src/asm/map.c + src/asm/buf.c + src/asm/buf_io.c + src/asm/named_buffer.c + src/asm/parse.c + src/asm/pc.c + src/asm/vec.c + src/bme/bme_win.cpp + src/bme/bme_io.cpp + src/bme/bme_end.cpp) + include_directories(${CMAKE_BINARY_DIR}/src) include_directories(${CMAKE_SOURCE_DIR}/src) include_directories(${CMAKE_SOURCE_DIR}/src/bme) @@ -94,9 +126,9 @@ add_executable(loadtrk ${LOADTRK_SOURCES}) add_executable(mod2sng ${MOD2SNG_SOURCES}) add_executable(ins2snd2 ${INS2SND2_SOURCES}) add_executable(sngspli2 ${SNGSPLI2_SOURCES}) +add_executable(ltreloc ${LTRELOC_SOURCES}) - -target_include_directories(datafile PUBLIC SDL3::Headers) +target_compile_definitions(ltreloc PUBLIC LTRELOC) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/src) @@ -116,10 +148,7 @@ add_custom_command( add_custom_target(ltrkdata DEPENDS ${CMAKE_BINARY_DIR}/src/ltrkdata.cpp) add_dependencies(loadtrk ltrkdata) - -target_include_directories(mod2sng PUBLIC SDL3::Headers) -target_include_directories(ins2snd2 PUBLIC SDL3::Headers) -target_include_directories(sngspli2 PUBLIC SDL3::Headers) +add_dependencies(ltreloc ltrkdata) if(MINGW) set(LIB_MINGW mingw32) @@ -129,8 +158,10 @@ OPTION(BUILD_STATIC "Static build" OFF) IF(BUILD_STATIC) set(CMAKE_EXE_LINKER_FLAGS "-static") target_link_libraries(loadtrk SDL3::SDL3-static) + target_link_libraries(ltreloc SDL3::SDL3-static) ELSE() target_link_libraries(loadtrk SDL3::SDL3) + target_link_libraries(ltreloc SDL3::SDL3) ENDIF() find_package(Jack) @@ -205,10 +236,10 @@ endif() include(GNUInstallDirs) -INSTALL(TARGETS loadtrk RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +INSTALL(TARGETS loadtrk ltreloc mod2sng ins2snd2 sngspli2 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) INSTALL(FILES loadtrk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) INSTALL(FILES loadtrk.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons) -INSTALL(FILES doc/en/loadtrk.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) +INSTALL(FILES doc/en/loadtrk.1 doc/en/ltreloc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) INSTALL(DIRECTORY examples DESTINATION ${CMAKE_INSTALL_DATADIR}/loadtrk FILES_MATCHING REGEX ".*\.(sng|ins)") set(PACKAGE_NAME "${PROJECT_NAME}") diff --git a/docs/en/loadtrk.1 b/docs/en/loadtrk.1 index bb7ab41..7ced493 100644 --- a/docs/en/loadtrk.1 +++ b/docs/en/loadtrk.1 @@ -70,7 +70,7 @@ Set speed multiplier (0 for 25Hz, 1 for 1x, 2 for 2x etc.) \fB-V\fIxx\fR Set finevibrato conversion (0 = off, 1 = on) DEFAULT=on .TP -\fB-\fIXxx\fR +\fB-W\fIXxx\fR Set window type (0 = window, 1 = fullscreen) DEFAULT=window .TP \fB-Y\fIxx\fR diff --git a/docs/en/ltreloc.1 b/docs/en/ltreloc.1 new file mode 100644 index 0000000..69bd2d3 --- /dev/null +++ b/docs/en/ltreloc.1 @@ -0,0 +1,83 @@ +.TH LTReloc "Jul 22, 2026" +.SH NAME +ltreloc \- commandline relocator/packer +.SH SYNOPSIS +.B ltreloc +.RI [ songname ] +.RI [ outfile ] +.RI [ options ] +.SH DESCRIPTION +This manual page documents briefly the +.B loadtrk +command. +.PP +\fBltreloc\fP is a commandline relocator/packer based on goattracker's gt2reloc. + +.TP +\fB-A\fIxx\fR +Set ADSR parameter for hardrestart in hex. DEFAULT=0F00 +.TP +\fB-B\fIx\fR +Enable/disable buffered SID writes. DEFAULT=disabled +.TP +\fB-C\fIx\fR +Enable/disable zeropage ghost registers. DEFAULT=disabled +.TP +\fB-D\fIx\fR +Enable/disable sound effect support. DEFAULT=disabled +.TP +\fB-E\fIx\fR +Enable/disable volume change support. DEFAULT=disabled +.TP +\fB-F\fIxx\fR +Set custom SID clock cycles per second (0 = use PAL/NTSC default) +.TP +\fB-G\fIxx\fR +Set pitch of A-4 in Hz (0 = use default frequencytable, close to 440Hz) +.TP +\fB-H\fIx\fR +Enable/disable storing of author info. DEFAULT=disabled +.TP +\fB-I\fIx\fR +Enable/disable optimizations. DEFAULT=enabled +.TP +\fB-J\fIx\fR +Enable/disable full buffering. DEFAULT=disabled +.TP +\fB-L\fIxx\fR +SID memory location in hex. DEFAULT=D400 +.TP +\fB-O\fIxx\fR +Set pulseoptimization/skipping (0 = off, 1 = on) DEFAULT=on +.TP +\fB-R\fIxx\fR +Set realtime-effect optimization/skipping (0 = off, 1 = on) DEFAULT=on +.TP +\fB-S\fIxx\fR +Set speed multiplier (0 for 25Hz, 1 for 1x, 2 for 2x etc.) DEFAULT=1 +.TP +\fB-V\fIxx\fR +Set finevibrato conversion (0 = off, 1 = on) DEFAULT=on +.TP +\fB-W\fIXxx\fR +Player memory location highbyte in hex. DEFAULT=1000 +.TP +\fB-Z\fIxx\fR +Zeropage memory location in hex. DEFAULT=FC +.TP +\fB-N\fR +Use NTSC timing +.TP +\fB-P\fR +Use PAL timing (DEFAULT) +.TP +\fB-?\fR +Show help +.SH SEE ALSO +.BR loadtrk (1) +.br +.SH AUTHOR +ltreloc was written by Lasse \[:O]\[:o]rni, Leandro Nini. +.PP +This manual page was written by G\[:u]rkan Seng\[:u]n , +for the Debian project (but may be used by others). diff --git a/src/colors.cpp b/src/colors.cpp new file mode 100644 index 0000000..746e3b4 --- /dev/null +++ b/src/colors.cpp @@ -0,0 +1,38 @@ +/* + * LoadTracker + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "colors.h" + +Colors colors; + +void initcolorscheme(bool dark) +{ + colors.CBKGND = dark ? CBLACK : CDBLUE; + + colors.CNORMAL = (dark ? CGREY : CLBLUE)|(colors.CBKGND<<4); + colors.CMUTE = CDGREY |(colors.CBKGND<<4); + colors.CEDIT = CLGREEN|(colors.CBKGND<<4); + colors.CPLAYING = CLRED |(colors.CBKGND<<4); + colors.CCOMMAND = CLGREY |(colors.CBKGND<<4); + colors.CTITLE = CWHITE |(colors.CBKGND<<4); + + colors.CHDRBG = dark ? CDBLUE : CLBLUE; + colors.CHDRFG = CYELLOW; + + colors.CHEADER = colors.CHDRFG|(colors.CHDRBG<<4); +} diff --git a/src/colors.h b/src/colors.h new file mode 100644 index 0000000..3d93b44 --- /dev/null +++ b/src/colors.h @@ -0,0 +1,60 @@ +/* + * LoadTracker + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef COLORS_H +#define COLORS_H + +enum +{ + CBLACK = 0x0, + CWHITE = 0x1, + CDRED = 0x2, + CCYAN = 0x3, + CPURPLE = 0x4, + CDGREEN = 0x5, + CDBLUE = 0x6, + CYELLOW = 0x7, + CLBROWN = 0x8, + CDBROWN = 0x9, + CLRED = 0xA, + CDGREY = 0xB, + CGREY = 0xC, + CLGREEN = 0xD, + CLBLUE = 0xE, + CLGREY = 0xF +}; + +struct Colors +{ + unsigned char CBKGND; + unsigned char CNORMAL; + unsigned char CMUTE; + unsigned char CEDIT; + unsigned char CPLAYING; + unsigned char CCOMMAND; + unsigned char CTITLE; + unsigned char CHDRBG; + unsigned char CHDRFG; + unsigned char CHEADER; +}; + +extern Colors colors; + +void initcolorscheme(bool dark); + +#endif diff --git a/src/common.h b/src/common.h index abc483a..23e4f75 100644 --- a/src/common.h +++ b/src/common.h @@ -87,20 +87,6 @@ enum #define VISIBLEPATTROWS 34 #define VISIBLETABLEROWS 15 -struct Colors -{ - unsigned char CBKGND; - unsigned char CNORMAL; - unsigned char CMUTE; - unsigned char CEDIT; - unsigned char CPLAYING; - unsigned char CCOMMAND; - unsigned char CTITLE; - unsigned char CHDRBG; - unsigned char CHDRFG; - unsigned char CHEADER; -}; - struct Instr { unsigned char ad; diff --git a/src/console.cpp b/src/console.cpp index 53e2e9a..cd8e894 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -24,6 +24,7 @@ #include "console.h" +#include "colors.h" #include "configfile.h" #include "loadtrk.h" diff --git a/src/display.cpp b/src/display.cpp index 9629284..1d59285 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -24,6 +24,7 @@ #include "display.h" +#include "colors.h" #include "configfile.h" #include "console.h" #include "instr.h" @@ -45,26 +46,6 @@ #include #include -enum -{ - CBLACK = 0x0, - CWHITE = 0x1, - CDRED = 0x2, - CCYAN = 0x3, - CPURPLE = 0x4, - CDGREEN = 0x5, - CDBLUE = 0x6, - CYELLOW = 0x7, - CLBROWN = 0x8, - CDBROWN = 0x9, - CLRED = 0xA, - CDGREY = 0xB, - CGREY = 0xC, - CLGREEN = 0xD, - CLBLUE = 0xE, - CLGREY = 0xF -}; - const char *notename[] = {"C-0", "C#0", "D-0", "D#0", "E-0", "F-0", "F#0", "G-0", "G#0", "A-0", "A#0", "B-0", "C-1", "C#1", "D-1", "D#1", "E-1", "F-1", "F#1", "G-1", "G#1", "A-1", "A#1", "B-1", @@ -86,23 +67,6 @@ int cursorcolortable[] = { CWHITE, CLGREY, CGREY, CLGREY }; std::string tooltip; -void initcolorscheme(bool dark) -{ - colors.CBKGND = dark ? CBLACK : CDBLUE; - - colors.CNORMAL = (dark ? CGREY : CLBLUE)|(colors.CBKGND<<4); - colors.CMUTE = CDGREY |(colors.CBKGND<<4); - colors.CEDIT = CLGREEN|(colors.CBKGND<<4); - colors.CPLAYING = CLRED |(colors.CBKGND<<4); - colors.CCOMMAND = CLGREY |(colors.CBKGND<<4); - colors.CTITLE = CWHITE |(colors.CBKGND<<4); - - colors.CHDRBG = dark ? CDBLUE : CLBLUE; - colors.CHDRFG = CYELLOW; - - colors.CHEADER = colors.CHDRFG|(colors.CHDRBG<<4); -} - void printmainscreen() { clearscreen(); diff --git a/src/file.cpp b/src/file.cpp index 4600258..0d6716f 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -24,6 +24,7 @@ #include "file.h" +#include "colors.h" #include "console.h" #include "display.h" #include "loadtrk.h" diff --git a/src/help.cpp b/src/help.cpp index fd43f5c..d451979 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -20,6 +20,7 @@ // online help // ============================================================================= +#include "colors.h" #include "console.h" #include "display.h" #include "loadtrk.h" diff --git a/src/loadtrk.cpp b/src/loadtrk.cpp index f16d17e..3f0a74f 100644 --- a/src/loadtrk.cpp +++ b/src/loadtrk.cpp @@ -22,6 +22,7 @@ #include "config.h" +#include "colors.h" #include "configfile.h" #include "console.h" #include "display.h" @@ -85,8 +86,6 @@ unsigned char hexkeytbl[] = {'0', '1', '2', '3', '4', '5', '6', '7', extern unsigned char datafile[]; // from ltrkdata.cpp -Colors colors; - const char* usage[] = { "Usage: loadtrk [songname] [options]", "Options:", @@ -186,7 +185,7 @@ int main(int argc, char **argv) if (!initscreen()) return EXIT_FAILURE; for (int y = 0; y < usagelen; ++y) - printtext(0, y, 15, usage[y]); + printtext(0, y, CLGREY, usage[y]); waitkeynoupdate(); #else for (int y = 0; y < usagelen; ++y) @@ -349,7 +348,7 @@ int main(int argc, char **argv) // Init sound if (!sound_init(mr, writer, sidmodel, ntsc, multiplier, interpolate, customclockrate, exsid, filterbias, combwaves)) { - printtextc(MAX_ROWS/2-1, 15, "Sound init failed. Press any key to run without sound (notice that song timer won't start)"); + printtextc(MAX_ROWS/2-1, CLGREY, "Sound init failed. Press any key to run without sound (notice that song timer won't start)"); waitkeynoupdate(); } @@ -1338,7 +1337,7 @@ void quit() { if ((!shiftpressed) || (mouseb)) { - printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, 15, "Really Quit (y/n)?"); + printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, CLGREY, "Really Quit (y/n)?"); waitkey(); printblank(dpos.statusBottomX, dpos.statusBottomY, 58); if ((key == 'y') || (key == 'Y')) exitprogram = true; @@ -1349,7 +1348,7 @@ void quit() void clear() { - printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, 15, "Optimize everything (y/n)?"); + printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, CLGREY, "Optimize everything (y/n)?"); waitkey(); printblank(dpos.statusBottomX, dpos.statusBottomY, 58); if ((key == 'y') || (key == 'Y')) @@ -1366,27 +1365,27 @@ void clear() bool ct = false; bool cn = false; - printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, 15, "Clear orderlists (y/n)?"); + printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, CLGREY, "Clear orderlists (y/n)?"); waitkey(); printblank(dpos.statusBottomX, dpos.statusBottomY, 58); if ((key == 'y') || (key == 'Y')) cs = true; - printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, 15, "Clear patterns (y/n)?"); + printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, CLGREY, "Clear patterns (y/n)?"); waitkey(); printblank(dpos.statusBottomX, dpos.statusBottomY, 58); if ((key == 'y') || (key == 'Y')) cp = true; - printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, 15, "Clear instruments (y/n)?"); + printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, CLGREY, "Clear instruments (y/n)?"); waitkey(); printblank(dpos.statusBottomX, dpos.statusBottomY, 58); if ((key == 'y') || (key == 'Y')) ci = true; - printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, 15, "Clear tables (y/n)?"); + printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, CLGREY, "Clear tables (y/n)?"); waitkey(); printblank(dpos.statusBottomX, dpos.statusBottomY, 58); if ((key == 'y') || (key == 'Y')) ct = true; - printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, 15, "Clear songname (y/n)?"); + printtextcp(dpos.statusBottomX+29, dpos.statusBottomY, CLGREY, "Clear songname (y/n)?"); waitkey(); printblank(dpos.statusBottomX, dpos.statusBottomY, 58); if ((key == 'y') || (key == 'Y')) cn = true; @@ -1396,7 +1395,7 @@ void clear() bool selectdone = false; unsigned olddpl = defaultpatternlength; - printtext(dpos.statusBottomX+20, dpos.statusBottomY, 15, "Pattern length:"); + printtext(dpos.statusBottomX+20, dpos.statusBottomY, CLGREY, "Pattern length:"); while (!selectdone) { if (patterndispmode) @@ -1792,7 +1791,7 @@ void switchMode() printtextcp( dpos.statusBottomX+29, dpos.statusBottomY, - 15, + CLGREY, textbuffer ); settooltip("Warning: All Songdata Will Be Lost!!!"); diff --git a/src/loadtrk.h b/src/loadtrk.h index 13d6c8c..7450398 100644 --- a/src/loadtrk.h +++ b/src/loadtrk.h @@ -62,7 +62,6 @@ extern char packedpath[MAX_PATHNAME]; extern const char *programname; extern const char *notename[]; extern char textbuffer[MAX_PATHNAME]; -extern Colors colors; #endif void waitkey(); diff --git a/src/reloc.cpp b/src/reloc.cpp index b3ea0d5..b28f59a 100644 --- a/src/reloc.cpp +++ b/src/reloc.cpp @@ -24,6 +24,7 @@ #include "reloc.h" +#include "colors.h" #include "configfile.h" #include "console.h" #include "display.h" @@ -38,6 +39,10 @@ #include "bme_io.h" #include "bme_snd.h" +#ifdef LTRELOC +# include "tools/ltreloc.h" +#endif + extern "C" { #include "buf.h" #include "parse.h" @@ -49,14 +54,6 @@ extern "C" { #include #include -#define PLAYER_BUFFERED 8 -#define PLAYER_SOUNDEFFECTS 16 -#define PLAYER_VOLUME 32 -#define PLAYER_AUTHORINFO 64 -#define PLAYER_ZPGHOSTREGS 128 -#define PLAYER_NOOPTIMIZATION 256 -#define PLAYER_FULLBUFFERED 512 - #define MAX_OPTIONS 7 enum @@ -202,7 +199,7 @@ void relocator() int packedsize = 0; FILE *songhandle = nullptr; -#ifndef GT2RELOC +#ifndef LTRELOC int selectdone; int opt = 0; #endif @@ -580,6 +577,7 @@ void relocator() findtableduplicates(c); // Select playroutine options +#ifndef LTRELOC clearscreen(); printblankc(0, 0, colors.CHEADER, MAX_COLUMNS); if (!std::strlen(loadedsongfilename)) @@ -666,7 +664,7 @@ void relocator() } } if (selectdone == -1) goto PRCLEANUP; - +#endif // Disable optimizations if necessary if (playerversion & PLAYER_NOOPTIMIZATION) { @@ -1014,6 +1012,10 @@ void relocator() if (nopulse) pulsetblsize = 0; if (nofilter) filttblsize = 0; +#ifdef LTRELOC + std::fprintf(STDOUT, "Player address: $%04X\n", playeradr); + std::fprintf(STDOUT, "Zeropage address: $%04X\n", zeropageadr); +#else std::sprintf(textbuffer, "SELECT START ADDRESS: (CURSORS=MOVE, ENTER=ACCEPT, ESC=CANCEL)"); printtext(1, 11, colors.CTITLE, textbuffer); @@ -1139,7 +1141,7 @@ void relocator() } if (selectdone == -1) goto PRCLEANUP; - +#endif // Validate frequencytable parameters if (lastnote < firstnote) lastnote = firstnote; @@ -1496,6 +1498,25 @@ void relocator() } // Print results +#ifdef LTRELOC + std::fprintf(STDOUT, "packing results:\n"); + std::fprintf(STDOUT, "Playroutine: %d bytes\n", playersize); + std::fprintf(STDOUT, "Songtable: %d bytes\n", songtblsize); + std::fprintf(STDOUT, "Song-orderlists: %d bytes\n", songdatasize); + std::fprintf(STDOUT, "Patterntable: %d bytes\n", patttblsize); + std::fprintf(STDOUT, "Patterns: %d bytes\n", pattdatasize); + std::fprintf(STDOUT, "Instruments: %d bytes\n", instrsize); + std::fprintf(STDOUT, "Tables: %d bytes\n", wavetblsize+pulsetblsize+filttblsize+speedtblsize); + std::fprintf(STDOUT, "Total size: %d bytes\n", packedsize); + + songhandle = std::fopen(packedsongname, "wb"); + if (!songhandle) + { + std::fprintf(STDERR, "error: could not open output file '%s'.\n", packedsongname); + goto PRCLEANUP; + } + +#else clearscreen(); printblankc(0, 0, colors.CHEADER, MAX_COLUMNS); if (!std::strlen(loadedsongfilename)) @@ -1641,6 +1662,7 @@ void relocator() } songhandle = std::fopen(packedsongname, "wb"); } +#endif if (fileformat == FORMAT_PRG) { diff --git a/src/reloc.h b/src/reloc.h index 7e87923..f5c973e 100644 --- a/src/reloc.h +++ b/src/reloc.h @@ -35,6 +35,17 @@ enum TYPE_JUMP = 2 }; +enum +{ + PLAYER_BUFFERED = 8, + PLAYER_SOUNDEFFECTS = 16, + PLAYER_VOLUME = 32, + PLAYER_AUTHORINFO = 64, + PLAYER_ZPGHOSTREGS = 128, + PLAYER_NOOPTIMIZATION = 256, + PLAYER_FULLBUFFERED = 512 +}; + #ifndef RELOC_C extern unsigned char pattused[MAX_PATT]; extern unsigned char instrused[MAX_INSTR]; diff --git a/src/tools/ltreloc.cpp b/src/tools/ltreloc.cpp new file mode 100644 index 0000000..9b5cd52 --- /dev/null +++ b/src/tools/ltreloc.cpp @@ -0,0 +1,499 @@ +/* + * LTReloc + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// ============================================================================= +// commandline relocator/packer +// ============================================================================= + +#define LTRELOC_C + +#include "ltreloc.h" + +#include "config.h" + +#include "colors.h" +#include "console.h" +#include "pattern.h" +#include "reloc.h" +#include "sound.h" +#include "file.h" +#include "play.h" +#include "song.h" + +#include "bme_io.h" +#include "bme_win.h" + +#ifdef _WIN32 +# include +#endif + +#include +#include +#include +#include +#include + +enum class EditHdr +{ + NONE = 0, + ADSR = 1, + BPM = 2 +}; + +bool menu = false; +int editmode = 0; +bool recordmode = true; +bool followplay = false; +int hexnybble = -1; +int stepsize = 4; +int defaultpatternlength = 64; +bool exitprogram = false; +int eacolumn = 0; +int eamode = 0; +EditHdr ehmode = EditHdr::NONE; + +unsigned keypreset = KEY_TRACKER; +unsigned playerversion = 0; +int fileformat = FORMAT_PRG; +int zeropageadr = 0xfc; +int playeradr = 0x1000; +unsigned sidmodel = 0; +unsigned multiplier = 1; +unsigned adparam = 0x0f00; +unsigned ntsc = 0; +unsigned patterndispmode = 0; +unsigned sidaddress = 0xd400; +unsigned sid2address = 0xd500; +unsigned finevibrato = 1; +unsigned optimizepulse = 1; +unsigned optimizerealtime = 1; +unsigned customclockrate = 0; +bool usefinevib = false; +unsigned mr = DEFAULTMIXRATE; +unsigned writer = 0; +unsigned interpolate = 0; +unsigned residdelay = 0; +float basepitch = 0.0f; +unsigned numsids = 1; +bool monomode = true; +int snd_bpmtempo = 125; + +#define NUMSIDREGS 0x19 +unsigned char sidreg[NUMSIDREGS]; +unsigned char sidreg2[NUMSIDREGS]; + +char configbuf[MAX_PATHNAME]; +char loadedsongfilename[MAX_FILENAME]; +char songfilename[MAX_FILENAME]; +char songfilter[MAX_FILENAME]; +char songpath[MAX_PATHNAME]; +char instrfilename[MAX_FILENAME]; +char instrfilter[MAX_FILENAME]; +char instrpath[MAX_PATHNAME]; +char packedpath[MAX_PATHNAME]; +char packedsongname[MAX_PATHNAME]; + +const char *programname = "LTReloc v" PACKAGE_VERSION; + +char textbuffer[MAX_PATHNAME]; + +extern unsigned char datafile[]; + +void calculatefreqtable(); +int getMaxChannels(); +int getVisibleOrderlist(); +void waitkeynoupdate(); + +#ifdef _WIN32 +FILE *STDOUT, *STDERR; +#else +# define STDOUT stdout +# define STDERR stderr +#endif + +void usage() +{ + std::fprintf(STDOUT, "Usage: ltreloc [options]\n"); + std::fprintf(STDOUT, "Options:\n"); + std::fprintf(STDOUT, "-Axx Set ADSR parameter for hardrestart in hex. DEFAULT=0F00\n"); + std::fprintf(STDOUT, "-Bx enable/disable buffered SID writes. DEFAULT=disabled\n"); + std::fprintf(STDOUT, "-Cx enable/disable zeropage ghost registers. DEFAULT=disabled\n"); + std::fprintf(STDOUT, "-Dx enable/disable sound effect support. DEFAULT=disabled\n"); + std::fprintf(STDOUT, "-Ex enable/disable volume change support. DEFAULT=disabled\n"); + std::fprintf(STDOUT, "-Fxx Set custom SID clock cycles per second (0 = use PAL/NTSC default)\n"); + std::fprintf(STDOUT, "-Gxx Set pitch of A-4 in Hz (0 = use default frequencytable, close to 440Hz)\n"); + std::fprintf(STDOUT, "-Hx enable/disable storing of author info. DEFAULT=disabled\n"); + std::fprintf(STDOUT, "-Ix enable/disable optimizations. DEFAULT=enabled\n"); + std::fprintf(STDOUT, "-Jx enable/disable full buffering. DEFAULT=disabled\n"); + std::fprintf(STDOUT, "-Lxx SID memory location in hex. DEFAULT=D400\n"); + std::fprintf(STDOUT, "-N Use NTSC timing\n"); + std::fprintf(STDOUT, "-Oxx Set pulseoptimization/skipping (0 = off, 1 = on) DEFAULT=on\n"); + std::fprintf(STDOUT, "-P Use PAL timing (DEFAULT)\n"); + std::fprintf(STDOUT, "-Rxx Set realtime-effect optimization/skipping (0 = off, 1 = on) DEFAULT=on\n"); + std::fprintf(STDOUT, "-Sxx Set speed multiplier (0 for 25Hz, 1 for 1x, 2 for 2x etc.) DEFAULT=1\n"); + std::fprintf(STDOUT, "-Vxx Set finevibrato conversion (0 = off, 1 = on) DEFAULT=on\n"); + std::fprintf(STDOUT, "-Wxx player memory location highbyte in hex. DEFAULT=1000\n"); + std::fprintf(STDOUT, "-Zxx zeropage memory location in hex. DEFAULT=FC\n"); + std::fprintf(STDOUT, "-? Show options\n"); +} + +int main(int argc, char **argv) +{ +#ifdef _WIN32 + /* + SDL_Init() reroutes stdout and stderr, either to stdout.txt and stderr.txt + or to nirwana. simply reopening these handles does, other than suggested on + some web pages, not work reliably - opening new files on CON using different + handles however does. + */ + STDOUT = std::fopen("CON", "w"); + STDERR = std::fopen("CON", "w"); +#endif + + // Open datafile + io_openlinkeddatafile(datafile); + + // Reset channels/song + initchannels(); + clearsong(true,true,true,true,true); + + // get input- and output file names + if (argc >= 3) { + std::strcpy(songfilename, argv[1]); + std::strcpy(packedsongname, argv[2]); + } else { + usage(); + std::exit(EXIT_FAILURE); + } + + // Load song + if (std::strlen(songfilename)) { + loadsong(); + } else { + std::fprintf(STDERR, "error: no song filename given.\n"); + std::exit(EXIT_FAILURE); + } + + int c = std::strlen(packedsongname); + if (std::strlen(packedsongname) <= 0) { + std::fprintf(STDERR, "error: no output filename given.\n"); + std::exit(EXIT_FAILURE); + } + + // determine output format from file extension of the output filename + c--; + while ((c > 0) && (packedsongname[c] != '.')) c--; + if (packedsongname[c] == '.') c++; + + if (!std::strcmp(&packedsongname[c], "sid")) { + fileformat = FORMAT_SID; + } else if (!std::strcmp(&packedsongname[c], "prg")) { + fileformat = FORMAT_PRG; + } else if (!std::strcmp(&packedsongname[c], "bin")) { + fileformat = FORMAT_BIN; + } else { + fileformat = FORMAT_PRG; + } + + std::fprintf(STDOUT, "%s Packer/Relocator\n", programname); + std::fprintf(STDOUT, "song file: %s\n", loadedsongfilename); + std::fprintf(STDOUT, "output file: %s\n", packedsongname); + std::fprintf(STDOUT, "output format: "); + if (fileformat == FORMAT_SID) { + std::fprintf(STDOUT, "sid\n"); + } else if (fileformat == FORMAT_BIN) { + std::fprintf(STDOUT, "bin\n"); + } else { + std::fprintf(STDOUT, "prg\n"); + } + + // Scan command line + for (c = 3; c < argc; c++) + { +#ifdef _WIN32 + if ((argv[c][0] == '-') || (argv[c][0] == '/')) +#else + if (argv[c][0] == '-') +#endif + { + switch(std::toupper(argv[c][1])) + { + case '?': + return 0; + + case 'A': + std::sscanf(&argv[c][2], "%x", &adparam); + break; + + case 'G': + std::sscanf(&argv[c][2], "%f", &basepitch); + break; + + case 'L': + std::sscanf(&argv[c][2], "%x", &sidaddress); + break; + + case 'O': + std::sscanf(&argv[c][2], "%u", &optimizepulse); + break; + + case 'R': + std::sscanf(&argv[c][2], "%u", &optimizerealtime); + break; + + case 'V': + std::sscanf(&argv[c][2], "%u", &finevibrato); + break; + + case 'S': + std::sscanf(&argv[c][2], "%u", &multiplier); + break; + + // NTSC timing + case 'N': + ntsc = 1; + customclockrate = 0; + break; + // PAL timing + case 'P': + ntsc = 0; + customclockrate = 0; + break; + // custom clock rate + case 'F': + std::sscanf(&argv[c][2], "%u", &customclockrate); + break; + + // player options (first menu) + // 0: Buffered SID-writes + case 'B': + if (argv[c][2] == '1') { + playerversion |= PLAYER_BUFFERED; + } else { + playerversion &= ~PLAYER_BUFFERED; + } + break; + // 1: Sound effect support + case 'D': + if (argv[c][2] == '1') { + playerversion |= PLAYER_SOUNDEFFECTS; + } else { + playerversion &= ~PLAYER_SOUNDEFFECTS; + } + break; + // 2: Volume change support + case 'E': + if (argv[c][2] == '1') { + playerversion |= PLAYER_VOLUME; + } else { + playerversion &= ~PLAYER_VOLUME; + } + break; + // 3: Store author-info + case 'H': + if (argv[c][2] == '1') { + playerversion |= PLAYER_AUTHORINFO; + } else { + playerversion &= ~PLAYER_AUTHORINFO; + } + break; + // 4: Use zeropage ghostregs + case 'C': + if (argv[c][2] == '1') { + playerversion |= PLAYER_ZPGHOSTREGS; + } else { + playerversion &= ~PLAYER_ZPGHOSTREGS; + } + break; + // 5: Disable optimization + case 'I': + if (argv[c][2] == '1') { + playerversion &= ~PLAYER_NOOPTIMIZATION; + } else { + playerversion |= PLAYER_NOOPTIMIZATION; + } + break; + // 6: Full buffering + case 'J': + if (argv[c][2] == '1') { + playerversion &= ~PLAYER_FULLBUFFERED; + } else { + playerversion |= PLAYER_FULLBUFFERED; + } + break; + + // start address (second menu) + case 'W': + std::sscanf(&argv[c][2], "%x", (unsigned *)&playeradr); + playeradr<<=8; + break; + + // zeropage address (third menu) + case 'Z': + std::sscanf(&argv[c][2], "%x", (unsigned *)&zeropageadr); + break; + } + } + else + { + std::fprintf(STDERR, "error: unknown option\n"); + usage(); + std::exit(EXIT_FAILURE); + } + } + + // Init colorscheme + initcolorscheme(1); + + // Validate parameters + sidmodel &= 1; + adparam &= 0xffff; + zeropageadr &= 0xff; + playeradr &= 0xff00; + sidaddress &= 0xffff; + + if (multiplier > 16) multiplier = 16; + if ((finevibrato == 1) && (multiplier < 2)) usefinevib = true; + if (finevibrato > 1) usefinevib = true; + if (optimizepulse > 1) optimizepulse = 1; + if (optimizerealtime > 1) optimizerealtime = 1; + if (customclockrate < 100) customclockrate = 0; + + // Calculate frequencytable if necessary + if (basepitch < 0.0f) + basepitch = 0.0f; + if (basepitch > 0.0f) + calculatefreqtable(); + + // perform relocation + relocator(); + + // Exit + return 0; +} + +void waitkeymousenoupdate() +{ +} + +void getparam(FILE *handle, unsigned *value) +{ + char *configptr; + + for (;;) + { + if (std::feof(handle)) return; + std::fgets(configbuf, MAX_PATHNAME, handle); + if ((configbuf[0]) && (configbuf[0] != ';') && (configbuf[0] != ' ') && (configbuf[0] != 13) && (configbuf[0] != 10)) break; + } + + configptr = configbuf; + if (*configptr == '$') + { + *value = 0; + configptr++; + for (;;) + { + char c = tolower(*configptr++); + int h = -1; + + if ((c >= 'a') && (c <= 'f')) h = c - 'a' + 10; + if ((c >= '0') && (c <= '9')) h = c - '0'; + + if (h >= 0) + { + *value *= 16; + *value += h; + } + else break; + } + } + else + { + *value = 0; + for (;;) + { + char c = tolower(*configptr++); + int d = -1; + + if ((c >= '0') && (c <= '9')) d = c - '0'; + + if (d >= 0) + { + *value *= 10; + *value += d; + } + else break; + } + } +} + +void getfloatparam(FILE *handle, float *value) +{ + char *configptr; + + for (;;) + { + if (std::feof(handle)) return; + std::fgets(configbuf, MAX_PATHNAME, handle); + if ((configbuf[0]) && (configbuf[0] != ';') && (configbuf[0] != ' ') && (configbuf[0] != 13) && (configbuf[0] != 10)) break; + } + + configptr = configbuf; + *value = 0.0f; + std::sscanf(configptr, "%f", value); +} + +void calculatefreqtable() +{ + double basefreq = (double)basepitch * (16777216.0 / 985248.0) * std::pow(2.0, 0.25) / 32.0; + int c; + + for (c = 0; c < 8*12 ; c++) + { + double note = c; + double freq = basefreq * std::pow(2.0, note/12.0); + int intfreq = freq + 0.5; + if (intfreq > 0xffff) + intfreq = 0xffff; + freqtbllo[c] = intfreq & 0xff; + freqtblhi[c] = intfreq >> 8; + } +} + +int getMaxChannels() +{ + return (numsids == 1) ? MAX_CHN_MONO : MAX_CHN; +} + +int getVisibleOrderlist() +{ + return (numsids == 1) ? 23 : 14; +} + +void waitkeynoupdate() +{ + for (;;) + { + fliptoscreen(); + getkey(); + if ((rawkey) || (key)) break; + if ((mouseb) && (!prevmouseb)) break; + if (win_quitted) break; + } +} diff --git a/src/tools/ltreloc.h b/src/tools/ltreloc.h new file mode 100644 index 0000000..ac368ca --- /dev/null +++ b/src/tools/ltreloc.h @@ -0,0 +1,31 @@ +/* + * LTReloc + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LTRELOC_H +#define LTRELOC_H + +#ifndef LTRELOC_C +#ifdef _WIN32 +extern FILE *STDOUT, *STDERR; +#else +# define STDOUT stdout +# define STDERR stderr +#endif +#endif + +#endif