diff --git a/src/commands.cpp b/src/commands.cpp index 673179b..b7c94ed 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -946,13 +946,14 @@ void patterncommands() { song.pattern[epnum[epchn]][eppos*4] = newbyte; } - } - if (recordmode && (autoadvance < 1)) - { - eppos++; - if (eppos > getPattlen(epnum[epchn])) + + if (autoadvance < 1) { - eppos = 0; + eppos++; + if (eppos > getPattlen(epnum[epchn])) + { + eppos = 0; + } } } } diff --git a/src/help.cpp b/src/help.cpp index 9f02c9a..e5c911d 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -323,7 +323,7 @@ void onlinehelp(int standalone, int context) left = printrows(0 + offsetX,left,color_normal, tables); left++; } else { - switch(editmode) { + switch (editmode) { case EDIT_PATTERN: printtext(0 + offsetX,left++, color_header, "PATTERN EDIT MODE"); left = printrows(0 + offsetX,left,color_normal, patternkeys); @@ -360,7 +360,7 @@ void onlinehelp(int standalone, int context) } } - if(!lastrow) lastrow=left; + if (!lastrow) lastrow=left; printblank(0, 0, MAX_COLUMNS); printbg(0, 0, colors.CHDRBG, MAX_COLUMNS); diff --git a/src/loadtrk.cpp b/src/loadtrk.cpp index ea3656c..ed7f866 100644 --- a/src/loadtrk.cpp +++ b/src/loadtrk.cpp @@ -1007,14 +1007,7 @@ void mousecommands() save(); if ((input.mousex >= 49) && (input.mousex <= 57)) { - if (config.numsids == 1) - { - relocator(loadedsongfilename); - } - else if (config.numsids == 2) - { - relocator_stereo(loadedsongfilename); - } + relocator(loadedsongfilename); } if ((input.mousex >= 59) && (input.mousex <= 64)) onlinehelp(0,0); @@ -1220,14 +1213,7 @@ void generalcommands() case KEY_F9: if (!input.shiftpressed) { - if (config.numsids == 1) - { - relocator(loadedsongfilename); - } - else if (config.numsids == 2) - { - relocator_stereo(loadedsongfilename); - } + relocator(loadedsongfilename); } else if (input.shiftpressed && (config.numsids == 2)) { diff --git a/src/reloc.cpp b/src/reloc.cpp index 8f45d38..fa5d51d 100644 --- a/src/reloc.cpp +++ b/src/reloc.cpp @@ -46,7 +46,7 @@ #endif #include "asm/buf.h" -#include "asm/log.h" +//#include "asm/log.h" #include "asm/parse.h" #include @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -291,10 +292,28 @@ void initreloc() tableerror = ErrorType::NONE; } +bool checklen(int c, bool dual) +{ + bool res = (song.len[c][0]) && + (song.len[c][1]) && + (song.len[c][2]); + if (dual) + { + res &= (song.len[c][3]) && + (song.len[c][4]) && + (song.len[c][5]); + } + return res; +} + void relocator(const char* filename) { + bool dual = config.numsids == 2; unsigned char *packeddata = nullptr; - const char *playername = (config.adparam < 0xf000) ? "player.s" : "altplayer.s"; + std::string playername = (config.adparam < 0xf000) ? "player" : "altplayer"; + if (dual) + playername.append("_s"); + playername.append(".s"); unsigned char pattmap[MAX_PATT]; DataInf patt[MAX_PATT]; @@ -349,21 +368,24 @@ void relocator(const char* filename) stopsong(); + // this errors out, hopefully we don't need to debug players + // asm/log.h:124:59: error: invalid conversion from ‘int’ to ‘log_level’ [-fpermissive] //LOG_INIT_CONSOLE(LOG_NORMAL); parse_init(); buf_free(&src); buf_free(&dest); int maxChns = config.getMaxChannels(); - +#ifndef LTRELOC + int ypos; +#endif // Process song-orderlists countpatternlengths(); + // Calculate amount of songs with nonzero length for (int c = 0; c < MAX_SONGS; c++) { - if ((song.len[c][0]) && - (song.len[c][1]) && - (song.len[c][2])) + if (checklen(c, dual)) { // See which patterns are used in this song for (int d = 0; d < maxChns; d++) @@ -618,6 +640,13 @@ void relocator(const char* filename) for (int c = 0; c < MAX_TABLES; c++) findtableduplicates(c); + if (dual) + { + // Force options for dual sid tunes + config.playerversion |= PLAYER_BUFFERED; + config.playerversion &= ~PLAYER_ZPGHOSTREGS; + } + // Select playroutine options #ifndef LTRELOC clearscreen(); @@ -630,18 +659,23 @@ void relocator(const char* filename) printtext(1, 0, colors.CHEADER, textbuffer); printtext(1, 2, colors.CTITLE, "SELECT PLAYROUTINE OPTIONS: (CURSORS=MOVE/CHANGE, ENTER=ACCEPT, ESC=CANCEL)"); - if (config.multiplier == 1 && snd_bpmtempo != 125) + if (!dual) { - ciaval = 19566 - ((19655 / 125) * (snd_bpmtempo - 125)); + if (config.multiplier == 1 && snd_bpmtempo != 125) + { + ciaval = 19566 - ((19655 / 125) * (snd_bpmtempo - 125)); - std::snprintf(textbuffer, MAX_PATHNAME, "[INFO] CIA timer value for %03d BPM: $%04X", snd_bpmtempo, ciaval); - printtext(1, 3+MAX_OPTIONS+8, colors.CEDIT, textbuffer); + std::snprintf(textbuffer, MAX_PATHNAME, "[INFO] CIA timer value for %03d BPM: $%04X", snd_bpmtempo, ciaval); + printtext(1, 3+MAX_OPTIONS+8, colors.CEDIT, textbuffer); + } } selectdone = 0; while (!selectdone) { - for (int c = 0; c < MAX_OPTIONS; c++) + int opts = MAX_OPTIONS; + if (dual) opts--; + for (int c = 0; c < opts; c++) { int color = (opt == c) ? colors.CEDIT : colors.CNORMAL; @@ -668,7 +702,9 @@ void relocator(const char* filename) config.playerversion ^= (PLAYER_BUFFERED << opt); if (opt) { - if ((config.playerversion & PLAYER_SOUNDEFFECTS) || (config.playerversion & PLAYER_ZPGHOSTREGS) || (config.playerversion & PLAYER_FULLBUFFERED)) + if ((config.playerversion & PLAYER_SOUNDEFFECTS) || + (config.playerversion & PLAYER_ZPGHOSTREGS) || + (!dual && (config.playerversion & PLAYER_FULLBUFFERED))) config.playerversion |= PLAYER_BUFFERED; } else @@ -677,7 +713,7 @@ void relocator(const char* filename) { config.playerversion &= ~PLAYER_SOUNDEFFECTS; config.playerversion &= ~PLAYER_ZPGHOSTREGS; - config.playerversion &= ~PLAYER_FULLBUFFERED; + if (!dual) config.playerversion &= ~PLAYER_FULLBUFFERED; } } break; @@ -700,6 +736,12 @@ void relocator(const char* filename) selectdone = 1; break; } + + if (dual) + { + config.playerversion |= PLAYER_BUFFERED; + config.playerversion &= ~PLAYER_ZPGHOSTREGS; + } } if (selectdone == -1) goto PRCLEANUP; #endif @@ -746,12 +788,19 @@ void relocator(const char* filename) } // Make sure buffering is used if it is needed - if ((config.playerversion & PLAYER_SOUNDEFFECTS) || (config.playerversion & PLAYER_ZPGHOSTREGS) || (config.playerversion & PLAYER_FULLBUFFERED)) + if ((config.playerversion & PLAYER_SOUNDEFFECTS) || + (config.playerversion & PLAYER_ZPGHOSTREGS) || + (!dual && (config.playerversion & PLAYER_FULLBUFFERED))) config.playerversion |= PLAYER_BUFFERED; - // Sound effect or ghostreg players always use full 3 channels - if ((config.playerversion & PLAYER_SOUNDEFFECTS) || (config.playerversion & PLAYER_FULLBUFFERED) || (config.playerversion & PLAYER_ZPGHOSTREGS)) - channels = maxChns; + if (!dual) + { + // Sound effect or ghostreg players always use full 3 channels + if ((config.playerversion & PLAYER_SOUNDEFFECTS) || + (config.playerversion & PLAYER_FULLBUFFERED) || + (config.playerversion & PLAYER_ZPGHOSTREGS)) + channels = maxChns; + } // Allocate memory for song-orderlists songtblsize = songs*6; @@ -766,9 +815,7 @@ void relocator(const char* filename) songdatasize = 0; for (int c = 0; c < songs; c++) { - if ((song.len[c][0]) && - (song.len[c][1]) && - (song.len[c][2])) + if (checklen(c, dual)) { for (int d = 0; d < maxChns; d++) { @@ -1043,14 +1090,15 @@ void relocator(const char* filename) std::fprintf(STDOUT, "Player address: $%04X\n", config.playeradr); std::fprintf(STDOUT, "Zeropage address: $%04X\n", config.zeropageadr); #else + ypos = dual ? 10 : 11; std::snprintf(textbuffer, MAX_PATHNAME, "SELECT START ADDRESS: (CURSORS=MOVE, ENTER=ACCEPT, ESC=CANCEL)"); - printtext(1, 11, colors.CTITLE, textbuffer); + printtext(1, ypos, colors.CTITLE, textbuffer); selectdone = 0; while (!selectdone) { std::snprintf(textbuffer, MAX_PATHNAME, "$%04X", config.playeradr); - printtext(1, 12, colors.CEDIT, textbuffer); + printtext(1, ypos+1, colors.CEDIT, textbuffer); fliptoscreen(); waitkeynoupdate(); @@ -1096,7 +1144,7 @@ void relocator(const char* filename) if (selectdone == -1) goto PRCLEANUP; std::snprintf(textbuffer, MAX_PATHNAME, "SELECT ZEROPAGE ADDRESS: (CURSORS=MOVE, ENTER=ACCEPT, ESC=CANCEL)"); - printtext(1, 14, colors.CTITLE, textbuffer); + printtext(1, ypos+3, colors.CTITLE, textbuffer); selectdone = 0; while (!selectdone) @@ -1128,7 +1176,7 @@ void relocator(const char* filename) std::snprintf(textbuffer, MAX_PATHNAME, "$%02X-$%02X (ghostregs start at %02X)", config.zeropageadr, config.zeropageadr+26, config.zeropageadr); } - printtext(1, 15, colors.CEDIT, textbuffer); + printtext(1, ypos+4, colors.CEDIT, textbuffer); fliptoscreen(); waitkeynoupdate(); @@ -1188,12 +1236,15 @@ void relocator(const char* filename) insertdefine("base", config.playeradr); insertdefine("zpbase", config.zeropageadr); insertdefine("SIDBASE", config.sidaddress); + if (dual) + insertdefine("SID2BASE", config.sid2address); // Insert conditionals insertdefine("SOUNDSUPPORT", (config.playerversion & PLAYER_SOUNDEFFECTS) ? 1 : 0); insertdefine("VOLSUPPORT", (config.playerversion & PLAYER_VOLUME) ? 1 : 0); insertdefine("BUFFEREDWRITES", (config.playerversion & PLAYER_BUFFERED) ? 1 : 0); - insertdefine("GHOSTREGS", (config.playerversion & (PLAYER_ZPGHOSTREGS|PLAYER_FULLBUFFERED)) ? 1 : 0); + if (!dual) + insertdefine("GHOSTREGS", (config.playerversion & (PLAYER_ZPGHOSTREGS|PLAYER_FULLBUFFERED)) ? 1 : 0); insertdefine("ZPGHOSTREGS", (config.playerversion & PLAYER_ZPGHOSTREGS) ? 1 : 0); insertdefine("FIXEDPARAMS", fixedparams); insertdefine("SIMPLEPULSE", simplepulse); @@ -1257,23 +1308,26 @@ void relocator(const char* filename) } // Insert source code of player - if (!insertfile(playername)) + if (!insertfile(playername.c_str())) { error("COULD NOT OPEN PLAYROUTINE!"); goto PRCLEANUP; } - // Modify ghostregs to not be zeropage if needed - if ((config.playerversion & PLAYER_FULLBUFFERED) && (config.playerversion & PLAYER_ZPGHOSTREGS) == 0) + if (!dual) { - int bufsize = buf_size(&src); - char* bufdata = (char*)buf_data(&src); - for (int c = 0; c < bufsize; c++) + // Modify ghostregs to not be zeropage if needed + if ((config.playerversion & PLAYER_FULLBUFFERED) && (config.playerversion & PLAYER_ZPGHOSTREGS) == 0) { - if (bufdata[c] == '<') + int bufsize = buf_size(&src); + char* bufdata = (char*)buf_data(&src); + for (int c = 0; c < bufsize; c++) { - if (std::memcmp(bufdata + c + 1, "ghost", 5) == 0) - bufdata[c] = ' '; + if (bufdata[c] == '<') + { + if (std::memcmp(bufdata + c + 1, "ghost", 5) == 0) + bufdata[c] = ' '; + } } } } @@ -1696,6 +1750,7 @@ void relocator(const char* filename) if (config.fileformat == FORMAT_SID) { unsigned char ident[] = {'P', 'S', 'I', 'D', 0x00, 0x02, 0x00, 0x7c}; + if (dual) ident[5] = 0x03; unsigned char byte; // Identification std::fwrite(ident, sizeof ident, 1, songhandle); @@ -1755,7 +1810,10 @@ void relocator(const char* filename) // Song speed bits byte = 0x00; - if ((config.ntsc) || (config.multiplier > 1) || (!config.multiplier) || (ciaval)) byte = 0xff; + if ((config.ntsc) || + (config.multiplier > 1) || + (!config.multiplier) || + (!dual && ciaval)) byte = 0xff; fwrite8(songhandle, byte); fwrite8(songhandle, byte); fwrite8(songhandle, byte); @@ -1771,15 +1829,20 @@ void relocator(const char* filename) fwrite8(songhandle, byte); if (config.ntsc) byte = 8; else byte = 4; - if (config.sidmodel) byte |= 32; - else byte |= 16; + if (config.sidmodel) + byte |= dual ? 32 + 128 : 32; + else + byte |= dual ? 16 + 64 : 16; fwrite8(songhandle, byte); - // Reserved longword + // reserved bytes and second SID address if any byte = 0x00; fwrite8(songhandle, byte); fwrite8(songhandle, byte); - fwrite8(songhandle, byte); + if (dual) + fwrite8(songhandle, (config.sid2address & 0x0ff0) >> 4); + else + fwrite8(songhandle, byte); fwrite8(songhandle, byte); // Load address @@ -2289,1511 +2352,6 @@ void calcspeedtest(unsigned char pos) else nonormalspeed = 0; } -void relocator_stereo(const char* filename) -{ - unsigned char *packeddata = nullptr; - const char *playername = (config.adparam < 0xf000) ? "player_s.s" : "altplayer_s.s"; - - unsigned char pattmap[MAX_PATT]; - DataInf patt[MAX_PATT]; - DataInf sng[MAX_SONGS][MAX_CHN]; - - TabError taberr; - int patterns = 0; - int songs = 0; - int instruments = 0; - int numlegato = 0; - int numnohr = 0; - int numnormal = 0; - int freenormal; - int freenohr; - int freelegato; - int transuprange = 0; - int transdownrange = 0; - int pattdatasize = 0; - int patttblsize = 0; - int songdatasize = 0; - int songtblsize = 0; - int instrsize = 0; - int wavetblsize = 0; - int pulsetblsize = 0; - int filttblsize = 0; - int speedtblsize = 0; - int playersize = 0; - int packedsize = 0; - - FILE *songhandle = nullptr; -#ifndef LTRELOC - int selectdone; - int opt = 0; -#endif - unsigned char speedcode[] = {0xa2,0x00,0x8e,0x04,0xdc,0xa2,0x00,0x8e,0x05,0xdc}; - - unsigned char patttemp[512]; - unsigned char *songwork = nullptr; - unsigned char *pattwork = nullptr; - unsigned char *instrwork = nullptr; - - int ciaval = 0; - - int channels = config.getMaxChannels(); - int fixedparams = 1; - int simplepulse = 1; - int firstnote = MAX_NOTES-1; - int lastnote = 0; - int patternlastnote = 0; - - initreloc(); - - stopsong(); - - //LOG_INIT_CONSOLE(LOG_NORMAL); - parse_init(); - buf_free(&src); - buf_free(&dest); - - int maxChns = config.getMaxChannels(); - - // Process song-orderlists - countpatternlengths(); - // Calculate amount of songs with nonzero length - for (int c = 0; c < MAX_SONGS; c++) - { - if ((song.len[c][0]) && - (song.len[c][1]) && - (song.len[c][2])) - { - // See which patterns are used in this song - for (int d = 0; d < maxChns; d++) - { - songdatasize += song.len[c][d]+2; - for (int e = 0; e < song.len[c][d]; e++) - { - if (song.order[c][d][e] < REPEAT) - { - int num = song.order[c][d][e]; - - pattused.set(num); - for (int f = 0; f < getPattlen(num); f++) - { - if ((song.pattern[num][f*4] != REST) || (song.pattern[num][f*4+1]) || (song.pattern[num][f*4+2])) - chnused.set(d); - } - } - else - { - if (song.order[c][d][e] >= TRANSDOWN) - { - notrans = 0; - if (song.order[c][d][e] < TRANSUP) - { - int newtransdownrange = -(song.order[c][d][e] - TRANSUP); - if (newtransdownrange > transdownrange) transdownrange = newtransdownrange; - } - else - { - int newtransuprange = song.order[c][d][e] - TRANSUP; - if (newtransuprange > transuprange) transuprange = newtransuprange; - } - } - else norepeat = 0; - } - } - if (song.order[c][d][song.len[c][d]+1] >= song.len[c][d]) - { - std::snprintf(textbuffer, MAX_PATHNAME, "ILLEGAL SONG RESTART POSITION! (SUBTUNE %02X, CHANNEL %d)", c, d+1); - error(textbuffer); - goto PRCLEANUP_S; - } - } - songs++; - } - } - - if (!songs) - { - error("NO SONGS, NO DATA TO SAVE!"); - goto PRCLEANUP_S; - } - - // Optimize amount of used channels - for (int c = maxChns-1; c; c--) - { - if (chnused.test(c)) - break; - channels = c; - } - - // Build the pattern-mapping - // Instrument 1 is always used - instr[1].used = true; - for (int c = 0; c < MAX_PATT; c++) - { - if (pattused.test(c)) - { - pattmap[c] = patterns; - patterns++; - - // See which instruments/tablecommands are used - for (int d = 0; d < getPattlen(c); d++) - { - tableerror = ErrorType::NONE; - - if ((song.pattern[c][d*4] == KEYOFF) || (song.pattern[c][d*4] == KEYON)) - nogate = 0; - if (song.pattern[c][d*4+1]) - instr[song.pattern[c][d*4+1]].used = true; - if (song.pattern[c][d*4+2]) - noeffects = 0; - if ((song.pattern[c][d*4+2] >= CMD_SETWAVEPTR) && (song.pattern[c][d*4+2] <= CMD_SETFILTERPTR)) - exectable(song.pattern[c][d*4+2] - CMD_SETWAVEPTR, song.pattern[c][d*4+3]); - if ((song.pattern[c][d*4+2] >= CMD_PORTAUP) && (song.pattern[c][d*4+2] <= CMD_VIBRATO)) - { - exectable(STBL, song.pattern[c][d*4+3]); - calcspeedtest(song.pattern[c][d*4+3]); - } - if (song.pattern[c][d*4+2] == CMD_FUNKTEMPO) - exectable(STBL, song.pattern[c][d*4+3]); - if (song.pattern[c][d*4+2] == CMD_FUNKTEMPO) - { - nofunktempo = 0; - noglobaltempo = 0; - } - if ((song.pattern[c][d*4+2] == CMD_SETTEMPO) && ((song.pattern[c][d*4+3] & 0x7f) < 3)) nofunktempo = 0; - - // See, which are the highest/lowest notes used - if ((song.pattern[c][d*4] >= FIRSTNOTE) && (song.pattern[c][d*4] <= LASTNOTE)) - { - int newfirstnote = song.pattern[c][d*4] - FIRSTNOTE - transdownrange; - int newlastnote = song.pattern[c][d*4] - FIRSTNOTE + transuprange; - if (newfirstnote < 0) newfirstnote = 0; - if (newlastnote > MAX_NOTES-1) newlastnote = MAX_NOTES-1; - - if (newfirstnote < firstnote) firstnote = newfirstnote; - if (newlastnote > lastnote) - { - patternlastnote = newlastnote; - lastnote = newlastnote; - } - if (newfirstnote > lastnote) - { - patternlastnote = newfirstnote; - lastnote = newfirstnote; - } - } - if ((tableerror != ErrorType::NONE) && (taberr.type == ErrorType::NONE)) - { - taberr.type = tableerror; - taberr.cause = Cause::PATTERN; - taberr.source1 = c; - taberr.source2 = d; - } - } - } - } - - // Count amount of normal, nohr, and legato instruments - // Also see if special first wave parameters are used - for (int c = 0; c < MAX_INSTR; c++) - { - if (instr[c].used) - { - if (song.instr[c].gatetimer & 0x40) numlegato++; - else - { - if (song.instr[c].gatetimer & 0x80) numnohr++; - else numnormal++; - } - if ((!song.instr[c].firstwave) || (song.instr[c].firstwave >= 0xfe)) - nofirstwavecmd = 0; - } - } - freenormal = 1; - freenohr = freenormal + numnormal; - freelegato = freenohr + numnohr; - - // Build the instrument-mapping - for (int c = 0; c < MAX_INSTR; c++) - { - if (instr[c].used) - { - if (song.instr[c].gatetimer & 0x40) instr[c].map = freelegato++; - else - { - if (song.instr[c].gatetimer & 0x80) instr[c].map = freenohr++; - else instr[c].map = freenormal++; - } - instruments++; - for (int d = 0; d < MAX_TABLES; d++) - { - tableerror = ErrorType::NONE; - exectable(d, song.instr[c].ptr[d]); - if (d == STBL) calcspeedtest(song.instr[c].ptr[d]); - if ((tableerror != ErrorType::NONE) && (taberr.type == ErrorType::NONE)) - { - taberr.type = tableerror; - taberr.cause = Cause::INSTRUMENT; - taberr.source1 = c; - taberr.source2 = d; - } - } - } - } - - // Execute tableprograms invoked from wavetable commands - for (int c = 0; c < MAX_TABLELEN; c++) - { - if (table[WTBL][c+1].used) - { - if ((song.ltable[WTBL][c] >= WAVECMD) && (song.ltable[WTBL][c] <= WAVELASTCMD)) - { - int d = -1; - tableerror = ErrorType::NONE; - - switch(song.ltable[WTBL][c] - WAVECMD) - { - case CMD_PORTAUP: - case CMD_PORTADOWN: - case CMD_TONEPORTA: - case CMD_VIBRATO: - d = STBL; - calcspeedtest(song.rtable[WTBL][c]); - break; - - case CMD_SETPULSEPTR: - d = PTBL; - nopulse = 0; - break; - - case CMD_SETFILTERPTR: - d = FTBL; - nofilter = 0; - break; - - case CMD_DONOTHING: - case CMD_SETWAVEPTR: - case CMD_FUNKTEMPO: - std::snprintf(textbuffer, MAX_PATHNAME, "ILLEGAL WAVETABLE COMMAND (ROW %02X, COMMAND %X)", c+1, song.ltable[WTBL][c] - WAVECMD); - error(textbuffer); - goto PRCLEANUP_S; - } - - if (d != -1) exectable(d, song.rtable[WTBL][c]); - - if ((tableerror != ErrorType::NONE) && (taberr.type == ErrorType::NONE)) - { - taberr.type = tableerror; - taberr.cause = Cause::WAVE_CMD; - taberr.source1 = c+1; - taberr.source2 = d; - } - } - } - } - - // Build the table-mapping - for (int c = 0; c < MAX_TABLES; c++) - { - unsigned char e = 1; - for (int d = 0; d < MAX_TABLELEN; d++) - { - if (table[c][d+1].used) - { - table[c][d+1].map = e; - e++; - } - } - } - - // Check for table errors - if (taberr.cause != Cause::NONE) - { - table_error(taberr); - goto PRCLEANUP_S; - } - - // Find duplicate ranges in tables - for (int c = 0; c < MAX_TABLES; c++) - findtableduplicates(c); - - // Force options for dual sid tunes - config.playerversion |= PLAYER_BUFFERED; - config.playerversion &= ~PLAYER_ZPGHOSTREGS; - - // Select playroutine options -#ifndef LTRELOC - clearscreen(); - printblankc(0, 0, colors.CHEADER, MAX_COLUMNS); - if (!std::strlen(filename)) - std::snprintf(textbuffer, MAX_PATHNAME, "%s Packer/Relocator", programname); - else - std::snprintf(textbuffer, MAX_PATHNAME, "%s Packer/Relocator - %s", programname, filename); - textbuffer[MAX_COLUMNS] = 0; - printtext(1, 0, colors.CHEADER, textbuffer); - printtext(1, 2, colors.CTITLE, "SELECT PLAYROUTINE OPTIONS: (CURSORS=MOVE/CHANGE, ENTER=ACCEPT, ESC=CANCEL)"); - - selectdone = 0; - while (!selectdone) - { - for (int c = 0; c < (MAX_OPTIONS-1); c++) - { - int color = (opt == c) ? colors.CEDIT : colors.CNORMAL; - - printtext(1, 3+c, color, playeroptname[c]); - if (config.playerversion & (PLAYER_BUFFERED << c)) - printtext(24, 3+c, color, "Yes"); - else - printtext(24, 3+c, color, "No "); - } - fliptoscreen(); - waitkeynoupdate(); - - if (win_quitted) - { - exitprogram = true; - goto PRCLEANUP_S; - } - - switch(input.rawkey) - { - case KEY_LEFT: - case KEY_RIGHT: - case KEY_SPACE: - config.playerversion ^= (PLAYER_BUFFERED << opt); - if (opt) - { - if ((config.playerversion & PLAYER_SOUNDEFFECTS) || (config.playerversion & PLAYER_ZPGHOSTREGS)) - config.playerversion |= PLAYER_BUFFERED; - } - else - { - if (!(config.playerversion & PLAYER_BUFFERED)) - { - config.playerversion &= ~PLAYER_SOUNDEFFECTS; - config.playerversion &= ~PLAYER_ZPGHOSTREGS; - } - } - break; - - case KEY_UP: - opt--; - if (opt < 0) opt = MAX_OPTIONS-1; - break; - - case KEY_DOWN: - opt++; - if (opt >= MAX_OPTIONS) opt = 0; - break; - - case KEY_ESC: - selectdone = -1; - break; - - case KEY_ENTER: - selectdone = 1; - break; - } - - config.playerversion |= PLAYER_BUFFERED; - config.playerversion &= ~PLAYER_ZPGHOSTREGS; - } - if (selectdone == -1) goto PRCLEANUP_S; -#endif - - // Disable optimizations if necessary - if (config.playerversion & PLAYER_NOOPTIMIZATION) - { - fixedparams = 0; - if (!numlegato) numlegato++; - - simplepulse = 0; - firstnote = 0; - lastnote = MAX_NOTES-1; - nogate = 0; - noeffects = 0; - nofilter = 0; - nofiltermod = 0; - nopulse = 0; - nopulsemod = 0; - nowavedelay = 0; - nowavecmd = 0; - norepeat = 0; - notrans = 0; - noportamento = 0; - notoneporta = 0; - novib = 0; - noinsvib = 0; - nosetad = 0; - nosetsr = 0; - nosetwave = 0; - nosetwaveptr = 0; - nosetpulseptr = 0; - nosetfiltptr = 0; - nosetfiltcutoff = 0; - nosetfiltctrl = 0; - nosetmastervol = 0; - nofunktempo = 0; - noglobaltempo = 0; - nochanneltempo = 0; - nofirstwavecmd = 0; - nocalculatedspeed = 0; - nonormalspeed = 0; - nozerospeed = 0; - } - - // Make sure buffering is used if it is needed - if ((config.playerversion & PLAYER_SOUNDEFFECTS) || (config.playerversion & PLAYER_ZPGHOSTREGS)) - config.playerversion |= PLAYER_BUFFERED; - - // Allocate memory for song-orderlists - songtblsize = songs*6; - songwork = new (std::nothrow) unsigned char[songdatasize]; - if (!songwork) - { - error("OUT OF MEMORY IN PACKER/RELOCATOR!"); - goto PRCLEANUP_S; - } - - // Generate song.orderlists & songtable - songdatasize = 0; - for (int c = 0; c < songs; c++) - { - if ((song.len[c][0]) && - (song.len[c][1]) && - (song.len[c][2])) - { - for (int d = 0; d < maxChns; d++) - { - sng[c][d].offset = songdatasize; - sng[c][d].size = song.len[c][d] + 2; - - int e; - for (e = 0; e < song.len[c][d]; e++) - { - // Pattern - if (song.order[c][d][e] < REPEAT) - songwork[songdatasize++] = pattmap[song.order[c][d][e]]; - else - { - // Transpose - if (song.order[c][d][e] >= TRANSDOWN) - { - songwork[songdatasize++] = song.order[c][d][e]; - } - // Repeat sequence: must be swapped - else - { - // See that repeat amount is more than 1 - if (song.order[c][d][e] > REPEAT) - { - // Insanity check that a pattern indeed follows - if (song.order[c][d][e+1] < REPEAT) - { - songwork[songdatasize++] = pattmap[song.order[c][d][e+1]]; - songwork[songdatasize++] = song.order[c][d][e]; - e++; - } - else - songwork[songdatasize++] = song.order[c][d][e]; - } - } - } - } - // Endmark & repeat position - songwork[songdatasize++] = song.order[c][d][e++]; - songwork[songdatasize++] = song.order[c][d][e++]; - } - } - else - { - for (int d = 0; d < maxChns; d++) - { - sng[c][d].offset = songdatasize; - sng[c][d].size = 0; - } - } - } - - // Calculate total size of patterns - for (int c = 0; c < MAX_PATT; c++) - { - if (pattused.test(c)) - { - int result = packpattern(patttemp, song.pattern[c], getPattlen(c)); - - if (result < 0) - { - std::snprintf(textbuffer, MAX_PATHNAME, "PATTERN %02X IS TOO COMPLEX (OVER 256 BYTES PACKED)!", c); - error(textbuffer); - goto PRCLEANUP_S; - } - pattdatasize += result; - } - } - - patttblsize = patterns*2; - pattwork = new (std::nothrow) unsigned char[pattdatasize]; - if (!pattwork) - { - error("OUT OF MEMORY IN PACKER/RELOCATOR!"); - goto PRCLEANUP_S; - } - - // This time pack the patterns for real - pattdatasize = 0; - for (int c = 0, d = 0; c < MAX_PATT; c++) - { - if (pattused.test(c)) - { - patt[d].offset = pattdatasize; - patt[d].size = packpattern(&pattwork[pattdatasize], song.pattern[c], getPattlen(c)); - pattdatasize += patt[d].size; - d++; - } - } - - // Then process instruments - instrsize = instruments*9; - instrwork = new (std::nothrow) unsigned char[instrsize]; - if (!instrwork) - { - error("OUT OF MEMORY IN PACKER/RELOCATOR!"); - goto PRCLEANUP_S; - } - - for (int c = 1; c < MAX_INSTR; c++) - { - if (instr[c].used) - { - int d = instr[c].map - 1; - instrwork[d] = song.instr[c].ad; - instrwork[d+instruments] = song.instr[c].sr; - instrwork[d+instruments*2] = table[WTBL][song.instr[c].ptr[WTBL]].map; - instrwork[d+instruments*3] = table[PTBL][song.instr[c].ptr[PTBL]].map; - instrwork[d+instruments*4] = table[FTBL][song.instr[c].ptr[FTBL]].map; - if (song.instr[c].vibdelay) - { - instrwork[d+instruments*5] = table[STBL][song.instr[c].ptr[STBL]].map; - instrwork[d+instruments*6] = song.instr[c].vibdelay - 1; - } - else - { - instrwork[d+instruments*5] = 0; - instrwork[d+instruments*6] = 0; - } - instrwork[d+instruments*7] = song.instr[c].gatetimer & 0x3f; - instrwork[d+instruments*8] = song.instr[c].firstwave; - - if (song.instr[c].ptr[STBL]) - { - novib = 0; - noinsvib = 0; - } - if (song.instr[c].ptr[PTBL]) - nopulse = 0; - if (song.instr[c].ptr[FTBL]) - nofilter = 0; - - // See if all instruments use same gatetimer & firstwave parameters - if ((song.instr[c].gatetimer != song.instr[1].gatetimer) || - (song.instr[c].firstwave != song.instr[1].firstwave)) - fixedparams = 0; - // or if special firstwave commands are in use - if ((!song.instr[c].firstwave) || (song.instr[c].firstwave >= 0xfe)) - fixedparams = 0; - } - } - - // Disable sameparam optimization for multispeed stability - if (config.multiplier > 1) - { - fixedparams = 0; - numlegato++; - numnohr++; - } - - if (fixedparams) instrsize -= instruments*2; - if (noinsvib) instrsize -= instruments*2; - if (nopulse) instrsize -= instruments; - if (nofilter) instrsize -= instruments; - - // Process tables - for (int c = 0; c < MAX_TABLELEN; c++) - { - if (table[WTBL][c+1].used) - { - wavetblsize += 2; - if ((song.ltable[WTBL][c] >= WAVEDELAY) && (song.ltable[WTBL][c] <= WAVELASTDELAY)) nowavedelay = 0; - if ((song.ltable[WTBL][c] >= WAVECMD) && (song.ltable[WTBL][c] <= WAVELASTCMD)) - { - nowavecmd = 0; - noeffects = 0; - switch (song.ltable[WTBL][c] - WAVECMD) - { - case CMD_PORTAUP: - case CMD_PORTADOWN: - noportamento = 0; - break; - - case CMD_TONEPORTA: - notoneporta = 0; - break; - - case CMD_VIBRATO: - novib = 0; - break; - - case CMD_SETAD: - nosetad = 0; - break; - - case CMD_SETSR: - nosetsr = 0; - break; - - case CMD_SETWAVE: - nosetwave = 0; - break; - - case CMD_SETPULSEPTR: - nosetpulseptr = 0; - break; - - case CMD_SETFILTERPTR: - nosetfiltptr = 0; - break; - - case CMD_SETFILTERCUTOFF: - nosetfiltcutoff = 0; - break; - - case CMD_SETFILTERCTRL: - nosetfiltctrl = 0; - break; - - case CMD_SETMASTERVOL: - nosetmastervol = 0; - break; - } - } - if (song.ltable[WTBL][c] < WAVECMD) - { - if (song.rtable[WTBL][c] <= 0x80) - { - int newlastnote = song.rtable[WTBL][c] + patternlastnote; - if (newlastnote > MAX_NOTES - 1) newlastnote = MAX_NOTES - 1; - if (song.rtable[WTBL][c] >= 0x20) firstnote = 0; - if (newlastnote > lastnote) lastnote = newlastnote; - } - else - { - int newfirstnote = song.rtable[WTBL][c] & 0x7f; - int newlastnote = song.rtable[WTBL][c] & 0x7f; - if (newlastnote > MAX_NOTES - 1) newlastnote = MAX_NOTES - 1; - if (newfirstnote < firstnote) firstnote = newfirstnote; - if (newlastnote > lastnote) lastnote = newlastnote; - } - } - } - } - for (int c = 0; c < MAX_TABLELEN; c++) - { - if (table[PTBL][c+1].used) - { - pulsetblsize += 2; - if ((song.ltable[PTBL][c] >= 0x80) && (song.ltable[PTBL][c] != 0xff)) - { - if (song.rtable[PTBL][c] & 0xf) simplepulse = 0; - } - if (song.ltable[PTBL][c] < 0x80) - { - nopulsemod = 0; - if (song.rtable[PTBL][c] & 0xf) simplepulse = 0; - } - } - } - for (int c = 0; c < MAX_TABLELEN; c++) - { - if (table[FTBL][c+1].used) - { - filttblsize += 2; - if (song.ltable[FTBL][c] < 0x80) nofiltermod = 0; - } - } - for (int c = 0; c < MAX_TABLELEN; c++) - { - if (table[STBL][c+1].used) speedtblsize += 2; - } - // Zero entry of speedtable - if ((!novib) || (!nofunktempo) || (!noportamento) || (!notoneporta)) - speedtblsize += 2; - - if (nopulse) pulsetblsize = 0; - if (nofilter) filttblsize = 0; - -#ifdef LTRELOC - std::fprintf(STDOUT, "Player address: $%04X\n", config.playeradr); - std::fprintf(STDOUT, "Zeropage address: $%04X\n", config.zeropageadr); -#else - std::snprintf(textbuffer, MAX_PATHNAME, "SELECT START ADDRESS: (CURSORS=MOVE, ENTER=ACCEPT, ESC=CANCEL)"); - printtext(1, 10, colors.CTITLE, textbuffer); - - selectdone = 0; - while (!selectdone) - { - std::snprintf(textbuffer, MAX_PATHNAME, "$%04X", config.playeradr); - printtext(1, 11, colors.CEDIT, textbuffer); - - fliptoscreen(); - waitkeynoupdate(); - - if (win_quitted) - { - exitprogram = true; - goto PRCLEANUP_S; - } - - switch(input.rawkey) - { - case KEY_LEFT: - config.playeradr -= 0x0400; - config.playeradr &= 0xff00; - break; - - case KEY_UP: - config.playeradr += 0x0100; - config.playeradr &= 0xff00; - break; - - case KEY_RIGHT: - config.playeradr += 0x0400; - config.playeradr &= 0xff00; - break; - - case KEY_DOWN: - config.playeradr -= 0x0100; - config.playeradr &= 0xff00; - break; - - case KEY_ESC: - selectdone = -1; - break; - - case KEY_ENTER: - selectdone = 1; - break; - } - } - - if (selectdone == -1) goto PRCLEANUP_S; - - std::snprintf(textbuffer, MAX_PATHNAME, "SELECT ZEROPAGE ADDRESS: (CURSORS=MOVE, ENTER=ACCEPT, ESC=CANCEL)"); - printtext(1, 13, colors.CTITLE, textbuffer); - - selectdone = 0; - while (!selectdone) - { - if (config.playerversion & PLAYER_ZPGHOSTREGS) - { - if (config.zeropageadr < 0x02) config.zeropageadr = 0xe5; - if (config.zeropageadr > 0xe5) config.zeropageadr = 0x02; - } - else - { - if (config.zeropageadr < 0x02) config.zeropageadr = 0xfe; - if (config.zeropageadr > 0xfe) config.zeropageadr = 0x02; - } - - if (!(config.playerversion & PLAYER_ZPGHOSTREGS)) - { - if (config.zeropageadr < 0x90) - std::snprintf(textbuffer, MAX_PATHNAME, "$%02X-$%02X (Used by BASIC interpreter) ", config.zeropageadr, config.zeropageadr+1); - if ((config.zeropageadr >= 0x90) && (config.zeropageadr < 0xfb)) - std::snprintf(textbuffer, MAX_PATHNAME, "$%02X-$%02X (Used by KERNAL routines) ", config.zeropageadr, config.zeropageadr+1); - if ((config.zeropageadr >= 0xfb) && (config.zeropageadr < 0xfe)) - std::snprintf(textbuffer, MAX_PATHNAME, "$%02X-$%02X (Unused) ", config.zeropageadr, config.zeropageadr+1); - if (config.zeropageadr >= 0xfe) - std::snprintf(textbuffer, MAX_PATHNAME, "$%02X-$%02X ($FF used by BASIC interpreter)", config.zeropageadr, config.zeropageadr+1); - } - else - { - std::snprintf(textbuffer, MAX_PATHNAME, "$%02X-$%02X (ghostregs start at %02X)", config.zeropageadr, config.zeropageadr+26, config.zeropageadr); - } - - printtext(1, 14, colors.CEDIT, textbuffer); - - fliptoscreen(); - waitkeynoupdate(); - - if (win_quitted) - { - exitprogram = true; - goto PRCLEANUP_S; - } - - switch(input.rawkey) - { - case KEY_LEFT: - config.zeropageadr -= 0x10; - break; - - case KEY_UP: - config.zeropageadr++; - break; - - case KEY_RIGHT: - config.zeropageadr += 0x10; - break; - - case KEY_DOWN: - config.zeropageadr--; - break; - - case KEY_ESC: - selectdone = -1; - break; - - case KEY_ENTER: - selectdone = 1; - break; - } - } - - if (selectdone == -1) goto PRCLEANUP_S; -#endif - - // Validate frequencytable parameters - if (lastnote < firstnote) - lastnote = firstnote; - if (firstnote < 0) firstnote = 0; - if (!nocalculatedspeed) - lastnote++; // Calculated speeds need the next frequency value - if (lastnote > MAX_NOTES-1) lastnote = MAX_NOTES-1; - // For sound effect support, always use the full table - if (config.playerversion & PLAYER_SOUNDEFFECTS) - { - firstnote = 0; - lastnote = MAX_NOTES-1; - } - - // Insert baseaddresses - insertdefine("base", config.playeradr); - insertdefine("zpbase", config.zeropageadr); - insertdefine("SIDBASE", config.sidaddress); - insertdefine("SID2BASE", config.sid2address); - - // Insert conditionals - insertdefine("SOUNDSUPPORT", (config.playerversion & PLAYER_SOUNDEFFECTS) ? 1 : 0); - insertdefine("VOLSUPPORT", (config.playerversion & PLAYER_VOLUME) ? 1 : 0); - insertdefine("BUFFEREDWRITES", (config.playerversion & PLAYER_BUFFERED) ? 1 : 0); - insertdefine("ZPGHOSTREGS", (config.playerversion & PLAYER_ZPGHOSTREGS) ? 1 : 0); - insertdefine("FIXEDPARAMS", fixedparams); - insertdefine("SIMPLEPULSE", simplepulse); - insertdefine("PULSEOPTIMIZATION", config.optimizepulse); - insertdefine("REALTIMEOPTIMIZATION", config.optimizerealtime); - insertdefine("NOAUTHORINFO", (config.playerversion & PLAYER_AUTHORINFO) ? 0 : 1); - insertdefine("NOEFFECTS", noeffects); - insertdefine("NOGATE", nogate); - insertdefine("NOFILTER", nofilter); - insertdefine("NOFILTERMOD", nofiltermod); - insertdefine("NOPULSE", nopulse); - insertdefine("NOPULSEMOD", nopulsemod); - insertdefine("NOWAVEDELAY", nowavedelay); - insertdefine("NOWAVECMD", nowavecmd); - insertdefine("NOREPEAT", norepeat); - insertdefine("NOTRANS", notrans); - insertdefine("NOPORTAMENTO", noportamento); - insertdefine("NOTONEPORTA", notoneporta); - insertdefine("NOVIB", novib); - insertdefine("NOINSTRVIB", noinsvib); - insertdefine("NOSETAD", nosetad); - insertdefine("NOSETSR", nosetsr); - insertdefine("NOSETWAVE", nosetwave); - insertdefine("NOSETWAVEPTR", nosetwaveptr); - insertdefine("NOSETPULSEPTR", nosetpulseptr); - insertdefine("NOSETFILTPTR", nosetfiltptr); - insertdefine("NOSETFILTCTRL", nosetfiltctrl); - insertdefine("NOSETFILTCUTOFF", nosetfiltcutoff); - insertdefine("NOSETMASTERVOL", nosetmastervol); - insertdefine("NOFUNKTEMPO", nofunktempo); - insertdefine("NOGLOBALTEMPO", noglobaltempo); - insertdefine("NOCHANNELTEMPO", nochanneltempo); - insertdefine("NOFIRSTWAVECMD", nofirstwavecmd); - insertdefine("NOCALCULATEDSPEED", nocalculatedspeed); - insertdefine("NONORMALSPEED", nonormalspeed); - insertdefine("NOZEROSPEED", nozerospeed); - - // Insert parameters - insertdefine("NUMCHANNELS", channels); - insertdefine("NUMSONGS", songs); - insertdefine("FIRSTNOTE", firstnote); - insertdefine("FIRSTNOHRINSTR", numnormal + 1); - insertdefine("FIRSTLEGATOINSTR", numnormal + numnohr + 1); - insertdefine("NUMHRINSTR", numnormal); - insertdefine("NUMNOHRINSTR", numnohr); - insertdefine("NUMLEGATOINSTR", numlegato); - insertdefine("ADPARAM", config.adparam >> 8); - insertdefine("SRPARAM", config.adparam & 0xff); - insertdefine("CIAVALLO", ciaval & 0xff); - insertdefine("CIAVALHI", ciaval >> 8); - if ((song.instr[MAX_INSTR-1].ad >= 2) && (!(song.instr[MAX_INSTR-1].ptr[WTBL]))) - insertdefine("DEFAULTTEMPO", song.instr[MAX_INSTR-1].ad - 1); - else - insertdefine("DEFAULTTEMPO", config.multiplier ? (config.multiplier*6-1) : 5); - - // Fixed firstwave & gatetimer - if (fixedparams) - { - insertdefine("FIRSTWAVEPARAM", song.instr[1].firstwave); - insertdefine("GATETIMERPARAM", song.instr[1].gatetimer & 0x3f); - } - - // Insert source code of player - if (!insertfile(playername)) - { - error("COULD NOT OPEN PLAYROUTINE!"); - goto PRCLEANUP_S; - } - - // Insert frequencytable - insertlabel("mt_freqtbllo"); - insertbytes(&freqtbllo[firstnote], lastnote-firstnote+1); - insertlabel("mt_freqtblhi"); - insertbytes(&freqtblhi[firstnote], lastnote-firstnote+1); - - // Insert songtable - insertlabel("mt_songtbllo"); - for (int c = 0; c < songs*maxChns; c++) - { - std::snprintf(textbuffer, MAX_PATHNAME, "mt_song%d", c); - insertaddrlo(textbuffer); - } - insertlabel("mt_songtblhi"); - for (int c = 0; c < songs*maxChns; c++) - { - std::snprintf(textbuffer, MAX_PATHNAME, "mt_song%d", c); - insertaddrhi(textbuffer); - } - - // Insert patterntable - insertlabel("mt_patttbllo"); - for (int c = 0; c < patterns; c++) - { - std::snprintf(textbuffer, MAX_PATHNAME, "mt_patt%d", c); - insertaddrlo(textbuffer); - } - insertlabel("mt_patttblhi"); - for (int c = 0; c < patterns; c++) - { - std::snprintf(textbuffer, MAX_PATHNAME, "mt_patt%d", c); - insertaddrhi(textbuffer); - } - - // Insert instruments - insertlabel("mt_insad"); - insertbytes(&instrwork[0], instruments); - insertlabel("mt_inssr"); - insertbytes(&instrwork[instruments], instruments); - insertlabel("mt_inswaveptr"); - insertbytes(&instrwork[instruments*2], instruments); - if (!nopulse) - { - insertlabel("mt_inspulseptr"); - insertbytes(&instrwork[instruments*3], instruments); - } - if (!nofilter) - { - insertlabel("mt_insfiltptr"); - insertbytes(&instrwork[instruments*4], instruments); - } - if (!noinsvib) - { - insertlabel("mt_insvibparam"); - insertbytes(&instrwork[instruments*5], instruments); - insertlabel("mt_insvibdelay"); - insertbytes(&instrwork[instruments*6], instruments); - } - if (!fixedparams) - { - insertlabel("mt_insgatetimer"); - insertbytes(&instrwork[instruments*7], instruments); - insertlabel("mt_insfirstwave"); - insertbytes(&instrwork[instruments*8], instruments); - } - - // Insert tables - for (int c = 0; c < MAX_TABLES; c++) - { - if ((c == PTBL) && (nopulse)) goto SKIPTABLE_S; - if ((c == FTBL) && (nofilter)) goto SKIPTABLE_S; - - // Write table left side - // Extra zero for speedtable - if ((c == STBL) && ((!novib) || (!nofunktempo) || (!noportamento) || (!notoneporta))) insertbyte(0); - // Table label - insertlabel(tableleftname[c]); - - // Table data - for (int d = 0; d < MAX_TABLELEN; d++) - { - if (table[c][d+1].used) - { - switch (c) - { - // In wavetable, convert waveform values for the playroutine - case WTBL: - { - unsigned char wave = song.ltable[c][d]; - if ((song.ltable[c][d] >= WAVESILENT) && (song.ltable[c][d] <= WAVELASTSILENT)) wave &= 0xf; - if ((song.ltable[c][d] > WAVELASTDELAY) && (song.ltable[c][d] <= WAVELASTSILENT) && (!nowavedelay)) wave += 0x10; - insertbyte(wave); - } - break; - - case PTBL: - if ((simplepulse) && (song.ltable[c][d] != 0xff) && (song.ltable[c][d] > 0x80)) - insertbyte(0x80); - else - insertbyte(song.ltable[c][d]); - break; - - // In filtesong.rtable, modify passband bits - case FTBL: - if ((song.ltable[c][d] != 0xff) && (song.ltable[c][d] > 0x80)) - insertbyte(((song.ltable[c][d] & 0x70) >> 1) | 0x80); - else - insertbyte(song.ltable[c][d]); - break; - - default: - insertbyte(song.ltable[c][d]); - break; - } - } - } - - // Write table right side, remapping jumps as necessary - // Extra zero for speedtable - if ((c == STBL) && ((!novib) || (!nofunktempo) || (!noportamento) || (!notoneporta))) insertbyte(0); - // Table label - insertlabel(tablerightname[c]); - - for (int d = 0; d < MAX_TABLELEN; d++) - { - if (table[c][d+1].used) - { - if ((song.ltable[c][d] != 0xff) || (c == STBL)) - { - switch(c) - { - case WTBL: - if ((song.ltable[c][d] >= WAVECMD) && (song.ltable[c][d] <= WAVELASTCMD)) - { - // Remap table-referencing commands - switch (song.ltable[c][d] - WAVECMD) - { - case CMD_PORTAUP: - case CMD_PORTADOWN: - case CMD_TONEPORTA: - case CMD_VIBRATO: - insertbyte(table[STBL][song.rtable[c][d]].map); - break; - - case CMD_SETPULSEPTR: - insertbyte(table[PTBL][song.rtable[c][d]].map); - break; - - case CMD_SETFILTERPTR: - insertbyte(table[FTBL][song.rtable[c][d]].map); - break; - - default: - insertbyte(song.rtable[c][d]); - break; - } - } - else - { - // For normal notes, reverse all right side high bits - insertbyte(song.rtable[c][d] ^ 0x80); - } - break; - - case PTBL: - if (simplepulse) - { - if (song.ltable[c][d] >= 0x80) - insertbyte((song.ltable[c][d] & 0x0f) | (song.rtable[c][d] & 0xf0)); - else - { - int pulsespeed = song.rtable[c][d] >> 4; - if (song.rtable[c][d] & 0x80) - { - pulsespeed |= 0xf0; - pulsespeed--; - } - pulsespeed = swapnybbles(pulsespeed); - insertbyte(pulsespeed); - } - } - else - insertbyte(song.rtable[c][d]); - break; - - default: - insertbyte(song.rtable[c][d]); - break; - } - } - else - insertbyte(table[c][song.rtable[c][d]].map); - } - } - -SKIPTABLE_S: - {} - } - - // Insert orderlists - for (int c = 0; c < songs; c++) - { - for (int d = 0; d < maxChns; d++) - { - std::snprintf(textbuffer, MAX_PATHNAME, "mt_song%d", c*maxChns+d); - insertlabel(textbuffer); - insertbytes(&songwork[sng[c][d].offset], sng[c][d].size); - } - } - - // Insert patterns - for (int c = 0; c < patterns; c++) - { - std::snprintf(textbuffer, MAX_PATHNAME, "mt_patt%d", c); - insertlabel(textbuffer); - insertbytes(&pattwork[patt[c].offset], patt[c].size); - } -#ifndef NDEBUG - { - FILE *handle = std::fopen("debug.s", "wb"); - std::fwrite(buf_data(&src), buf_size(&src), 1, handle); - std::fclose(handle); - } -#endif - // Assemble; on error fail in a rude way (the parser does so too) - if (assemble(&src, &dest)) std::exit(EXIT_FAILURE); - - packeddata = (unsigned char*)buf_data(&dest); - packedsize = buf_size(&dest); - playersize = packedsize - songtblsize - songdatasize - patttblsize - pattdatasize - instrsize - wavetblsize - pulsetblsize - filttblsize - speedtblsize; - - // Copy author info - if (config.playerversion & PLAYER_AUTHORINFO) - { - for (int c = 0; c < 32; c++) - { - packeddata[32+c] = song.author[c]; - // Convert 0 to space - if (packeddata[32+c] == 0) packeddata[32+c] = 0x20; - } - } - - // 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(filename, "wb"); - if (!songhandle) - { - std::fprintf(STDERR, "error: could not open output file '%s'.\n", filename); - goto PRCLEANUP_S; - } - -#else - clearscreen(); - printblankc(0, 0, colors.CHEADER, MAX_COLUMNS); - if (!std::strlen(filename)) - std::snprintf(textbuffer, MAX_PATHNAME, "%s Packer/Relocator", programname); - else - std::snprintf(textbuffer, MAX_PATHNAME, "%s Packer/Relocator - %s", programname, filename); - textbuffer[80] = 0; - printtext(0, 0, colors.CHEADER, textbuffer); - - std::snprintf(textbuffer, MAX_PATHNAME, "PACKING RESULTS:"); - printtext(1, 2, colors.CMESSAGE, textbuffer); - - std::snprintf(textbuffer, MAX_PATHNAME, "Playroutine: %d bytes", playersize); - printtext(1, 3, colors.CHDRFG, textbuffer); - std::snprintf(textbuffer, MAX_PATHNAME, "Songtable: %d bytes", songtblsize); - printtext(1, 4, colors.CHDRFG, textbuffer); - std::snprintf(textbuffer, MAX_PATHNAME, "Song-orderlists: %d bytes", songdatasize); - printtext(1, 5, colors.CHDRFG, textbuffer); - std::snprintf(textbuffer, MAX_PATHNAME, "Patterntable: %d bytes", patttblsize); - printtext(1, 6, colors.CHDRFG, textbuffer); - std::snprintf(textbuffer, MAX_PATHNAME, "Patterns: %d bytes", pattdatasize); - printtext(1, 7, colors.CHDRFG, textbuffer); - std::snprintf(textbuffer, MAX_PATHNAME, "Instruments: %d bytes", instrsize); - printtext(1, 8, colors.CHDRFG, textbuffer); - std::snprintf(textbuffer, MAX_PATHNAME, "Tables: %d bytes", wavetblsize+pulsetblsize+filttblsize+speedtblsize); - printtext(1, 9, colors.CHDRFG, textbuffer); - std::snprintf(textbuffer, MAX_PATHNAME, "Total size: %d bytes", packedsize); - printtext(1, 11, colors.CHDRFG, textbuffer); - fliptoscreen(); - - - // Now ask for config.fileformat - printtext(1, 13, colors.CTITLE, "SELECT FORMAT TO SAVE IN: (CURSORS=MOVE, ENTER=ACCEPT, ESC=CANCEL)"); - - selectdone = 0; - - char packedfilter[MAX_FILENAME]; - while (!selectdone) - { - switch(config.fileformat) - { - case FORMAT_SID: - printtext(1, 14, colors.CEDIT, "SID - SIDPlay music file format "); - std::strcpy(packedfilter, "*.sid"); - break; - - case FORMAT_PRG: - printtext(1, 14, colors.CEDIT, "PRG - C64 native format "); - std::strcpy(packedfilter, "*.prg"); - break; - - case FORMAT_BIN: - printtext(1, 14, colors.CEDIT, "BIN - Raw binary format (no startaddress)"); - std::strcpy(packedfilter, "*.bin"); - break; - } - - fliptoscreen(); - waitkeynoupdate(); - - if (win_quitted) - { - exitprogram = true; - goto PRCLEANUP_S; - } - - switch(input.rawkey) - { - case KEY_LEFT: - case KEY_DOWN: - config.fileformat--; - if (config.fileformat < FORMAT_SID) config.fileformat = FORMAT_BIN; - break; - - case KEY_RIGHT: - case KEY_UP: - config.fileformat++; - if (config.fileformat > FORMAT_BIN) config.fileformat = FORMAT_SID; - break; - - case KEY_ESC: - selectdone = -1; - break; - - case KEY_ENTER: - selectdone = 1; - break; - } - } - if (selectdone == -1) goto PRCLEANUP_S; - - // By default, copy loaded song name up to the extension - char packedsongname[MAX_FILENAME]; - std::memset(packedsongname, 0, sizeof packedsongname); - for (size_t i = 0; i < std::strlen(filename); i++) - { - if (filename[i] == '.') break; - packedsongname[i] = filename[i]; - } - switch (config.fileformat) - { - case FORMAT_PRG: - std::strcat(packedsongname, ".prg"); - break; - - case FORMAT_BIN: - std::strcat(packedsongname, ".bin"); - break; - - case FORMAT_SID: - std::strcat(packedsongname, ".sid"); - break; - } - - // Now ask for filename, retry if unsuccessful - while (!songhandle) - { - if (!fileselector(packedsongname, packedpath, packedfilter, "Save Music+Playroutine", 3)) - goto PRCLEANUP_S; - - if (std::strlen(packedsongname) < MAX_FILENAME-4) - { - int extfound = 0; - for (int c = (int)std::strlen(packedsongname)-1; c >= 0; c--) - { - if (packedsongname[c] == '.') extfound = 1; - } - if (!extfound) - { - switch (config.fileformat) - { - case FORMAT_PRG: - std::strcat(packedsongname, ".prg"); - break; - - case FORMAT_BIN: - std::strcat(packedsongname, ".bin"); - break; - - case FORMAT_SID: - std::strcat(packedsongname, ".sid"); - break; - } - } - } - songhandle = std::fopen(packedsongname, "wb"); - } -#endif - - if (config.fileformat == FORMAT_PRG) - { - fwritele16(songhandle, config.playeradr); - } - if (config.fileformat == FORMAT_SID) - { - unsigned char ident[] = {'P', 'S', 'I', 'D', 0x00, 0x03, 0x00, 0x7c}; - unsigned char byte; - // Identification - std::fwrite(ident, sizeof ident, 1, songhandle); - - // Load address - byte = 0x00; - fwrite8(songhandle, byte); - fwrite8(songhandle, byte); - - // Init address - if ((config.multiplier > 1) || (!config.multiplier)) - { - unsigned speedvalue; - byte = (config.playeradr-10) >> 8; - fwrite8(songhandle, byte); - byte = (config.playeradr-10) & 0xff; - fwrite8(songhandle, byte); - - if (config.multiplier) - { - if (config.ntsc) speedvalue = 0x42c6/config.multiplier; - else speedvalue = 0x4cc7/config.multiplier; - } - else - { - if (config.ntsc) speedvalue = 0x42c6*2; - else speedvalue = 0x4cc7*2; - } - speedcode[1] = speedvalue & 0xff; - speedcode[6] = speedvalue >> 8; - } - else - { - byte = (config.playeradr) >> 8; - fwrite8(songhandle, byte); - byte = (config.playeradr) & 0xff; - fwrite8(songhandle, byte); - } - - // Play address - byte = (config.playeradr+3) >> 8; - fwrite8(songhandle, byte); - byte = (config.playeradr+3) & 0xff; - fwrite8(songhandle, byte); - - // Number of subtunes - byte = 0x00; - fwrite8(songhandle, byte); - byte = songs; - fwrite8(songhandle, byte); - - // Default subtune - byte = 0x00; - fwrite8(songhandle, byte); - byte = 0x01; - fwrite8(songhandle, byte); - - // Song speed bits - byte = 0x00; - if ((config.ntsc) || (config.multiplier > 1) || (!config.multiplier)) byte = 0xff; - fwrite8(songhandle, byte); - fwrite8(songhandle, byte); - fwrite8(songhandle, byte); - fwrite8(songhandle, byte); - - // Songname etc. - std::fwrite(song.title, sizeof song.title, 1, songhandle); - std::fwrite(song.author, sizeof song.author, 1, songhandle); - std::fwrite(song.released, sizeof song.released, 1, songhandle); - - // Flags - byte = 0x00; - fwrite8(songhandle, byte); - if (config.ntsc) byte = 8; - else byte = 4; - // Set model for both SIDs - if (config.sidmodel) byte |= 32 + 128; - else byte |= 16 + 64; - fwrite8(songhandle, byte); - - // Relocation and second SID address - byte = 0x00; - fwrite8(songhandle, byte); - fwrite8(songhandle, byte); - fwrite8(songhandle, (config.sid2address & 0x0ff0) >> 4); - fwrite8(songhandle, byte); - - // Load address - if ((config.multiplier > 1) || (!config.multiplier)) - { - byte = (config.playeradr-10) & 0xff; - fwrite8(songhandle, byte); - byte = (config.playeradr-10) >> 8; - fwrite8(songhandle, byte); - } - else - { - byte = (config.playeradr) & 0xff; - fwrite8(songhandle, byte); - byte = (config.playeradr) >> 8; - fwrite8(songhandle, byte); - } - if ((config.multiplier > 1) || (!config.multiplier)) std::fwrite(speedcode, 10, 1, songhandle); - } - - std::fwrite(packeddata, packedsize, 1, songhandle); - std::fclose(songhandle); - -PRCLEANUP_S: - buf_free(&src); - buf_free(&dest); - parse_free(); - //LOG_FREE; - - if (pattwork) delete [] pattwork; - if (songwork) delete [] songwork; - if (instrwork) delete [] instrwork; - printmainscreen(); - input.clearkeys(); -} - void exectable(int num, int ptr) { // Jump error check diff --git a/src/reloc.h b/src/reloc.h index 83f6948..1cf5e46 100644 --- a/src/reloc.h +++ b/src/reloc.h @@ -40,7 +40,6 @@ enum }; void relocator(const char* filename); -void relocator_stereo(const char* filename); void optimizetable(int num); #endif diff --git a/src/song.cpp b/src/song.cpp index 473df86..d02a1d3 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -1836,6 +1836,8 @@ void mergesong() } } + int maxChns = config.getMaxChannels(); + // Determine amount of songs int c = MAX_SONGS - 1; for (;;) @@ -1843,6 +1845,10 @@ void mergesong() if ((song.len[c][0]) && (song.len[c][1]) && (song.len[c][2])) break; + if ((maxChns == 6) && + (song.len[c][3]) && + (song.len[c][4]) && + (song.len[c][5])) break; if (c == 0) break; c--; } @@ -1853,9 +1859,9 @@ void mergesong() int tablebase[MAX_TABLES]; - for (int c = 0; c < MAX_TABLES; c++) + for (int t = 0; t < MAX_TABLES; t++) { - tablebase[c] = song.gettablelen(c); + tablebase[t] = song.gettablelen(t); } char ident[4]; diff --git a/src/tools/ltreloc.cpp b/src/tools/ltreloc.cpp index 82f949c..7057acd 100644 --- a/src/tools/ltreloc.cpp +++ b/src/tools/ltreloc.cpp @@ -332,16 +332,16 @@ int main(int argc, char **argv) case SngType::STANDARD: std::fprintf(STDOUT, "Single SID\n"); config.numsids = 1; - relocator(packedsongname); break; case SngType::DUAL: std::fprintf(STDOUT, "Dual SID\n"); config.numsids = 2; - relocator_stereo(packedsongname); break; default: break; // unreachable } + relocator(packedsongname); + // Exit return EXIT_SUCCESS; }