Mercurial > hg > dmlib
changeset 652:d9888292f971
Rename again.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 16 Apr 2013 06:04:22 +0300 |
parents | e2ac08228a0f |
children | 469119cab5b2 |
files | tools/data2inc.c tools/gentab.c tools/gfxconv.c tools/mod2wav.c tools/objlink.c tools/packed.c tools/ppl.c tools/svg2qd.py tools/view64.c tools/viewmod.c tools/xm2jss.c utils/data2inc.c utils/gentab.c utils/gfxconv.c utils/mod2wav.c utils/objlink.c utils/packed.c utils/ppl.c utils/svg2qd.py utils/view64.c utils/viewmod.c utils/xm2jss.c |
diffstat | 22 files changed, 7004 insertions(+), 7004 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/data2inc.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,404 @@ +/* + * data2inc - Convert binary data to "C"-source or XA-compatible include file + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2003,2009-2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <errno.h> +#include "dmlib.h" +#include "dmargs.h" +#include "dmmutex.h" + +#define RA_LINEBUF (16) + +enum +{ + FMT_AUTO = 0, + FMT_C, + FMT_ASM +}; + +char *optInFilename = NULL, + *optOutFilename = NULL, + *optObjName = "default_object", + *optDataType = NULL, + *optAddLine = NULL; + +int optIndentation = -1; +int optFormat = FMT_AUTO; +BOOL optHexMode = FALSE, + optQuiet = FALSE, + optExtraData = FALSE, + optFormatting = TRUE; + + +void (*writeHeader) (FILE *, char *) = NULL; +void (*writeDecl) (FILE *, size_t, char *) = NULL; +void (*writeData) (FILE *, Uint8 *, size_t) = NULL; +void (*writeFooter) (FILE *, size_t, char *) = NULL; + + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 4, 'A', "format-asm", "Output in XA-compatible asm", OPT_NONE }, + { 5, 'C', "format-c", "Output in ANSI C", OPT_NONE }, + { 1, 'n', "name", "Set object name", OPT_ARGREQ }, + { 2, 't', "type", "Set datatype (unsigned char/byte)", OPT_ARGREQ }, + { 3, 'a', "add-line", "Add this line to start of file", OPT_ARGREQ }, + { 6, 'x', "hexadecimal", "Use hexadecimal output", OPT_NONE }, + { 7, 'q', "quiet", "Do not add comments", OPT_NONE }, + { 8, 'f', "no-formatting", "Disable additional output formatting", OPT_NONE }, + { 9, 'i', "indentation", "Set indentation (negative value = tab)", OPT_ARGREQ }, + { 10, 'e', "extra-data", "Add object end labels and size in asm output", OPT_NONE }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, + "[options] [sourcefile] [destfile]"); + + dmArgsPrintHelp(stdout, optList, optListN); + + printf( + "\n" + "To convert a data file to a C structure using 'Uint8' as type:\n" + "$ data2inc -C -n variable_name -t Uint8 input.bin output.h\n" + "\n" + ); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + optObjName = optArg; + break; + + case 2: + optDataType = optArg; + break; + + case 3: + optAddLine = optArg; + break; + + case 4: + optFormat = FMT_ASM; + break; + case 5: + optFormat = FMT_C; + break; + case 6: + optHexMode = TRUE; + break; + case 7: + optQuiet = TRUE; + break; + case 8: + optFormatting = FALSE; + break; + + case 9: + optIndentation = atoi(optArg); + break; + + case 10: + optExtraData = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char * currArg) +{ + if (!optInFilename) + optInFilename = currArg; + else + if (!optOutFilename) + optOutFilename = currArg; + else + dmError("Source and destination filenames already specified, extraneous argument '%s'.\n", currArg); + + return TRUE; +} + + +/* Assembler include data output functions + */ +void writeHeader_ASM(FILE * f, char *name) +{ + if (name) + fprintf(f, "; '%s'", name); + else + fprintf(f, "; Generated"); + fprintf(f, " by %s v%s\n", + dmProgName, dmProgVersion); +} + +void writeDecl_ASM(FILE * f, size_t len, char *name) +{ + if (optExtraData) + fprintf(f, "%s_size = %u\n", name, len); + fprintf(f, "%s:\n", name); +} + +void writeData_ASM(FILE * f, Uint8 * buf, size_t len) +{ + size_t i; + + fprintf(f, "%s ", optDataType); + for (i = 0; i < len; i++) + { + if (optFormatting) + { + if (optHexMode) + fprintf(f, "$%.2x", buf[i]); + else + fprintf(f, "%3d", buf[i]); + } + else + { + if (optHexMode) + fprintf(f, "$%x", buf[i]); + else + fprintf(f, "%d", buf[i]); + } + + if (i < (len - 1)) + fprintf(f, ","); + } +} + +void writeFooter_ASM(FILE * f, size_t len, char *name) +{ + (void) len; + if (optExtraData) + fprintf(f, "%s_end: \n", name); + else + fprintf(f, "\n"); +} + + +/* ANSI-C include data output functions + */ +void writeHeader_C(FILE * f, char *name) +{ + if (name) + fprintf(f, "/* '%s' generated", name); + else + fprintf(f, "/* Generated"); + + fprintf(f, " by %s v%s\n" " */\n", + dmProgName, dmProgVersion); +} + +void writeDecl_C(FILE * f, size_t len, char *name) +{ + fprintf(f, "%s %s[%u] = {\n", + optDataType, name, len); + + printf("extern %s %s[%u];\n", + optDataType, name, len); +} + +void writeData_C(FILE * f, Uint8 * buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + { + if (optFormatting) + { + if (optHexMode) + fprintf(f, "0x%.2x", buf[i]); + else + fprintf(f, "%3d", buf[i]); + } + else + { + if (optHexMode) + fprintf(f, "0x%x", buf[i]); + else + fprintf(f, "%d", buf[i]); + } + + fprintf(f, ","); + } +} + +void writeFooter_C(FILE * f, size_t len, char *name) +{ + (void) len; + (void) name; + fprintf(f, "};\n"); +} + + +off_t dmGetFileSize(FILE *f) +{ + off_t len, pos = ftell(f); + fseeko(f, 0, SEEK_END); + len = ftell(f); + fseek(f, pos, SEEK_SET); + return len; +} + + +int main(int argc, char *argv[]) +{ + FILE *sfile = NULL, *dfile = NULL; + off_t inSize; + Uint8 inBuf[RA_LINEBUF]; + int tmpRes; + + /* Initialize */ + dmInitProg("data2inc", "Data to include converter", "0.6", NULL, NULL); + dmVerbosity = 0; + + /* Parse arguments */ + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + /* Determine output type, if not specified */ + if (optFormat == FMT_AUTO) + { + char *dext; + + if (optOutFilename == NULL) + { + dmError("Output format not specified and no output filename given (try --help)\n"); + exit(1); + } + + /* Check filename extension */ + dext = strrchr(optOutFilename, '.'); + if (dext) + { + dext++; + if (!strcasecmp(dext, "c") || !strcasecmp(dext, "h") || + !strcasecmp(dext, "cc") || !strcasecmp(dext, "cpp") || + !strcasecmp(dext, "hpp") || !strcasecmp(dext, "c++")) + optFormat = FMT_C; + else + optFormat = FMT_ASM; + } else + optFormat = FMT_ASM; + } + + /* Set functions */ + switch (optFormat) + { + case FMT_ASM: + if (!optDataType) + optDataType = ".byte"; + + writeHeader = writeHeader_ASM; + writeDecl = writeDecl_ASM; + writeData = writeData_ASM; + writeFooter = writeFooter_ASM; + break; + + case FMT_C: + if (!optDataType) + optDataType = "unsigned char"; + + writeHeader = writeHeader_C; + writeDecl = writeDecl_C; + writeData = writeData_C; + writeFooter = writeFooter_C; + break; + + case FMT_AUTO: + default: + dmError("Internal error, FMT_AUTO at output function init.\n"); + exit(2); + } + + /* Open the files */ + if (optInFilename == NULL) + sfile = stdin; + else + if ((sfile = fopen(optInFilename, "rb")) == NULL) + { + tmpRes = errno; + dmError("Error opening input file '%s'. (%s)\n", + optInFilename, strerror(tmpRes)); + exit(3); + } + + if (optOutFilename == NULL) + dfile = stdout; + else + if ((dfile = fopen(optOutFilename, "wa")) == NULL) + { + tmpRes = errno; + dmError("Error creating output file '%s'. (%s)\n", + optOutFilename, strerror(tmpRes)); + exit(4); + } + + /* Get sourcefile size */ + inSize = dmGetFileSize(sfile); + + /* Output header */ + if (!optQuiet) + writeHeader(dfile, optOutFilename); + + if (optAddLine) + fprintf(dfile, "%s\n", optAddLine); + + /* Output declaration */ + writeDecl(dfile, inSize, optObjName); + + /* Output data */ + while (!feof(sfile)) + { + tmpRes = fread(inBuf, sizeof(Uint8), RA_LINEBUF, sfile); + if (tmpRes > 0) + { + if (optIndentation < 0) + fprintf(dfile, "\t"); + else + if (optIndentation > 0) + { + int i; + for (i = 0; i < optIndentation; i++) + fputs(" ", dfile); + } + + writeData(dfile, inBuf, tmpRes); + + fprintf(dfile, "\n"); + } + } + + + /* Output footer */ + writeFooter(dfile, inSize, optObjName); + + /* Exit */ + fclose(sfile); + fclose(dfile); + + exit(0); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/gentab.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,264 @@ +#include "dmlib.h" +#include "dmargs.h" +#include <math.h> + +enum +{ + MT_SIN, + MT_COS, + MT_SMOOTH1, + MT_SCURVE, + MT_SMOOTH1_CLAMP, + MT_SCURVE_CLAMP, + MT_SIN_SCURVE, + + MT_LAST +}; + + +typedef struct +{ + char *name; + char *desc; +} DMTransType; + +static DMTransType dmTransTypes[MT_LAST] = +{ + { "sin", "Sine" }, + { "cos", "Cosine" }, + { "smooth1", "Smoothstep1 LERP" }, + { "scurve", "S-curve LERP" }, + { "smooth1-clamp", "Clamped smoothstep1 LERP" }, + { "scurve-clamp", "Clamped S-curve LERP" }, + { "sin-scurve", "Sine S-curve" }, +}; + + +DMFloat + optSOffset = 0.0f, + optSAmplitude = 1.0f, + optSOmega = 1.0f, + optStartValue = 0.0f, + optEndValue = 1.0f; + +int optNSteps = 64, + optPerLine = 16, + optTransType = -1; + +char + *optObjectName = NULL, + *optOutFilename = NULL; + + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'v', "verbose", "Increase verbosity", OPT_NONE }, + { 2, 'o', "output", "Set output file (default stdout)", OPT_ARGREQ }, + { 3, 'n', "name", "Set output object name", OPT_ARGREQ }, + + { 4, 's', "steps", "Number of steps/values in output table", OPT_ARGREQ }, + { 5, 't', "type", "Curve/interpolation type (see list)", OPT_ARGREQ }, + + { 6, 'O', "offset", "Output data offset", OPT_ARGREQ }, + { 7, 'A', "amplitude", "Output amplitude scale", OPT_ARGREQ }, + { 8, 'W', "omega", "Omega (w) multiplier", OPT_ARGREQ }, + + { 9, 'S', "start", "Start value (only smooth/scurve)", OPT_ARGREQ }, + { 10, 'E', "end", "End value (only smooth/scurve)", OPT_ARGREQ }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + int index; + dmPrintBanner(stdout, dmProgName, "[options]"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf("\nAvailable types:\n"); + for (index = 0; index < MT_LAST; index++) + { + DMTransType *tm = &dmTransTypes[index]; + printf("%-15s | %s\n", tm->name, tm->desc); + } + printf("\n"); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + dmVerbosity++; + break; + + case 2: + optOutFilename = optArg; + break; + + case 3: + optObjectName = optArg; + break; + + case 4: + { + int tmp; + if (sscanf(optArg, "%d", &tmp) != 1) + { + dmError("Invalid number of steps argument '%s'.\n", optArg); + return FALSE; + } + optNSteps = tmp; + } + break; + + case 5: + { + int index; + for (index = 0; index < MT_LAST; index++) + { + DMTransType *tm = &dmTransTypes[index]; + if (strcasecmp(tm->name, optArg) == 0) + { + optTransType = index; + return TRUE; + } + } + dmError("Invalid transformation type option '%s'.\n", + optArg); + return FALSE; + } + break; + + case 6: + case 7: + case 8: + case 9: + case 10: + { + DMFloat tmp; + if (sscanf(optArg, "%f", &tmp) != 1) + { + dmError("Invalid %s option argument '%s', expected a floating point value.\n", + currArg, optArg); + return FALSE; + } + switch (optN) + { + case 6: optSOffset = tmp; break; + case 7: optSAmplitude = tmp; break; + case 8: optSOmega = tmp; break; + case 9: optStartValue = tmp; break; + case 10: optEndValue = tmp; break; + } + } + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + FILE *outFile; + DMLerpContext ctx; + int step, n; + + dmInitProg("gentab", "Sine, etc. table generator", "0.1", NULL, NULL); + dmVerbosity = 1; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, TRUE)) + exit(1); + + // Check settings + if (optTransType < 0) + { + dmError("No transformation type set, perhaps try --help\n"); + return -1; + } + + if (optObjectName == NULL) + { + dmError("Object name not specified, try --help\n"); + return -2; + } + + if (optOutFilename == NULL) + outFile = stdout; + else + if ((outFile = fopen(optOutFilename, "w")) == NULL) + { + int err = dmGetErrno(); + dmError("Could not open output file '%s', %d: %s\n", + optOutFilename, err, dmErrorStr(err)); + return -2; + } + + + // Generate table + dmLerpInit(&ctx, optStartValue, optEndValue, optNSteps); + + fprintf(outFile, + "cnt_%s = %d\n" + "vtab_%s: ", + optObjectName, + optNSteps, + optObjectName + ); + + for (n = 0, step = 0; step < optNSteps; step++) + { + DMFloat t = ((DMFloat) step * optSOmega) / (DMFloat) optNSteps, delta, value; + + switch (optTransType) + { + case MT_SIN: delta = sin(t * 2 * DM_PI); break; + case MT_COS: delta = cos(t * 2 * DM_PI); break; + + case MT_SMOOTH1: delta = dmLerp1(&ctx, step); break; + case MT_SCURVE: delta = dmLerpSCurve(&ctx, step); break; + case MT_SMOOTH1_CLAMP: delta = dmLerp1Clamp(&ctx, step); break; + case MT_SCURVE_CLAMP: delta = dmLerpSCurveClamp(&ctx, step); break; + case MT_SIN_SCURVE: delta = dmLerpSCurveClamp(&ctx, step); break; + + default: delta = 0; + } + + value = optSOffset + delta * optSAmplitude; + + // Print the value + if (n == 0) + fprintf(outFile, "\t.byte "); + + fprintf(outFile, "%ld%s", + lrint(value), + (n < optPerLine - 1) ? "," : ""); + + if (++n >= optPerLine) + { + fprintf(outFile, "\n"); + n = 0; + } + } + if (n > 0) + fprintf(outFile, "\n"); + + fprintf(outFile, "\n"); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/gfxconv.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,1697 @@ +/* + * gfxconv - Convert various graphics formats + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include "dmlib.h" +#include "dmargs.h" +#include "dmfile.h" +#include "dmmutex.h" +#include "libgfx.h" +#include "lib64gfx.h" + +//#define UNFINISHED 1 + +#define DM_MAX_COLORS 256 + +#define ASC_NBITS 8 +#define ASC_NCOLORS 4 +static const char dmASCIIPalette[ASC_NCOLORS] = ".:X#"; + +enum +{ + FFMT_AUTO = 0, + + FFMT_ASCII, + FFMT_ANSI, + FFMT_IMAGE, + + FFMT_CHAR, + FFMT_SPRITE, + FFMT_BITMAP, + + FFMT_LAST +}; + + +typedef struct +{ + char *name; + char *fext; + BOOL in, out; + int format; + int subformat; +} DMConvFormat; + + +static DMConvFormat convFormatList[] = +{ + { + "ASCII text", "asc", FALSE, TRUE, + FFMT_ASCII , 0, + }, + { + "ANSI colored text", "ansi", FALSE, TRUE, + FFMT_ANSI , 0, + }, + { + "PNG image file", "png", TRUE, TRUE, + FFMT_IMAGE , IMGFMT_PNG, + }, + { + "PPM image file", "ppm", FALSE, TRUE, + FFMT_IMAGE , IMGFMT_PPM, + }, + { + "PCX image file", "pcx", TRUE, TRUE, + FFMT_IMAGE , IMGFMT_PCX, + }, + { + "IFF ILBM file", "lbm", TRUE, FALSE, + FFMT_IMAGE , IMGFMT_ILBM, + }, + { + "Bitplaned RAW (intl/non-intl) image file", "raw", FALSE, TRUE, + FFMT_IMAGE , IMGFMT_RAW, + }, + { + "IFFMaster RAW image file", "araw", FALSE, TRUE, + FFMT_IMAGE , IMGFMT_ARAW, + }, + + { + "C64 bitmap image file", NULL, TRUE, TRUE, + FFMT_BITMAP , -1, + }, + + { + "C64 character/font data", "chr", TRUE, TRUE, + FFMT_CHAR , 0 + }, + { + "C64 sprite data", "spr", TRUE, TRUE, + FFMT_SPRITE , 0 + }, +}; + +static const int nconvFormatList = sizeof(convFormatList) / sizeof(convFormatList[0]); + + +typedef struct +{ + BOOL triplet, alpha; + DMColor color; + int from, to; +} DMMapValue; + + + +char *optInFilename = NULL, + *optOutFilename = NULL; +int optInFormat = FFMT_AUTO, + optOutFormat = FFMT_ASCII, + optInSubFormat = IMGFMT_PNG, + optOutSubFormat = IMGFMT_PNG, + optItemCount = -1, + optPlanedWidth = 1, + optForcedFormat = -1; +int optInSkip = 0; +BOOL optInMulticolor = FALSE, + optSequential = FALSE, + optRemapColors = FALSE, + optRemapRemove = FALSE; +int optNRemapTable = 0; +DMMapValue optRemapTable[DM_MAX_COLORS]; +int optColors[C64_MAX_COLORS]; + +DMImageSpec optSpec = +{ + .scale = 1, + .nplanes = 4, + .interleave = FALSE, + .paletted = FALSE, + .format = 0, +}; + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 15, 'v', "verbose", "Increase verbosity", OPT_NONE }, + { 3, 'o', "output", "Output filename", OPT_ARGREQ }, + { 1, 'i', "informat", "Set input format ([s]prite, [c]har, [b]itmap, [i]mage)", OPT_ARGREQ }, + { 2, 'm', "multicolor", "Input is multicolor / output in multicolor", OPT_NONE }, + { 4, 's', "skip", "Skip bytes in input", OPT_ARGREQ }, + { 5, 'f', "format", "Output format (see --formats)", OPT_ARGREQ }, + { 17, 'F', "formats", "Output format (see list below)", OPT_NONE }, + { 8, 'q', "sequential", "Output sequential files (image output only)", OPT_NONE }, + { 6, 'c', "colormap", "Color mappings (see below for information)", OPT_ARGREQ }, + { 7, 'n', "numitems", "How many 'items' to view (default: all)", OPT_ARGREQ }, + { 9, 'S', "scale", "Scale output by x (image output only)", OPT_ARGREQ }, + { 10, 'b', "bformat", "Force input bitmap format (see below)", OPT_ARGREQ }, + { 11, 'w', "width", "Item width (number of items per row, min 1)", OPT_ARGREQ }, + { 12, 'P', "paletted", "Use indexed/paletted output (png, pcx output only)", OPT_NONE }, + { 13, 'B', "bplanes", "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ }, + { 14, 'I', "interleave", "Interleave scanlines (default: output whole planes)", OPT_NONE }, + { 16, 'R', "remap", "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>] | -R @map.txt)", OPT_ARGREQ }, + { 18, 'r', "remap-remove", "Remove unused colors from remapped palette (requires -R)", OPT_NONE }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowFormats() +{ + int i; + + printf( + "Available input/output formats:\n" + " Ext | I | O | Description\n" + "------+---+---+-----------------------------------------------\n" + ); + + for (i = 0; i < nconvFormatList; i++) + { + DMConvFormat *fmt = &convFormatList[i]; + printf("%-5s | %c | %c | %s\n", + fmt->fext ? fmt->fext : "", + fmt->in ? 'X' : ' ', + fmt->out ? 'X' : ' ', + fmt->name); + } + + printf( + "\n" + "(Not all input->output combinations are actually supported.)\n" + "\n" + "Available bitmap formats:\n" + " Ext | Type | Description\n" + "------+-----------------+-------------------------------------\n" + ); + + for (i = 0; i < ndmC64ImageFormats; i++) + { + const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; + char buf[64]; + printf("%-5s | %-15s | %s\n", + fmt->fext, + dmC64GetImageTypeString(buf, sizeof(buf), fmt->type), + fmt->name); + } +} + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, "[options] <input file>"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf( + "\n" + "Color map definitions are used for ANSI and image output, to declare what\n" + "output colors of the C64 palette are used for each single color/multi color\n" + "bit-combination. For example, if the input is multi color sprite or char,\n" + "you can define colors like: -c 0,8,3,15 .. for single color: -c 0,1\n" + "The numbers are palette indexes, and the order is for bit(pair)-values\n" + "00, 01, 10, 11 (multi color) and 0, 1 (single color). NOTICE! 255 is the\n" + "special color that can be used for transparency.\n" + ); +} + + +int dmGetConvFormat(int format, int subformat) +{ + int i; + for (i = 0; i < nconvFormatList; i++) + { + DMConvFormat *fmt = &convFormatList[i]; + if (fmt->format == format && + fmt->subformat == subformat) + return i; + } + return -1; +} + + +BOOL dmGetFormatByExt(const char *fext, int *format, int *subformat) +{ + int i; + if (fext == NULL) + return FALSE; + + for (i = 0; i < nconvFormatList; i++) + { + DMConvFormat *fmt = &convFormatList[i]; + if (fmt->fext != NULL && + strcasecmp(fext, fmt->fext) == 0) + { + *format = fmt->format; + *subformat = fmt->subformat; + return TRUE; + } + } + + for (i = 0; i < ndmC64ImageFormats; i++) + { + const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; + if (fmt->fext != NULL && + strcasecmp(fext, fmt->fext) == 0) + { + *format = FFMT_BITMAP; + *subformat = i; + return TRUE; + } + } + + return FALSE; +} + + +static BOOL dmParseMapOptionMapItem(const char *popt, DMMapValue *value, const int nmax, const char *msg) +{ + char *end, *split, *opt = dm_strdup(popt); + + if (opt == NULL) + goto error; + + if ((end = split = strchr(opt, ':')) == NULL) + { + dmError("Invalid %s value '%s', expected <(#|%)RRGGBB|[$|0x]index>:<[$|0x]index>.\n", msg, opt); + goto error; + } + + // Trim whitespace + *end = 0; + for (end--; end > opt && *end && isspace(*end); end--) + *end = 0; + + // Parse either a hex triplet color definition or a normal value + if (*opt == '#' || *opt == '%') + { + int colR, colG, colB, colA; + + if (sscanf(opt + 1, "%2x%2x%2x%2x", &colR, &colG, &colB, &colA) == 4 || + sscanf(opt + 1, "%2X%2X%2X%2X", &colR, &colG, &colB, &colA) == 4) + { + value->alpha = TRUE; + value->color.a = colA; + } + else + if (sscanf(opt + 1, "%2x%2x%2x", &colR, &colG, &colB) != 3 && + sscanf(opt + 1, "%2X%2X%2X", &colR, &colG, &colB) != 3) + { + dmError("Invalid %s value '%s', expected a hex triplet, got '%s'.\n", msg, popt, opt + 1); + goto error; + } + + value->color.r = colR; + value->color.g = colG; + value->color.b = colB; + value->triplet = TRUE; + } + else + { + if (!dmGetIntVal(opt, &value->from)) + { + dmError("Invalid %s value '%s', could not parse source value '%s'.\n", msg, popt, opt); + goto error; + } + value->triplet = FALSE; + } + + // Trim whitespace + split++; + while (*split && isspace(*split)) split++; + + // Parse destination value + if (!dmGetIntVal(split, &value->to)) + { + dmError("Invalid %s value '%s', could not parse destination value '%s'.\n", msg, popt, split); + goto error; + } + + if (!value->triplet && (value->from < 0 || value->from > 255)) + { + dmError("Invalid %s map source color index value %d, must be [0..255].\n", msg, value->from); + goto error; + } + + if (value->to < 0 || value->to > nmax) + { + dmError("Invalid %s map destination color index value %d, must be [0..%d].\n", msg, value->to, nmax); + goto error; + } + + dmFree(opt); + return TRUE; + +error: + dmFree(opt); + return FALSE; +} + + +static BOOL dmParseMapOptionItem(char *opt, char *end, void *pvalue, const int index, const int nmax, const BOOL requireIndex, const char *msg) +{ + // Trim whitespace + if (end != NULL) + { + *end = 0; + for (end--; end > opt && *end && isspace(*end); end--) + *end = 0; + } + while (*opt && isspace(*opt)) opt++; + + // Parse item based on mode + if (requireIndex) + { + DMMapValue *value = (DMMapValue *) pvalue; + if (!dmParseMapOptionMapItem(opt, &value[index], nmax, msg)) + return FALSE; + } + else + { + int *value = (int *) pvalue; + char *split = strchr(opt, ':'); + if (split != NULL) + { + dmError("Unexpected ':' in indexed %s '%s'.\n", msg, opt); + return FALSE; + } + + if (!dmGetIntVal(opt, &value[index])) + { + dmError("Invalid %s value '%s', could not parse.\n", msg, opt); + return FALSE; + } + } + + return TRUE; +} + + +BOOL dmParseMapOptionString(char *opt, void *values, int *nvalues, const int nmax, const BOOL requireIndex, const char *msg) +{ + char *end, *start = opt; + + *nvalues = 0; + while (*nvalues < nmax && *start && (end = strchr(start, ',')) != NULL) + { + if (!dmParseMapOptionItem(start, end, values, *nvalues, nmax, requireIndex, msg)) + return FALSE; + + start = end + 1; + (*nvalues)++; + } + + if (*start && *nvalues < nmax) + { + if (!dmParseMapOptionItem(start, NULL, values, *nvalues, nmax, requireIndex, msg)) + return FALSE; + + (*nvalues)++; + } + + return TRUE; +} + + +int dmParseColorRemapFile(const char *filename, DMMapValue *values, int *nvalue, const int nmax) +{ + FILE *fp; + char line[512]; + int res = DMERR_OK; + + if ((fp = fopen(filename, "r")) == NULL) + { + res = dmGetErrno(); + dmError("Could not open color remap file '%s' for reading, %d: %s\n", + res, dmErrorStr(res)); + return res; + } + + while (fgets(line, sizeof(line), fp)) + { + char *start = line; + while (*start && isspace(*start)) start++; + + if (*start != 0 && *start != ';') + { + if (!dmParseMapOptionMapItem(line, &values[*nvalue], nmax, "mapping file")) + goto error; + else + { + (*nvalue)++; + if (*nvalue >= nmax) + { + dmError("Too many mapping pairs in '%s', maximum is %d.\n", + filename, nmax); + goto error; + } + } + } + } + +error: + fclose(fp); + return res; +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 17: + argShowFormats(); + exit(0); + break; + + case 15: + dmVerbosity++; + break; + + case 1: + switch (tolower(optArg[0])) + { + case 's': + optInFormat = FFMT_SPRITE; + break; + case 'c': + optInFormat = FFMT_CHAR; + break; + case 'b': + optInFormat = FFMT_BITMAP; + break; + case 'i': + optInFormat = FFMT_IMAGE; + break; + default: + dmError("Invalid input format '%s'.\n", optArg); + return FALSE; + } + break; + + case 2: + optInMulticolor = TRUE; + break; + + case 3: + optOutFilename = optArg; + break; + + case 4: + if (!dmGetIntVal(optArg, &optInSkip)) + { + dmError("Invalid skip value argument '%s'.\n", optArg); + return FALSE; + } + break; + + case 5: + if (!dmGetFormatByExt(optArg, &optOutFormat, &optOutSubFormat)) + { + dmError("Invalid output format '%s'.\n", optArg); + return FALSE; + } + break; + + case 6: + { + int index, ncolors; + if (!dmParseMapOptionString(optArg, optColors, + &ncolors, C64_MAX_COLORS, FALSE, "color table option")) + return FALSE; + + dmMsg(1, "Set color table: "); + for (index = 0; index < ncolors; index++) + { + dmPrint(1, "[%d:%d]%s", + index, optColors[index], + (index < ncolors) ? ", " : ""); + } + dmPrint(1, "\n"); + } + break; + + case 7: + if (sscanf(optArg, "%d", &optItemCount) != 1) + { + dmError("Invalid count value argument '%s'.\n", optArg); + return FALSE; + } + break; + + case 8: + optSequential = TRUE; + break; + + case 9: + { + int tmp = atoi(optArg); + if (tmp < 1 || tmp > 50) + { + dmError("Invalid scale value '%s'.\n", optArg); + return FALSE; + } + optSpec.scale = tmp; + } + break; + + case 11: + { + int tmp = atoi(optArg); + if (tmp < 1 || tmp > 512) + { + dmError("Invalid width value '%s'.\n", optArg); + return FALSE; + } + optPlanedWidth = tmp; + } + break; + + case 12: + optSpec.paletted = TRUE; + break; + + case 13: + { + int tmp = atoi(optArg); + if (tmp < 1 || tmp > 8) + { + dmError("Invalid bitplanes/bpp value '%s'.\n", optArg); + return FALSE; + } + optSpec.nplanes = tmp; + } + break; + + case 14: + optSpec.interleave = TRUE; + break; + + + case 16: + if (optArg[0] == '@') + { + if (optArg[1] != 0) + { + int res; + if ((res = dmParseColorRemapFile(optArg + 1, + optRemapTable, &optNRemapTable, DM_MAX_COLORS)) != DMERR_OK) + return FALSE; + } + else + { + dmError("No remap filename given.\n"); + return FALSE; + } + } + else + { + if (!dmParseMapOptionString(optArg, optRemapTable, + &optNRemapTable, DM_MAX_COLORS, TRUE, "color remap option")) + return FALSE; + } + + optRemapColors = TRUE; + break; + + case 18: + optRemapRemove = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (!optInFilename) + optInFilename = currArg; + else + { + dmError("Source filename already specified, extraneous argument '%s'.\n", + currArg); + return FALSE; + } + + return TRUE; +} + + +void dmPrintByte(FILE *out, int byte, int format, BOOL multicolor) +{ + int i; + + if (multicolor) + { + for (i = ASC_NBITS; i; i -= 2) + { + int val = (byte & (3ULL << (i - 2))) >> (i - 2); + char ch; + switch (format) + { + case FFMT_ASCII: + ch = dmASCIIPalette[val]; + fprintf(out, "%c%c", ch, ch); + break; + case FFMT_ANSI: + fprintf(out, "%c[0;%d;%dm##%c[0m", + 0x1b, + 1, + 31 + optColors[val], + 0x1b); + break; + } + } + } + else + { + for (i = ASC_NBITS; i; i--) + { + int val = (byte & (1ULL << (i - 1))) >> (i - 1); + char ch; + switch (format) + { + case FFMT_ASCII: + ch = val ? '#' : '.'; + fputc(ch, out); + break; + case FFMT_ANSI: + fprintf(out, "%c[0;%d;%dm %c[0m", + 0x1b, + 1, + 31 + optColors[val], + 0x1b); + break; + } + } + } +} + + +void dmDumpCharASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor) +{ + int yc; + + for (yc = 0; yc < C64_CHR_HEIGHT; yc++) + { + fprintf(outFile, "%04x : ", *offs); + dmPrintByte(outFile, buf[yc], format, multicolor); + fprintf(outFile, "\n"); + (*offs)++; + } +} + + +void dmDumpSpriteASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor) +{ + int bufOffs, xc, yc; + + for (bufOffs = yc = 0; yc < C64_SPR_HEIGHT; yc++) + { + fprintf(outFile, "%04x : ", *offs); + for (xc = 0; xc < C64_SPR_WIDTH; xc++) + { + dmPrintByte(outFile, buf[bufOffs], format, multicolor); + fprintf(outFile, " "); + bufOffs++; + (*offs)++; + } + fprintf(outFile, "\n"); + } + (*offs)++; +} + + +#ifdef UNFINISHED +int dmConvertBMP2(DMImage *screen, const DM64Image *img) +{ + int yc; + Uint8 *dp = screen->data; + + for (yc = 0; yc < screen->height; yc++) + { + Uint8 *d = dp; + const int y = yc / 8, yb = yc & 7; + const int scroffsy = y * C64_SCR_CH_WIDTH; + const int bmoffsy = y * C64_SCR_WIDTH; + int xc; + + for (xc = 0; xc < screen->width / 2; xc++) + { + const int x = xc / 4; + const int scroffs = scroffsy + x; + const int b = img->bitmap[0][bmoffsy + (x * 8) + yb]; + const int v = 6 - ((xc * 2) & 6); + Uint8 c; + + switch ((b >> v) & 3) + { + case 0: c = img->bgcolor; break; + case 1: c = img->screen[0][scroffs] >> 4; break; + case 2: c = img->screen[0][scroffs] & 15; break; + case 3: c = img->color[0][scroffs] & 15; break; + } + + *d++ = c; + *d++ = c; + } + + dp += screen->pitch; + } + + return 0; +} +#endif + + +int dmRemapImageColors(DMImage *image) +{ + DMColor *npal = dmCalloc(image->ncolors, sizeof(DMColor)); + int *mapping = dmMalloc(image->ncolors * sizeof(int)); + BOOL *mapped = dmMalloc(image->ncolors * sizeof(BOOL)); + BOOL *used = dmMalloc(image->ncolors * sizeof(BOOL)); + int n, index, xc, yc, ncolors; + + dmMsg(1, "Remapping %d output image colors of %d colors.\n", optNRemapTable, image->ncolors); + + if (npal == NULL || mapping == NULL || mapped == NULL || used == NULL) + { + dmError("Could not allocate memory for reused palette.\n"); + return DMERR_MALLOC; + } + + for (index = 0; index < image->ncolors; index++) + { + mapping[index] = -1; + mapped[index] = used[index] = FALSE; + } + + // Find used colors + dmMsg(2, "Scanning image for used colors...\n"); + for (ncolors = yc = 0; yc < image->height; yc++) + { + Uint8 *dp = image->data + image->pitch * yc; + for (xc = 0; xc < image->width; xc++) + { + Uint8 col = dp[xc]; + if (col < image->ncolors && !used[col]) + { + used[col] = TRUE; + ncolors++; + } + } + } + dmMsg(2, "Found %d used colors, creating remap-table.\n", ncolors); + + // Match and mark mapped colors + for (index = 0; index < optNRemapTable; index++) + { + DMMapValue *map = &optRemapTable[index]; + if (map->triplet) + { + BOOL found = FALSE; + for (n = 0; n < image->ncolors; n++) + { + if (dmCompareColor(&(image->pal[n]), &(map->color), map->alpha)) + { + dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n", + map->color.r, map->color.g, map->color.b, map->color.a, + n, + map->to); + + mapping[n] = map->to; + mapped[map->to] = TRUE; + found = TRUE; + } + } + + if (!found) + { + dmMsg(3, "No RGBA match found for map index %d, #%02x%02x%02x%02x\n", + index, + map->color.r, map->color.g, map->color.b, map->color.a); + } + } + else + { + dmMsg(3, "Map index: %d -> %d\n", + map->from, map->to); + + mapping[map->from] = map->to; + mapped[map->to] = TRUE; + } + } + + + // Fill in the rest + if (optRemapRemove) + { + dmMsg(2, "Removing unused colors.\n"); + for (index = 0; index < image->ncolors; index++) + if (mapping[index] < 0 && used[index]) + { + for (n = 0; n < image->ncolors; n++) + if (!mapped[n]) + { + mapping[index] = n; + mapped[n] = TRUE; + break; + } + } + } + else + { + for (index = 0; index < image->ncolors; index++) + if (mapping[index] < 0) + { + for (n = 0; n < image->ncolors; n++) + if (!mapped[n]) + { + mapping[index] = n; + mapped[n] = TRUE; + break; + } + } + } + + // Calculate final number of palette colors + ncolors = 0; + for (index = 0; index < image->ncolors; index++) + { + if (mapping[index] + 1 > ncolors) + ncolors = mapping[index] + 1; + } + + // Copy palette entries + for (index = 0; index < image->ncolors; index++) + { + if (mapping[index] >= 0) + { + memcpy(&npal[mapping[index]], &(image->pal[index]), sizeof(DMColor)); + } + } + + // Remap image + dmMsg(1, "Remapping image to %d colors...\n", ncolors); + for (yc = 0; yc < image->height; yc++) + { + Uint8 *dp = image->data + image->pitch * yc; + for (xc = 0; xc < image->width; xc++) + { + Uint8 col = dp[xc]; + if (col < image->ncolors && mapping[col] >= 0 && mapping[col] < image->ncolors) + dp[xc] = mapping[col]; + else + dp[xc] = 0; + } + } + + // Set new palette, free memory + dmFree(image->pal); + image->pal = npal; + image->ncolors = ncolors; + + dmFree(mapping); + dmFree(mapped); + dmFree(used); + return DMERR_OK; +} + + +int dmWriteBitmap(const char *filename, DMC64Image *image, int iformat, BOOL enableFixUps) +{ + FILE *outFile = NULL; + Uint8 *buf = NULL; + size_t bufSize; + int res = DMERR_OK; + const DMC64ImageFormat *fmt = &dmC64ImageFormats[iformat]; + + dmMsg(1, "Converting to %s format bitmap.\n", fmt->name); + if (image->type != fmt->type && enableFixUps) + { + // Try to do some simple fixups + if ((fmt->type & D64_FMT_FLI) && (image->type & D64_FMT_FLI) == 0) + { + dmMsg(1, "Upconverting multicolor to FLI.\n"); + int i; + for (i = 1; i < C64_SCR_MAX_BANK; i++) + { + memcpy(image->color[i], image->color[0], C64_SCR_COLOR_SIZE); + memcpy(image->screen[i], image->screen[0], C64_SCR_SCREEN_SIZE); + } + } + } + + + if ((res = dmC64EncodeGenericBMP(&buf, &bufSize, image, fmt)) != DMERR_OK) + goto error; + + dmMsg(2, "Result: %d bytes\n", bufSize); + + if ((outFile = fopen(filename, "wb")) == NULL) + { + res = dmGetErrno(); + dmError("Error opening output file '%s', %d: %s\n", + filename, res, dmErrorStr(res)); + goto error; + } + + if (!dm_fwrite_str(outFile, buf, bufSize)) + { + res = dmGetErrno(); + dmError("Error writing image data to '%s', %d: %s\n", + filename, res, dmErrorStr(res)); + } + +error: + if (outFile != NULL) + fclose(outFile); + dmFree(buf); + return res; +} + + +int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info) +{ + if (info) + { + dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n", + dmImageFormatList[iformat].fext, + image->width, image->height, + image->width * spec->scale, image->height * spec->scale, + spec->scale); + } + + // Perform color remapping + if (optRemapColors) + { + int res; + if ((res = dmRemapImageColors(image)) != DMERR_OK) + return res; + } + + switch (iformat) + { +#ifdef DM_USE_LIBPNG + case IMGFMT_PNG: + if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "32bit RGBA"); + spec->format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA; + return dmWritePNGImage(filename, image, spec); +#endif + + case IMGFMT_PPM: + if (info) dmMsg(2, "24bit RGB output.\n"); + spec->format = DM_IFMT_RGB; + return dmWritePPMImage(filename, image, spec); + + case IMGFMT_PCX: + if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "24bit RGB"); + return dmWritePCXImage(filename, image, spec); + + case IMGFMT_RAW: + case IMGFMT_ARAW: + { + FILE *fp; + char *dataFilename, *fext, *tmpFilename = dm_strdup(filename); + + // Form data file filename + if (tmpFilename == NULL) + return DMERR_MALLOC; + + fext = strrchr(tmpFilename, '.'); + if (fext != NULL) + *fext = 0; + dataFilename = dm_strdup_printf("%s.inc", tmpFilename); + dmFree(tmpFilename); + + // Open data file for writing + if ((fp = fopen(dataFilename, "w")) == NULL) + dmError("Could not create '%s'.\n", dataFilename); + dmFree(dataFilename); + + if (fp != NULL) + { + // Strip extension + int i; + char *palID = dm_strdup_printf("img_%s", filename); + char *fext = strrchr(palID, '.'); + if (fext != NULL) + *fext = 0; + + // Replace any non-alphanumerics + for (i = 0; palID[i]; i++) + { + if (isalnum(palID[i])) + palID[i] = tolower(palID[i]); + else + palID[i] = '_'; + } + + if (iformat == IMGFMT_ARAW) + { + fprintf(fp, + "%s_width: dw.w %d\n" + "%s_height: dw.w %d\n" + "%s_nplanes: dw.w %d\n" + "%s_ncolors: dw.w %d\n" + "%s_palette:\n", + palID, image->width, + palID, image->height, + palID, spec->nplanes, + palID, image->ncolors, + palID); + + dmWriteIFFMasterRAWPalette(fp, image, 1 << optSpec.nplanes, NULL, NULL); + + fprintf(fp, + "%s: incbin \"%s\"\n", + palID, filename); + } + else + { + fprintf(fp, + "%s_width: dw.w %d\n" + "%s_height: dw.w %d\n" + "%s_nplanes: dw.w %d\n", + palID, image->width, + palID, image->height, + palID, spec->nplanes); + } + + fclose(fp); + dmFree(palID); + } + + if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", spec->nplanes, spec->interleave ? "with" : "without"); + return dmWriteRAWImage(filename, image, spec); + } + break; + + default: + return DMERR_INVALID_DATA; + } +} + + +static Uint8 dmConvertByte(const Uint8 *sp, const BOOL multicolor) +{ + Uint8 byte = 0; + int xc; + + if (multicolor) + { + for (xc = 0; xc < 8 / 2; xc++) + { + Uint8 pixel = sp[xc * 2] & 3; + byte |= pixel << (6 - (xc * 2)); + } + } + else + { + for (xc = 0; xc < 8; xc++) + { + Uint8 pixel = sp[xc] == 0 ? 0 : 1; + byte |= pixel << (7 - xc); + } + } + + return byte; +} + + +BOOL dmConvertImage2Char(Uint8 *buf, const DMImage *image, + const int xoffs, const int yoffs, const BOOL multicolor) +{ + int yc; + + if (xoffs < 0 || yoffs < 0 || + xoffs + C64_CHR_WIDTH_PX > image->width || + yoffs + C64_CHR_HEIGHT > image->height) + return FALSE; + + for (yc = 0; yc < C64_CHR_HEIGHT; yc++) + { + const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + xoffs; + buf[yc] = dmConvertByte(sp, multicolor); + } + + return TRUE; +} + + +BOOL dmConvertImage2Sprite(Uint8 *buf, const DMImage *image, + const int xoffs, const int yoffs, const BOOL multicolor) +{ + int yc, xc; + + if (xoffs < 0 || yoffs < 0 || + xoffs + C64_SPR_WIDTH_PX > image->width || + yoffs + C64_SPR_HEIGHT > image->height) + return FALSE; + + for (yc = 0; yc < C64_SPR_HEIGHT; yc++) + { + for (xc = 0; xc < C64_SPR_WIDTH_PX / C64_SPR_WIDTH; xc++) + { + const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + (xc * 8) + xoffs; + buf[(yc * C64_SPR_WIDTH) + xc] = dmConvertByte(sp, multicolor); + } + } + + return TRUE; +} + + +int dmWriteSpritesAndChars(const char *filename, DMImage *image, int outFormat, BOOL multicolor) +{ + int outBlockW, outBlockH, bx, by; + FILE *outFile = NULL; + Uint8 *buf = NULL; + size_t bufSize; + char *outType; + + switch (outFormat) + { + case FFMT_CHAR: + bufSize = C64_CHR_SIZE; + outBlockW = image->width / C64_CHR_WIDTH_PX; + outBlockH = image->height / C64_CHR_HEIGHT; + outType = "char"; + break; + + case FFMT_SPRITE: + bufSize = C64_SPR_SIZE; + outBlockW = image->width / C64_SPR_WIDTH_PX; + outBlockH = image->height / C64_SPR_HEIGHT; + outType = "sprite"; + break; + + default: + dmError("Invalid output format %d, internal error.\n", outFormat); + goto error; + } + + if (outBlockW <= 0 || outBlockH <= 0) + { + dmError("Source image dimensions too small for conversion, block dimensions %d x %d.\n", + outBlockW, outBlockH); + goto error; + } + + if ((outFile = fopen(filename, "wb")) == NULL) + { + int err = dmGetErrno(); + dmError("Could not open '%s' for writing, %d: %s.\n", + filename, err, dmErrorStr(err)); + goto error; + } + + if ((buf = dmMalloc(bufSize)) == NULL) + { + dmError("Could not allocate %d bytes for conversion buffer.\n", + bufSize); + goto error; + } + + dmMsg(1, "Writing %d x %d = %d blocks of %s data...\n", + outBlockW, outBlockH, outBlockW * outBlockH, outType); + + for (by = 0; by < outBlockH; by++) + for (bx = 0; bx < outBlockW; bx++) + { + switch (outFormat) + { + case FFMT_CHAR: + if (!dmConvertImage2Char(buf, image, + bx * C64_CHR_WIDTH_PX, by * C64_CHR_HEIGHT, + multicolor)) + goto error; + break; + + case FFMT_SPRITE: + if (!dmConvertImage2Sprite(buf, image, + bx * C64_SPR_WIDTH_PX, by * C64_SPR_HEIGHT, + multicolor)) + goto error; + } + + if (!dm_fwrite_str(outFile, buf, bufSize)) + { + int err = dmGetErrno(); + dmError("Error writing data block %d,%d to '%s', %d: %s\n", + bx, by, filename, err, dmErrorStr(err)); + goto error; + } + } + + fclose(outFile); + dmFree(buf); + return 0; + +error: + if (outFile != NULL) + fclose(outFile); + dmFree(buf); + return -1; +} + + +int dmDumpSpritesAndChars(FILE *inFile) +{ + int dataOffs, itemCount, outWidth, outWidthPX, outHeight; + size_t bufSize; + Uint8 *bufData; + + switch (optInFormat) + { + case FFMT_CHAR: + bufSize = C64_CHR_SIZE; + outWidth = C64_CHR_WIDTH; + outWidthPX = C64_CHR_WIDTH_PX; + outHeight = C64_CHR_HEIGHT; + break; + + case FFMT_SPRITE: + bufSize = C64_SPR_SIZE; + outWidth = C64_SPR_WIDTH; + outWidthPX = C64_SPR_WIDTH_PX; + outHeight = C64_SPR_HEIGHT; + break; + + default: + dmError("Invalid input format %d, internal error.\n", optInFormat); + return -1; + } + + if ((bufData = dmMalloc(bufSize)) == NULL) + { + dmError("Could not allocate temporary buffer of %d bytes.\n", bufSize); + return -2; + } + + + dataOffs = optInSkip; + itemCount = 0; + + if (optOutFormat == FFMT_ANSI || optOutFormat == FFMT_ASCII) + { + BOOL error = FALSE; + FILE *outFile; + + if (optOutFilename == NULL) + outFile = stdout; + else + if ((outFile = fopen(optOutFilename, "w")) == NULL) + { + int res = dmGetErrno(); + dmError("Error opening output file '%s', %d: %s\n", + optOutFilename, res, dmErrorStr(res)); + goto error; + } + + while (!feof(inFile) && !error && (optItemCount < 0 || itemCount < optItemCount)) + { + memset(bufData, 0, bufSize); + + if (fread(bufData, 1, bufSize, inFile) != bufSize) + { + dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n", + bufSize, dataOffs); + error = TRUE; + } + + fprintf(outFile, "---- : -------------- #%d\n", itemCount); + + switch (optInFormat) + { + case FFMT_CHAR: + dmDumpCharASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor); + break; + case FFMT_SPRITE: + dmDumpSpriteASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor); + break; + } + itemCount++; + } + + fclose(outFile); + } + else + if (optOutFormat == FFMT_IMAGE) + { + DMImage *outImage = NULL; + char *outFilename = NULL; + int outX = 0, outY = 0, err; + + if (optSequential) + { + if (optOutFilename == NULL) + { + dmError("Sequential image output requires filename template.\n"); + goto error; + } + + outImage = dmImageAlloc(outWidthPX, outHeight); + dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n", + optItemCount, + outImage->width, outImage->height, + outImage->width * optSpec.scale, outImage->height * optSpec.scale); + } + else + { + int outIWidth, outIHeight; + if (optItemCount <= 0) + { + dmError("Single-image output requires count to be set (-n).\n"); + goto error; + } + + outIWidth = optPlanedWidth; + outIHeight = (optItemCount / optPlanedWidth); + if (optItemCount % optPlanedWidth) + outIHeight++; + + outImage = dmImageAlloc(outWidthPX * outIWidth, outIHeight * outHeight); + } + + outImage->constpal = TRUE; + outImage->pal = dmC64Palette; + outImage->ncolors = C64_NCOLORS; + outImage->ctransp = 255; + + while (!feof(inFile) && (optItemCount < 0 || itemCount < optItemCount)) + { + memset(bufData, 0, bufSize); + + if (fread(bufData, 1, bufSize, inFile) != bufSize) + { + dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n", + bufSize, dataOffs); + break; + } + + if ((err = dmC64ConvertCSData(outImage, outX * outWidthPX, outY * outHeight, + bufData, outWidth, outHeight, optInMulticolor, optColors)) != DMERR_OK) + { + dmError("Internal error in conversion of raw data to bitmap: %d.\n", err); + break; + } + + if (optSequential) + { + outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, convFormatList[optOutFormat].fext); + if (outFilename == NULL) + { + dmError("Could not allocate memory for filename template?\n"); + goto error; + } + + dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); + dmFree(outFilename); + } + else + { + if (++outX >= optPlanedWidth) + { + outX = 0; + outY++; + } + } + + itemCount++; + } + + if (!optSequential) + { + dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); + } + + dmImageFree(outImage); + } + else + if (optOutFormat == FFMT_BITMAP) + { + if (optSequential) + { + dmError("Sequential output not supported for spr/char -> bitmap conversion.\n"); + goto error; + } + } + + dmFree(bufData); + return 0; + +error: + dmFree(bufData); + return -1; +} + + +int main(int argc, char *argv[]) +{ + FILE *inFile; + const DMC64ImageFormat *cfmt; + DMC64Image cimage; + Uint8 *dataBuf = NULL; + size_t dataSize; + int i; + + // Default colors + for (i = 0; i < C64_MAX_COLORS; i++) + optColors[i] = i; + + // Initialize and parse commandline + dmInitProg("gfxconv", "Simple graphics converter", "0.75", NULL, NULL); + + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + +#ifndef DM_USE_LIBPNG + if (optOutFormat == IMGFMT_PNG) + { + dmError("PNG output format support not compiled in, sorry.\n"); + goto error; + } +#endif + + // Determine input format, if not specified' + if (optInFormat == FFMT_AUTO && optInFilename != NULL) + { + char *dext = strrchr(optInFilename, '.'); + dmMsg(4, "Trying to determine file format by extension.\n"); + if (dext) + { + dmGetFormatByExt(dext + 1, &optInFormat, &optInSubFormat); + } + } + + if (optInFilename == NULL) + { + if (optInFormat == FFMT_AUTO) + { + dmError("Standard input cannot be used without specifying input format.\n"); + dmError("Perhaps you should try using --help\n"); + goto error; + } + inFile = stdin; + } + else + if ((inFile = fopen(optInFilename, "rb")) == NULL) + { + int res = dmGetErrno(); + dmError("Error opening input file '%s', %d: %s\n", + optInFilename, res, dmErrorStr(res)); + goto error; + } + + if (dmReadDataFile(inFile, NULL, &dataBuf, &dataSize) != 0) + goto error; + + if (optInFormat == FFMT_AUTO || optInFormat == FFMT_BITMAP) + { + // Probe for format + const DMC64ImageFormat *forced = NULL; + int res; + + if (optForcedFormat >= 0) + { + forced = &dmC64ImageFormats[optForcedFormat]; + dmMsg(0,"Forced %s format image, type %d, %s\n", + forced->name, forced->type, forced->fext); + } + + res = dmC64DecodeBMP(&cimage, dataBuf, dataSize, optInSkip, optInSkip + 2, &cfmt, forced); + if (forced == NULL && cfmt != NULL) + { + dmMsg(1,"Probed %s format image, type %d, %s\n", + cfmt->name, cfmt->type, cfmt->fext); + } + + if (res == 0) + optInFormat = FFMT_BITMAP; + } + + if (optInFormat == FFMT_AUTO || optInFormat == FFMT_IMAGE) + { + DMImageFormat *ifmt = NULL; + int index; + dmMsg(4, "Trying to probe image formats.\n"); + if (dmImageProbeGeneric(dataBuf + optInSkip, dataSize - optInSkip, &ifmt, &index) > 0) + { + optInFormat = FFMT_IMAGE; + optInSubFormat = index; + dmMsg(2, "Probed %s format image.\n", ifmt->fext); + } + } + + if (optInFormat == FFMT_AUTO) + { + dmError("No input format specified, and could not be determined automatically.\n"); + exit(1); + } + + // Skip, if needed + if (fseek(inFile, optInSkip, SEEK_SET) != 0) + { + int res = dmGetErrno(); + dmError("Could not seek to file position %d (0x%x): %s\n", + optInSkip, optInSkip, dmErrorStr(res)); + goto error; + } + + int inFormat = dmGetConvFormat(optInFormat, optInSubFormat), + outFormat = dmGetConvFormat(optOutFormat, optOutSubFormat); + + if (inFormat != -1 && outFormat != -1) + { + char *inFmtName = convFormatList[inFormat].name, + *inFmtExt = convFormatList[inFormat].fext, + *outFmtName = convFormatList[outFormat].name, + *outFmtExt = convFormatList[outFormat].fext; + + if (optInFormat == FFMT_BITMAP) + inFmtExt = cfmt->name; + + dmMsg(1, "Attempting conversion %s (%s) -> %s (%s)\n", + inFmtName, inFmtExt, outFmtName, outFmtExt); + } + + switch (optInFormat) + { + case FFMT_SPRITE: + case FFMT_CHAR: + dmDumpSpritesAndChars(inFile); + break; + + case FFMT_BITMAP: + { + DMImage *outImage = NULL; + int res = DMERR_OK; + + if (optOutFilename == NULL) + { + dmError("Output filename not set, required for image formats.\n"); + goto error; + } + + switch (optOutFormat) + { + case FFMT_IMAGE: + res = dmC64ConvertBMP2Image(&outImage, &cimage, cfmt, TRUE); + + if (res != DMERR_OK || outImage == NULL) + { + dmError("Error in bitmap to image conversion.\n"); + goto error; + } + + res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); + break; + + + case FFMT_BITMAP: + res = dmWriteBitmap(optOutFilename, &cimage, optOutSubFormat, TRUE); + break; + + case FFMT_CHAR: + case FFMT_SPRITE: + res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor); + break; + + default: + dmError("Unsupported output format for bitmap/image conversion.\n"); + break; + } + + dmImageFree(outImage); + } + break; + + case FFMT_IMAGE: + { + DMImage *outImage = NULL; + int res = DMERR_OK; + + if (optOutFilename == NULL) + { + dmError("Output filename not set, required for image formats.\n"); + goto error; + } + + // Read input + DMImageFormat *ifmt = &dmImageFormatList[optInSubFormat]; + if (ifmt->readFILE != NULL) + res = ifmt->readFILE(inFile, &outImage); + else + dmError("Unsupported input image format for bitmap/image conversion.\n"); + + if (res != DMERR_OK || outImage == NULL) + break; + + switch (optOutFormat) + { + case FFMT_IMAGE: + res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); + break; + + case FFMT_CHAR: + case FFMT_SPRITE: + res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor); + break; + + default: + dmError("Unsupported output format for bitmap/image conversion.\n"); + break; + } + + dmImageFree(outImage); + } + break; + } + + fclose(inFile); + + dmFree(dataBuf); + exit(0); + return 0; + +error: + dmFree(dataBuf); + return -3; + exit(3); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/mod2wav.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,314 @@ +/* + * mod2wav - Render XM/JSSMOD module to WAV waveform file + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include "jss.h" +#include "jssmod.h" +#include "jssmix.h" +#include "jssplr.h" +#include "dmlib.h" +#include "dmargs.h" +#include "dmwav.h" +#include "dmmutex.h" + + +char *optInFilename = NULL, *optOutFilename = NULL; +int optOutFormat = JSS_AUDIO_S16, + optOutChannels = 2, + optOutFreq = 44100, + optMuteOChannels = -1, + optStartOrder = -1; +BOOL optUsePlayTime = FALSE; +size_t optPlayTime; + + +DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 3, '1', "16bit", "16-bit output", OPT_NONE }, + { 4, '8', "8bit", "8-bit output", OPT_NONE }, + { 5, 'm', "mono", "Mono output", OPT_NONE }, + { 6, 's', "stereo", "Stereo output", OPT_NONE }, + { 7, 'f', "freq", "Output frequency", OPT_ARGREQ }, + { 8, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, + { 9, 'o', "order", "Start from order #", OPT_ARGREQ }, + { 10, 't', "time", "Play for # seconds", OPT_ARGREQ }, +// {10, 'l', "loop", "Loop for # times", OPT_ARGREQ }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + (void) optArg; + + switch (optN) + { + case 0: + dmPrintBanner(stdout, dmProgName, + "[options] [sourcefile] [destfile]"); + + dmArgsPrintHelp(stdout, optList, optListN); + exit(0); + break; + + case 2: + dmVerbosity++; + break; + + case 3: + optOutFormat = JSS_AUDIO_S16; + break; + + case 4: + optOutFormat = JSS_AUDIO_U8; + break; + + case 5: + optOutChannels = JSS_AUDIO_MONO; + break; + + case 6: + optOutChannels = JSS_AUDIO_STEREO; + break; + + case 7: + optOutFreq = atoi(optArg); + break; + + case 8: + optMuteOChannels = atoi(optArg); + break; + + case 9: + optStartOrder = atoi(optArg); + break; + + case 10: + optPlayTime = atoi(optArg); + optUsePlayTime = TRUE; + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (!optInFilename) + optInFilename = currArg; + else + if (!optOutFilename) + optOutFilename = currArg; + else + { + dmError("Too many filename arguments (only source and dest needed) '%s'\n", currArg); + return FALSE; + } + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + DMResource *inFile = NULL; + FILE *outFile = NULL; + JSSModule *mod = NULL; + JSSMixer *dev = NULL; + JSSPlayer *plr = NULL; + int result = -1; + size_t bufLen = 1024*4, dataTotal, dataWritten, sampSize; + Uint8 *mb = NULL; + + dmInitProg("mod2wav", "XM/JSSMOD to WAV renderer", "0.2", NULL, NULL); + dmVerbosity = 1; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Check arguments + if (optInFilename == NULL || optOutFilename == NULL) + { + dmError("Input or output file not specified. Try --help.\n"); + return 1; + } + + // Initialize miniJSS + jssInit(); + + // Open the source file + if ((inFile = dmf_create_stdio(optInFilename, "rb")) == NULL) + { + dmError("Error opening input file '%s', %d: %s\n", + optInFilename, errno, strerror(errno)); + return 1; + } + + // Read module file + fprintf(stderr, "Reading file: %s\n", optInFilename); +#ifdef JSS_SUP_XM + fprintf(stderr, "* Trying XM...\n"); + result = jssLoadXM(inFile, &mod); +#endif +#ifdef JSS_SUP_JSSMOD + if (result != 0) + { + size_t bufgot, bufsize = dmfsize(inFile); + Uint8 *buf = dmMalloc(bufsize); + dmfseek(inFile, 0L, SEEK_SET); + fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); + if ((bufgot = dmfread(buf, 1, bufsize, inFile)) != bufsize) + { + fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n", + bufgot, dmferror(inFile), dmErrorStr(dmferror(inFile))); + return 2; + } + result = jssLoadJSSMOD(buf, bufsize, &mod); + dmFree(buf); + } +#endif + dmf_close(inFile); + if (result != DMERR_OK) + { + dmError("Error loading module file, %d: %s\n", + result, dmErrorStr(result)); + return 3; + } + + // Try to convert it + if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK) + { + dmError("Could not convert module for playing, %d: %s\n", + result, dmErrorStr(result)); + return 3; + } + + // Open mixer + dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); + if (dev == NULL) + { + dmError("jvmInit() returned NULL\n"); + return 4; + } + + sampSize = jvmGetSampleSize(dev); + if ((mb = dmMalloc(bufLen * sampSize)) == NULL) + { + dmError("Could not allocate mixing buffer\n"); + return 5; + } + + dmMsg(1, "Using fmt=%d, bits=%d, channels=%d, freq=%d [%d / sample]\n", + optOutFormat, jvmGetSampleRes(dev), optOutChannels, optOutFreq, + sampSize); + + // Initialize player + if ((plr = jmpInit(dev)) == NULL) + { + dmError("jmpInit() returned NULL.\n"); + return 6; + } + + // Set callback + jvmSetCallback(dev, jmpExec, plr); + + // Initialize playing + jmpSetModule(plr, mod); + if (optStartOrder >= 0) + { + dmMsg(1, "Starting from song order #%d\n", optStartOrder); + } else + optStartOrder = 0; + + jmpPlayOrder(plr, optStartOrder); + jvmSetGlobalVol(dev, 150); + + if (optMuteOChannels > 0 && optMuteOChannels <= mod->nchannels) + { + int i; + for (i = 0; i < mod->nchannels; i++) + jvmMute(dev, i, TRUE); + jvmMute(dev, optMuteOChannels - 1, FALSE); + } + + // Open output file + if ((outFile = fopen(optOutFilename, "wb")) == NULL) + { + dmError("Error opening output file '%s'. (%s)\n", optInFilename, strerror(errno)); + return 7; + } + + // Write initial header + dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, 1024); + + // Render audio data and output to file + if (optUsePlayTime) + dmMsg(1, "Rendering module (%d seconds) ...\n", optPlayTime); + else + dmMsg(1, "Rendering module ...\n"); + + optPlayTime *= optOutFreq; + dataTotal = 0; + dataWritten = 1; + while (plr->isPlaying && dataWritten > 0) + { + size_t writeLen = bufLen; + if (optUsePlayTime && (writeLen + dataTotal) > optPlayTime) + writeLen = optPlayTime - dataTotal; + + if (writeLen > 0) + { + jvmRenderAudio(dev, mb, writeLen); +#if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + jssEncodeSample16((Uint16 *)mb, writeLen * optOutChannels, jsampSwapEndianess); +#endif + dataWritten = fwrite(mb, sampSize, writeLen, outFile); + if (dataWritten < writeLen) + { + dmError("Error writing data!\n"); + fclose(outFile); + return 8; + } + dataTotal += dataWritten; + } + + if (optUsePlayTime && dataTotal >= optPlayTime) + break; + } + + // Write the correct header + if (fseek(outFile, 0L, SEEK_SET) != 0) + { + dmError("Error rewinding to header position!\n"); + return 9; + } + + dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, dataTotal); + + // Done! + fclose(outFile); + + jmpClose(plr); + jvmClose(dev); + jssFreeModule(mod); + jssClose(); + + dmMsg(1, "OK.\n"); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/objlink.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,990 @@ +/* + * objlink - Link files (RAW and PRG) into one PRG object + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <errno.h> +#include "dmlib.h" +#include "dmargs.h" +#include "dmfile.h" +#include "dmmutex.h" + +#define MAX_FILENAMES (128) +#define MAX_MEMBLOCKS (128) + + +/* Typedefs + */ +typedef struct +{ + ssize_t start, end; // Start and end address + int type; // Type + char *name; // Name of the block + int placement; +} DMMemBlock; + +typedef struct +{ + char *name; // Description of memory model + char *desc; + ssize_t size; // Total addressable memory size + ssize_t nmemBlocks; // Defined memory areas + DMMemBlock memBlocks[MAX_MEMBLOCKS]; +} DMMemModel; + +typedef struct +{ + char *filename; + int type; + int placement; + ssize_t addr; +} DMSourceFile; + +// Source file type +enum +{ + STYPE_RAW = 1, + STYPE_PRG, + STYPE_PRGA +}; + +// How to determine block placement / address +enum +{ + PLACE_STATIC = 1, // Already known + PLACE_ARGUMENT, // Commandline argument + PLACE_FILE, // From file +}; + +enum +{ + FMT_GENERIC = 1, + FMT_PLAIN, + FMT_DECIMAL +}; + +enum +{ + MTYPE_NONE = 0, + MTYPE_ROM, // Hard ROM + MTYPE_ROM_WT, // Write to RAM through ROM + MTYPE_IO, // I/O lines + MTYPE_RES // RESERVED +}; + +enum +{ + LA_NONE = -2, + LA_AUTO = -1 +}; + +/* Memory models + */ +const DMMemModel memoryModels[] = { + { "C64 unrestricted", "$01 = $34", (64*1024), 0, { + { 0, 0, 0, NULL, 0 } + }}, + + { "C64 normal (IO+Basic+Kernal)", "$01 = $37", (64*1024), 3, { + { 0xA000, 0xBFFF, MTYPE_ROM_WT, "Basic ROM", PLACE_STATIC }, + { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, + { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, + }}, + + { "C64 modified (IO+Kernal)", "$01 = $36", (64*1024), 2, { + { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, + { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, + }}, + + { "C64 modified (IO only)", "$01 = $35", (64*1024), 1, { + { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, + }}, + + { "C64 modified (Char+Kernal+Basic)", "$01 = $33", (64*1024), 3, { + { 0xA000, 0xBFFF, MTYPE_ROM_WT, "Basic ROM", PLACE_STATIC }, + { 0xD000, 0xDFFF, MTYPE_ROM, "Char ROM", PLACE_STATIC }, + { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, + }}, + +/* + { "C64 normal", "$01 = $37", (64*1024), 0, { + { 0x0000, 0x0000, MTYPE_RAM, "" }, + }}, +*/ +}; + +static const int nmemoryModels = sizeof(memoryModels) / sizeof(memoryModels[0]); + + +/* Global variables + */ +int nsrcFiles = 0; // Number of source files +DMSourceFile srcFiles[MAX_FILENAMES]; // Source file names + +int nmemBlocks = 0; +DMMemBlock memBlocks[MAX_FILENAMES]; + +char *optLinkFileName = NULL; +int optLinkFileFormat = FMT_GENERIC; + +BOOL optDescribe = FALSE, + optAllowOverlap = FALSE; + +Uint32 optInitValue = 0; +int optInitValueType = 1; +ssize_t optCropStart, optCropEnd; +BOOL optCropOutput = FALSE; + +ssize_t optLoadAddress = LA_AUTO; + +int optMemModel = 0; +const DMMemModel *memModel = NULL; +Uint8 *memory = NULL; + +char *optDestName = NULL; + + +/* Arguments + */ +static DMOptArg optList[] = { + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'r', "input-raw", "RAW input: -r <file>:<addr>", OPT_ARGREQ }, + { 2, 'p', "input-prg", "PRG input: -p <file>[:<addr>]", OPT_ARGREQ }, + { 12, 's', "section", "Reserved section: -s <start>-<end>[,name] or <start>:<len>[,name]", OPT_ARGREQ }, + { 5, 'o', "output", "Specify output file, -o <file>", OPT_ARGREQ }, + { 6, 'O', "overlap", "Allow overlapping memory areas", OPT_NONE }, + { 7, 'm', "model", "Set memory model", OPT_ARGREQ }, + { 8, 'l', "link-file", "Output addresses and labels into file", OPT_ARGREQ }, + { 9, 'f', "format", "Format of link-file: (g)eneric, (p)lain, (d)ecimal", OPT_ARGREQ }, + { 10, 'i', "initvalue", "Initialize memory with: -i <byte/word/dword>:[bwd]", OPT_ARGREQ }, + { 11, 'd', "describe", "Output ASCII memory map description", OPT_NONE }, + { 13, 'c', "crop", "Crop output file to: -c <start>-<end> or <start>:<len>", OPT_ARGREQ }, + { 14, 'L', "load-address","Set output file load address (or 'none' for 'raw' output)", OPT_ARGREQ }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + int i; + + dmPrintBanner(stdout, dmProgName, "[options]"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf( + "\n" + "Each numeric argument can be prefixed with $ or 0x for hexadecimal values.\n" + "NOTICE! -p filename:<addr> will ignore load address and use <addr> instead!\n" + "\n" + "Available memory models:\n"); + + for (i = 0; i < nmemoryModels; i++) + { + const DMMemModel *m = &memoryModels[i]; + printf(" %d = %-40s [%s] (%d kB)\n", + i, m->name, m->desc, m->size / 1024); + } +} + + +off_t dmGetFileSize(FILE *f) +{ + off_t len, pos = ftell(f); + fseeko(f, 0, SEEK_END); + len = ftell(f); + fseek(f, pos, SEEK_SET); + return len; +} + + +/* Memory block handling + */ +void reserveMemBlock(ssize_t startAddr, ssize_t endAddr, const char *blockName, int blockType) +{ + if (startAddr > endAddr) + { + dmError("ERROR! Block '%s' has startAddr=$%.4x > endAddr=$%.4x!\n", + blockName, startAddr, endAddr); + exit(4); + } + + if (nmemBlocks < MAX_FILENAMES) + { + memBlocks[nmemBlocks].start = startAddr; + memBlocks[nmemBlocks].end = endAddr; + memBlocks[nmemBlocks].name = dm_strdup(blockName); + memBlocks[nmemBlocks].type = blockType; + nmemBlocks++; + } + else + { + dmError("Maximum number of memBlock definitions (%d) exceeded!\n", + MAX_FILENAMES); + exit(4); + } +} + + +int compareMemBlock(const void *cva, const void *cvb) +{ + const DMMemBlock *a = cva, *b = cvb; + return a->start - b->start; +} + + +BOOL dmParseSection(const char *arg, ssize_t *sectStart, ssize_t *sectEnd, char **sectName, BOOL canHasName) +{ + char sectMode, *sep, *str, *namesep; + ssize_t tmpi; + + // Define reserved section + // Create a copy of the argument + if ((str = dm_strdup(arg)) == NULL) + { + dmError("Could not allocate temporary string!\n"); + exit(128); + } + + // Get start address + if ((sep = strchr(str, '-')) == NULL && + (sep = strchr(str, ':')) == NULL) + { + dmError("Section definition '%s' invalid.\n", arg); + goto error; + } + sectMode = *sep; + *sep = 0; + + // Get value + if (!dmGetIntVal(str, sectStart)) + { + dmError("Section start address '%s' in '%s' invalid.\n", str, arg); + goto error; + } + + // Check for name + namesep = strchr(sep + 1, ','); + if (canHasName && namesep != NULL) + { + *namesep = 0; + namesep++; + if (*namesep == 0) + { + dmError("Section definition '%s' name is empty. Either specify name or leave it out.\n", + arg); + goto error; + } + *sectName = dm_strdup(namesep); + } + else + if (namesep != NULL) + { + dmError("Section definition does not allow a name, syntax error in '%s' at '%s'.\n", + arg, namesep); + goto error; + } + + // Get end address or length + if (!dmGetIntVal(sep + 1, &tmpi)) + { + dmError("Section %s '%s' in '%s' invalid.\n", + sectMode == '-' ? "end address" : "length", + sep + 1, arg); + goto error; + } + + if (sectMode == ':') + { + *sectEnd = *sectStart + tmpi - 1; + } + else + { + if (tmpi < *sectStart) + { + dmError("Section start address > end address in '%s'.\n", + arg); + goto error; + } + *sectEnd = tmpi; + } + + dmFree(str); + return TRUE; + +error: + dmFree(str); + return FALSE; +} + + +BOOL dmParseInputFile(char *arg, const int type1, const int type2, const char *desc, BOOL requireAddr) +{ + ssize_t tmpi = 0; + BOOL hasAddr = FALSE; + char *sep; + + if ((sep = strrchr(arg, ':')) != NULL) + { + *sep = 0; + if (!dmGetIntVal(sep + 1, &tmpi)) + { + dmError("Invalid %s address '%s' specified for '%s'.\n", + desc, sep + 1, arg); + return FALSE; + } + hasAddr = TRUE; + } + else + if (requireAddr) + { + dmError("No %s loading address specified for '%s'.\n", desc, arg); + return FALSE; + } + + srcFiles[nsrcFiles].filename = arg; + srcFiles[nsrcFiles].type = hasAddr ? type1 : type2; + srcFiles[nsrcFiles].addr = tmpi; + nsrcFiles++; + return TRUE; +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + char *p; + ssize_t tmpi; + + switch (optN) { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + // Add RAW + if (!dmParseInputFile(optArg, STYPE_RAW, STYPE_RAW, "RAW", TRUE)) + return FALSE; + break; + + case 2: + // Add PRG + if (!dmParseInputFile(optArg, STYPE_PRGA, STYPE_PRG, "PRG", FALSE)) + return FALSE; + break; + + case 5: + // Set output file name + optDestName = optArg; + break; + + case 6: + // Allow overlapping segments + optAllowOverlap = TRUE; + dmError("Warning, allowing overlapping data.\n"); + break; + + case 7: + // Set memory model + optMemModel = atoi(optArg); + if (optMemModel < 0 || optMemModel >= nmemoryModels) + { + dmError("Invalid memory model number %i!\n", optMemModel); + return FALSE; + } + break; + + case 8: + // Linker file + optLinkFileName = optArg; + break; + + case 9: + // Linker file format + switch (tolower(optArg[0])) + { + case 'g': + optLinkFileFormat = FMT_GENERIC; + break; + case 'p': + optLinkFileFormat = FMT_PLAIN; + break; + case 'd': + optLinkFileFormat = FMT_DECIMAL; + break; + + default: + dmError("Invalid/unknown linker file format '%s'!\n", + optArg); + return FALSE; + } + break; + + case 10: + // Initialization value + optInitValueType = 1; + if ((p = strrchr(optArg, ':')) != NULL) + { + *p = 0; + switch (tolower(p[1])) + { + case 'b': optInitValueType = 1; break; + case 'w': optInitValueType = 2; break; + case 'd': optInitValueType = 4; break; + default: + dmError("Invalid init value type '%c' specified for '%s'.\n", + p[1], optArg); + return FALSE; + } + } + if (!dmGetIntVal(optArg, &tmpi)) + { + dmError("Invalid initvalue '%s'.\n", optArg); + return FALSE; + } + optInitValue = tmpi; + break; + + case 11: + // Set describe mode + optDescribe = TRUE; + break; + + case 12: + { + char *sectName = "Clear"; + ssize_t sectStart, sectEnd, sectLen; + if (!dmParseSection(optArg, §Start, §End, §Name, TRUE)) + return FALSE; + + // Allocate memory block + sectLen = sectEnd - sectStart + 1; + dmMsg(1, "Reserve $%.4x - $%.4x ($%x, %d bytes) as '%s'\n", + sectStart, sectEnd, sectLen, sectLen, sectName); + + reserveMemBlock(sectStart, sectEnd, sectName, MTYPE_RES); + } + break; + + case 13: + { + size_t cropLen; + if (!dmParseSection(optArg, &optCropStart, &optCropEnd, NULL, FALSE)) + return FALSE; + + cropLen = optCropEnd - optCropEnd + 1; + dmMsg(1, "Cutting output to $%.4x - $%.4x ($%x, %d bytes)\n", + optCropStart, optCropEnd, cropLen, cropLen); + + optCropOutput = TRUE; + } + break; + + case 14: + // Set loading address + if (strcasecmp(optArg, "none") == 0) + optLoadAddress = LA_NONE; + else + { + if (!dmGetIntVal(optArg, &tmpi)) + { + dmError("Invalid loading address '%s'.\n", optArg); + return FALSE; + } + if (tmpi < 0 || tmpi >= 64*1024) + { + dmError("Invalid or insane loading address %d/$%x!\n", + tmpi); + return FALSE; + } + optLoadAddress = tmpi; + } + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +int dmLoadPRG(const char *filename, BOOL forceAddr, const ssize_t destAddr) +{ + FILE *f; + ssize_t dataSize, loadAddr, endAddr; + Uint16 tmpAddr; + + // Open the input file + if ((f = fopen(filename, "rb")) == NULL) + { + dmError("Error opening input file '%s' (%s).\n", + filename, strerror(errno)); + return 1; + } + + // Get filesize + if ((dataSize = dmGetFileSize(f) - 2) < 0) + { + dmError("Error getting file size for '%s'.\n", filename); + return 6; + } + + // Get loading address + if (!dm_fread_le16(f, &tmpAddr)) + { + dmError("Error reading input file '%s' (%s).\n", + filename, strerror(errno)); + return 2; + } + + // Show information + loadAddr = forceAddr ? destAddr : tmpAddr; + endAddr = loadAddr + dataSize - 1; + + dmPrint(1, "* Loading '%s', %s at $%.4x-$%.4x", + filename, forceAddr ? "PRGA" : "PRG", loadAddr, endAddr); + + if (endAddr >= memModel->size) + { + dmPrint(1, " .. Does not fit into the memory!\n"); + return 5; + } + + // Load data + if (fread(&memory[loadAddr], dataSize, 1, f) < 1) + { + dmPrint(1, " .. Error: %s.\n", + strerror(errno)); + return 4; + } + + dmPrint(1, " .. OK\n"); + + // Add to list of blocks + reserveMemBlock(loadAddr, endAddr, filename, MTYPE_RES); + + return 0; +} + + +int dmLoadRAW(const char *filename, const ssize_t destAddr) +{ + FILE *f; + ssize_t dataSize, endAddr; + + // Open the input file + if ((f = fopen(filename, "rb")) == NULL) + { + dmError("Error opening input file '%s' (%s).\n", + filename, strerror(errno)); + return 1; + } + + // Get filesize + if ((dataSize = dmGetFileSize(f)) < 0) + { + dmError("Error getting file size for '%s'.\n", filename); + return 6; + } + + // Show information + endAddr = destAddr + dataSize - 1; + dmPrint(1, "* Loading '%s', RAW at $%.4x-$%.4x", + filename, destAddr, endAddr); + + if (endAddr >= memModel->size) + { + dmPrint(1, " .. Does not fit into the memory!\n"); + return 5; + } + + // Load data + if (fread(&memory[destAddr], dataSize, 1, f) < 1) + { + dmPrint(1, " .. Error: %s.\n", + strerror(errno)); + return 4; + } + + dmPrint(1, " .. OK\n"); + + // Add info to list + reserveMemBlock(destAddr, endAddr, filename, MTYPE_RES); + + return 0; +} + + +int outputLinkData(FILE *dfile, const char *blockName, const int blockStart, const int blockEnd) +{ + char *tmpStr, *s, *t; + int blockSize; + + blockSize = (blockEnd - blockStart + 1); + + // Create label name from filename + tmpStr = dm_strdup(blockName); + if (tmpStr == NULL) + { + dmError("Could not allocate memory for string '%s'!\n", + blockName); + return -1; + } + + if ((t = strrchr(tmpStr, '/'))) + s = (t + 1); + else if ((t = strrchr(tmpStr, '\\'))) + s = (t + 1); + else + s = tmpStr; + + if ((t = strrchr(s, '.'))) + *t = 0; + + for (t = s; *t; t++) + { + if (!isalnum(*t)) + *t = '_'; + } + + // Print the label line + switch (optLinkFileFormat) + { + case FMT_PLAIN: + fprintf(dfile, "%s = $%.4x\n", tmpStr, blockStart); + break; + + case FMT_DECIMAL: + fprintf(dfile, "%s = %d\n", tmpStr, blockStart); + break; + + case FMT_GENERIC: + default: + fprintf(dfile, "; %s ($%.4x - $%.4x, %d/$%x bytes)\n", + blockName, blockStart, blockEnd, blockSize, blockSize); + fprintf(dfile, "%s = $%.4x\n", s, blockStart); + break; + } + + dmFree(tmpStr); + return 0; +} + + +/* Print out an ASCII presentation of memory map + */ +void memPrintLine(FILE *f) +{ + fprintf(f, " +------------------------------------------+\n"); +} + +void memPrintEmpty(FILE *f, ssize_t n) +{ + ssize_t i; + for (i = 0; i < n; i++) + fprintf(f, " | |\n"); +} + +void dmDescribeMemory(FILE *f) +{ + int i; + DMMemBlock *prev = NULL; + + memPrintLine(f); + + for (i = 0; i < nmemBlocks; i++) + { + DMMemBlock *curr = &memBlocks[i]; + char desc[512], *s; + ssize_t siz, kz; + + // Check for empty, unreserved areas + siz = (curr->start - 1) - (prev->end + 1) + 1; + if (prev != NULL && siz > 1) + { + kz = siz / (1024 * 2); + + if (kz > 1) memPrintEmpty(f, kz); + + snprintf(desc, sizeof(desc), "EMPTY (%d)", siz); + fprintf(f, "$%.4x - $%.4x | %-40s |\n", prev->end + 1, curr->start - 1, desc); + + if (kz > 1) memPrintEmpty(f, kz); + memPrintLine(f); + } + prev = curr; + + // Print current block + switch (curr->type) + { + case MTYPE_NONE: s = "N/A (NC)"; break; + case MTYPE_ROM: s = "ROM"; break; + case MTYPE_ROM_WT: s = "ROM/WT"; break; + case MTYPE_IO: s = "I/O"; break; + case MTYPE_RES: s = "RSVD"; break; + default: s = "????"; break; + } + + siz = curr->end - curr->start + 1; + kz = siz / (1024 * 2); + + if (kz > 1) memPrintEmpty(f, kz); + snprintf(desc, sizeof(desc), "%s (%s, %d)", curr->name, s, siz); + fprintf(f, "$%.4x - $%.4x | %-40s |\n", curr->start, curr->end, desc); + if (kz > 1) memPrintEmpty(f, kz); + memPrintLine(f); + + } + + fprintf(f, + "\n" + "NC = Not Connected\n" + "RSVD = Reserved\n" + "ROM/WT = RAM under 'write-through' ROM\n" + "\n" + ); +} + + +/* + * The main program + */ +int main(int argc, char *argv[]) +{ + FILE *dfile = NULL; + BOOL hasOverlaps; + int i, j; + ssize_t startAddr, endAddr, dataSize, totalSize; + + dmInitProg("objlink", "Simple file-linker", "0.80", NULL, NULL); + dmVerbosity = 1; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, TRUE)) + exit(1); + + if (nsrcFiles < 1) + { + dmError("Nothing to do. (try --help)\n"); + exit(0); + } + + // Allocate memory + memModel = &memoryModels[optMemModel]; + dmMsg(1, "Using memory model #%d '%s', %d bytes.\n", + optMemModel, memModel->name, memModel->size); + + memory = (Uint8 *) dmMalloc(memModel->size + 32); + if (memory == NULL) + { + dmError("Could not allocate memory.\n"); + exit(2); + } + + // Initialize memory + dmMsg(1, "Initializing memory with "); + + if (optInitValueType == 1 || optInitValue <= 0xff) + { + dmPrint(1, "BYTE 0x%.2x\n", optInitValue); + memset(memory, optInitValue, memModel->size); + } + else + if (optInitValueType == 2 || optInitValue <= 0xffff) + { + uint16_t *mp = (uint16_t *) memory; + dmPrint(1, "WORD 0x%.4x\n", optInitValue); + for (i = memModel->size / sizeof(*mp); i; i--) + { + *mp++ = optInitValue; + } + } + else + { + Uint32 *mp = (Uint32 *) memory; + dmPrint(1, "DWORD 0x%.8x\n", optInitValue); + for (i = memModel->size / sizeof(*mp); i; i--) + { + *mp++ = optInitValue; + } + } + + // Load the datafiles + for (i = 0; i < nsrcFiles; i++) + switch (srcFiles[i].type) + { + case STYPE_RAW: + dmLoadRAW(srcFiles[i].filename, srcFiles[i].addr); + break; + + case STYPE_PRG: + dmLoadPRG(srcFiles[i].filename, FALSE, 0); + break; + + case STYPE_PRGA: + dmLoadPRG(srcFiles[i].filename, TRUE, srcFiles[i].addr); + break; + } + + // Add memory model blocks + dmMsg(1, "Applying memory model restrictions...\n"); + for (i = 0; i < memModel->nmemBlocks; i++) + { + reserveMemBlock( + memModel->memBlocks[i].start, + memModel->memBlocks[i].end, + memModel->memBlocks[i].name, + memModel->memBlocks[i].type); + } + + // Sort the blocks + qsort(memBlocks, nmemBlocks, sizeof(DMMemBlock), compareMemBlock); + + // Check for overlapping conflicts + hasOverlaps = FALSE; + for (i = 0; i < nmemBlocks; i++) + for (j = 0; j < nmemBlocks; j++) + if (j != i && memBlocks[i].type == MTYPE_RES) + { + DMMemBlock *mbi = &memBlocks[i], + *mbj = &memBlocks[j]; + + // Check for per-file conflicts + if ((mbj->start >= mbi->start && mbj->start <= mbi->end) || + (mbj->end >= mbi->start && mbj->end <= mbi->end)) + { + dmPrint(1, "* '%s' and '%s' overlap ($%.4x-$%.4x vs $%.4x-$%.4x)\n", + mbi->name, mbj->name, mbi->start, + mbi->end, mbj->start, mbj->end); + hasOverlaps = TRUE; + } + } + + if (!optAllowOverlap && hasOverlaps) + { + dmError("Error occured, overlaps not allowed.\n"); + exit(5); + } + + // Find out start and end-addresses + startAddr = memModel->size; + totalSize = endAddr = 0; + for (i = 0; i < nmemBlocks; i++) + { + DMMemBlock *mbi = &memBlocks[i]; + if (mbi->type == MTYPE_RES) + { + if (mbi->start < startAddr) + startAddr = mbi->start; + + if (mbi->end > endAddr) + endAddr = mbi->end; + + totalSize += (mbi->end - mbi->start + 1); + } + } + + if (startAddr >= memModel->size || endAddr < startAddr) + { + dmError("Invalid saveblock addresses (start=$%.4x, end=$%.4x)!\n", startAddr, endAddr); + exit(8); + } + + // Output linkfile + if (optLinkFileName) + { + dmMsg(1, "Writing linkfile to '%s'\n", optLinkFileName); + if ((dfile = fopen(optLinkFileName, "wb")) == NULL) + { + dmError("Error creating file '%s' (%s).\n", optLinkFileName, strerror(errno)); + exit(1); + } + + switch (optLinkFileFormat) + { + case FMT_GENERIC: + default: + fprintf(dfile, "; Definitions generated by %s v%s\n", + dmProgName, dmProgVersion); + break; + } + + for (i = 0; i < nmemBlocks; i++) + { + DMMemBlock *mbi = &memBlocks[i]; + outputLinkData(dfile, mbi->name, mbi->start, mbi->end); + } + + fclose(dfile); + } + + // Show some information + if (optCropOutput) + { + startAddr = optCropStart; + endAddr = optCropEnd; + } + + dataSize = endAddr - startAddr + 1; + + if (dataSize - totalSize > 0) + { + dmMsg(1, "Total of %d/$%x bytes unused(?) areas.\n", + dataSize - totalSize, dataSize - totalSize); + } + + dmMsg(1, "Writing $%.4x - $%.4x (%d/$%x bytes) ", + startAddr, endAddr, dataSize, dataSize); + + + // Open the destination file + if (optDestName == NULL) + { + dfile = stdout; + dmPrint(1, "...\n"); + } + else if ((dfile = fopen(optDestName, "wb")) == NULL) + { + dmError("Error creating output file '%s' (%s).\n", optDestName, strerror(errno)); + exit(1); + } + else + dmPrint(1, "to '%s'\n", optDestName); + + // Save loading address + if (optLoadAddress >= 0) + { + dmMsg(1, "Using specified loading address $%.4x\n", optLoadAddress); + dm_fwrite_le16(dfile, optLoadAddress); + } + else + if (optLoadAddress == LA_AUTO) + { + dmMsg(1, "Using automatic loading address $%.4x\n", startAddr); + dm_fwrite_le16(dfile, startAddr); + } + else + { + dmMsg(1, "Writing raw output, without loading address.\n"); + } + + // Save the data + if (fwrite(&memory[startAddr], dataSize, 1, dfile) < 1) + { + dmError("Error writing to file (%s)\n", strerror(errno)); + } + + fclose(dfile); + + // Describe + if (optDescribe) + dmDescribeMemory(stdout); + + exit(0); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/packed.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,465 @@ +/* + * PACKed - PACKfile EDitor + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2011 Tecnic Software productions (TNSP) + */ +#include "dmlib.h" +#include "dmargs.h" +#include "dmpack.h" +#include "dmpackutil.h" +#include "dmres.h" +#include "dmmutex.h" +#include <errno.h> + +#define SET_MAX_FILES (4096) +#define SET_DEFAULT_PACK "data.pak" + +enum +{ + CMD_NONE = 0, + CMD_CREATE, + CMD_ADD, + CMD_LIST, + CMD_EXTRACT +} DCOMMAND; + +enum +{ + PACK_EXTRACTED = 0x0001, +}; + +int nsrcFilenames = 0; +char * srcFilenames[SET_MAX_FILES]; +char * optPackFilename = NULL; +BOOL optCompress = TRUE; +int optCommand = CMD_NONE; +int optDefResFlags = 0; + + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'p', "pack", "Set pack filename (default: " SET_DEFAULT_PACK ")", OPT_ARGREQ }, + { 2, 'c', "create", "Create and add files to PACK", OPT_NONE }, + { 3, 'a', "add", "Add files to PACK", OPT_NONE }, + { 4, 'l', "list", "List files in PACK", OPT_NONE }, + { 5, 'e', "extract", "Extract files from PACK", OPT_NONE }, + { 6, 'n', "nocompress", "No compression", OPT_NONE }, + { 7, 'v', "verbose", "Increase verbosity", OPT_NONE }, + { 8, 'f', "resflags", "Set default resource flags (-f 0xff)", OPT_ARGREQ }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, "[options] [-p <packfilename>] [filename[s]]"); + dmArgsPrintHelp(stdout, optList, optListN); + fprintf(stdout, + "\n" + "Examples:\n" + "$ %s -p test.pak -l -- list files in test.pak\n" + "$ %s -a foobar.jpg -- add foobar.jpg in " SET_DEFAULT_PACK "\n" + "$ %s -x foobar.jpg -- extract foobar.jpg from " SET_DEFAULT_PACK "\n", + dmProgName, dmProgName, dmProgName); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + (void) optArg; + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + optPackFilename = optArg; + break; + case 2: + optCommand = CMD_CREATE; + break; + case 3: + optCommand = CMD_ADD; + break; + case 4: + optCommand = CMD_LIST; + break; + case 5: + optCommand = CMD_EXTRACT; + break; + + case 6: + optCompress = FALSE; + break; + + case 7: + dmVerbosity++; + break; + + case 8: + { + int i; + if (!dmGetIntVal(optArg, &i)) + { + dmError("Invalid flags value '%s'.\n", optArg); + return FALSE; + } + optDefResFlags = i; + } + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (nsrcFilenames < SET_MAX_FILES) + { + srcFilenames[nsrcFilenames] = currArg; + nsrcFilenames++; + } + else + { + dmError("Maximum number of input files (%d) exceeded!\n", + SET_MAX_FILES); + return FALSE; + } + return TRUE; +} + + +/* Compare a string to a pattern. Case-SENSITIVE version. + * The matching pattern can consist of any normal characters plus + * wildcards ? and *. "?" matches any character and "*" matches + * any number of characters. + */ +BOOL dm_strmatch(const char *str, const char *pattern) +{ + BOOL didMatch = TRUE, isAnyMode = FALSE, isEnd = FALSE; + const char *tmpPattern = NULL; + + // Check given pattern and string + if (str == NULL || pattern == NULL) + return FALSE; + + // Start comparision + do { + didMatch = FALSE; + switch (*pattern) + { + case '?': + // Any single character matches + if (*str) + { + didMatch = TRUE; + pattern++; + str++; + } + break; + + case '*': + didMatch = TRUE; + pattern++; + if (!*pattern) + isEnd = TRUE; + isAnyMode = TRUE; + tmpPattern = pattern; + break; + + case 0: + if (isAnyMode) + { + if (*str) + str++; + else + isEnd = TRUE; + } + else + { + if (*str) + { + if (tmpPattern) + { + isAnyMode = TRUE; + pattern = tmpPattern; + } + else + didMatch = FALSE; + } + else + isEnd = TRUE; + } + break; + default: + if (isAnyMode) + { + if (*pattern == *str) + { + isAnyMode = FALSE; + didMatch = TRUE; + } + else + { + if (*str) + { + didMatch = TRUE; + str++; + } + } + } + else + { + if (*pattern == *str) + { + didMatch = TRUE; + if (*pattern) + pattern++; + if (*str) + str++; + } + else + { + if (tmpPattern) + { + didMatch = TRUE; + isAnyMode = TRUE; + pattern = tmpPattern; + } + } + } + + if (!*str && !*pattern) + isEnd = TRUE; + break; + + } // switch + + } while (didMatch && !isEnd); + + return didMatch; +} + + +int dmAddFileToPack(DMPackFile *pack, const char *filename, int compression, int resFlags) +{ + DMPackEntry *node; + int res = dm_pack_add_file(pack, filename, compression, resFlags, &node); + + if (res != DMERR_OK) + { + dmPrint(1, "%-32s [ERROR:%d]\n", + filename, res); + } + else + { + char tmp[16]; + dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); + dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=%s]\n", + filename, node->filename, + node->size, node->length, node->offset, + tmp); + } + + return res; +} + + +int main(int argc, char *argv[]) +{ + int i, res = 0; + DMPackFile *pack = NULL; + +#ifndef __WIN32 + stderr = stdout; +#endif + + // Parse arguments + dmInitProg("packed", "Pack File Editor", "0.4", NULL, NULL); + dmVerbosity = 1; + + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Check PACK filename + if (optPackFilename == NULL) + optPackFilename = SET_DEFAULT_PACK; + + if (optCommand == CMD_NONE) + { + argShowHelp(); + dmError("Nothing to do.\n"); + exit(0); + return 0; + } + + dmMsg(1, "Processing %s ...\n", optPackFilename); + + // Execute command + switch (optCommand) + { + case CMD_CREATE: + case CMD_ADD: + switch (optCommand) + { + case CMD_CREATE: + dmMsg(1, "Creating new PACK\n"); + res = dm_pack_create(optPackFilename, &pack); + break; + + case CMD_ADD: + dmMsg(1, "Opening existing PACK\n"); + res = dm_pack_open(optPackFilename, &pack, FALSE); + break; + } + + // Add files into PACK + if (res == DMERR_OK) + { + dmMsg(1, "Adding %d files...\n", nsrcFilenames); + + for (i = 0; i < nsrcFilenames; i++) + { + // Handle resource definition files + if (srcFilenames[i][0] == '@') + { + } + else + { + dmAddFileToPack(pack, srcFilenames[i], optCompress, optDefResFlags); + } + } + + dmMsg(1, "w=%d\n", dm_pack_write(pack)); + dmMsg(1, "c=%d\n", dm_pack_close(pack)); + } + else + { + dmError("Could not open packfile, error #%d: %s\n", res, + dmErrorStr(res)); + } + break; + + case CMD_LIST: + // List files in PACK + res = dm_pack_open(optPackFilename, &pack, TRUE); + if (res == DMERR_OK) + { + DMPackEntry *node; + for (i = 0, node = pack->entries; node; i++) + node = node->next; + dmMsg(1, "%d files total\n", i); + + dmPrint(0, "%-32s | %8s | %8s | %8s | %s\n", + "Name", "Size", "CSize", "Offset", "ResFlags"); + + for (node = pack->entries; node != NULL; node = node->next) + { + BOOL match; + + // Check for matches + if (nsrcFilenames > 0) + { + match = FALSE; + for (i = 0; i < nsrcFilenames && !match; i++) + { + match = dm_strmatch(node->filename, srcFilenames[i]); + } + } + else + match = TRUE; + + if (match) + { + char flags[16]; + dmres_flags_to_symbolic(flags, sizeof(flags), node->resFlags); + + dmPrint(0, "%-32s | %8d | %8d | %08x | %s\n", + node->filename, node->size, node->length, + node->offset, flags); + } + } + + dmMsg(1, "c=%d\n", dm_pack_close(pack)); + } + else + dmError("Could not open packfile, error #%d: %s\n", res, + dmErrorStr(res)); + break; + + case CMD_EXTRACT: + // Extract files from PACK + res = dm_pack_open(optPackFilename, &pack, TRUE); + if (res == DMERR_OK) + { + DMPackEntry *node; + FILE *resFile = fopen(DMRES_RES_FILE, "w"); + if (resFile == NULL) + { + dmError("Could not create resource output file '%s' #%d: %s\n", + DMRES_RES_FILE, errno, strerror(errno)); + } + + for (node = pack->entries; node != NULL; node = node->next) + { + BOOL match; + + // Check for matches + if (nsrcFilenames > 0) + { + match = FALSE; + for (i = 0; (i < nsrcFilenames) && !match; i++) + { + match = dm_strmatch(node->filename, srcFilenames[i]); + } + } + else + match = TRUE; + + if (match && (node->privFlags & PACK_EXTRACTED) == 0) + { + char tmp[16]; + + // Mark as done + node->privFlags |= PACK_EXTRACTED; + + // Print one entry + dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); + dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=%s]\n", + node->filename, node->size, node->length, + node->offset, tmp); + + dm_pack_extract_file(pack, node); + + if (resFile != NULL) + { + fprintf(resFile, + "%s|%s\n", node->filename, tmp); + } + } + } + + dmMsg(1, "c=%d\n", dm_pack_close(pack)); + + if (resFile != NULL) + fclose(resFile); + } + else + dmError("Could not open packfile, error #%d: %s\n", res, + dmErrorStr(res)); + break; + + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ppl.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,932 @@ +/* + * Cyrbe Pasci Player - A simple SDL-based UI for XM module playing + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <SDL.h> +#include "dmlib.h" + +#include "jss.h" +#include "jssmod.h" +#include "jssmix.h" +#include "jssplr.h" + +#include "dmargs.h" +#include "dmimage.h" +#include "dmtext.h" + +#include "setupfont.h" + + +struct +{ + BOOL exitFlag; + SDL_Surface *screen; + SDL_Event event; + int optScrWidth, optScrHeight, optVFlags, optScrDepth; + + int actChannel; + BOOL pauseFlag; + + JSSModule *mod; + JSSMixer *dev; + JSSPlayer *plr; + SDL_AudioSpec afmt; +} engine; + +struct +{ + Uint32 boxBg, inboxBg, box1, box2, viewDiv, activeRow, activeChannel; +} col; + + +DMBitmapFont *font = NULL; + +char *optFilename = NULL; +int optOutFormat = JSS_AUDIO_S16, + optOutChannels = 2, + optOutFreq = 48000, + optMuteOChannels = -1, + optStartOrder = 0; +BOOL optUsePlayTime = FALSE; +size_t optPlayTime; + + +DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 2, 0, "fs", "Fullscreen", OPT_NONE }, + { 3, 'w', "window", "Initial window size/resolution -w 640x480", OPT_ARGREQ }, + + { 4, '1', "16bit", "16-bit output", OPT_NONE }, + { 5, '8', "8bit", "8-bit output", OPT_NONE }, + { 6, 'm', "mono", "Mono output", OPT_NONE }, + { 7, 's', "stereo", "Stereo output", OPT_NONE }, + { 8, 'f', "freq", "Output frequency", OPT_ARGREQ }, + + { 9, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, + { 10, 'o', "order", "Start from order #", OPT_ARGREQ }, + { 11, 't', "time", "Play for # seconds", OPT_ARGREQ }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, "[options] <module>"); + dmArgsPrintHelp(stdout, optList, optListN); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + dmVerbosity++; + break; + + case 2: + engine.optVFlags |= SDL_FULLSCREEN; + break; + + case 3: + { + int w, h; + if (sscanf(optArg, "%dx%d", &w, &h) == 2) + { + if (w < 320 || h < 200 || w > 3200 || h > 3200) + { + dmError("Invalid width or height: %d x %d\n", w, h); + return FALSE; + } + engine.optScrWidth = w; + engine.optScrHeight = h; + } + else + { + dmError("Invalid size argument '%s'.\n", optArg); + return FALSE; + } + } + break; + + case 4: + optOutFormat = JSS_AUDIO_S16; + break; + + case 5: + optOutFormat = JSS_AUDIO_U8; + break; + + case 6: + optOutChannels = JSS_AUDIO_MONO; + break; + + case 7: + optOutChannels = JSS_AUDIO_STEREO; + break; + + case 8: + optOutFreq = atoi(optArg); + break; + + case 9: + optMuteOChannels = atoi(optArg); + break; + + case 10: + optStartOrder = atoi(optArg); + break; + + case 11: + optPlayTime = atoi(optArg); + optUsePlayTime = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (!optFilename) + optFilename = currArg; + else + { + dmError("Too many filename arguments '%s'\n", currArg); + return FALSE; + } + + return TRUE; +} + + +void dmDrawBMTextConstQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt) +{ + const char *ptr = fmt; + DMUnscaledBlitFunc blit = NULL; + + while (*ptr) + { + int ch = *ptr++; + SDL_Surface *glyph; + + if (ch == '_') + { + xc += 4; + continue; + } + + if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL) + { + if (blit == NULL) + blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode); + + blit(glyph, xc, yc, screen); + xc += font->width; + } + else + xc += font->width; + } +} + + +void dmDrawBMTextVAQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, va_list ap) +{ + char tmp[512]; + vsnprintf(tmp, sizeof(tmp), fmt, ap); + dmDrawBMTextConstQ(screen, font, mode, xc, yc, tmp); +} + + +void dmDrawBMTextQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + dmDrawBMTextVAQ(screen, font, mode, xc, yc, fmt, ap); + va_end(ap); +} + + +Uint32 dmCol(float r, float g, float b) +{ + return dmMapRGB(engine.screen, 255.0f * r, 255.0f * g, 255.0f * b); +} + + +BOOL dmInitializeVideo() +{ + SDL_FreeSurface(engine.screen); + + engine.screen = SDL_SetVideoMode( + engine.optScrWidth, engine.optScrHeight, engine.optScrDepth, + engine.optVFlags | SDL_RESIZABLE | SDL_SWSURFACE | SDL_HWPALETTE); + + if (engine.screen == NULL) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + return FALSE; + } + + col.inboxBg = dmCol(0.6, 0.5, 0.2); + col.boxBg = dmCol(0.7, 0.6, 0.3); + col.box1 = dmCol(1.0, 0.9, 0.6); + col.box2 = dmCol(0.3, 0.3, 0.15); + col.viewDiv = dmCol(0,0,0); + col.activeRow = dmCol(0.5,0.4,0.1); + col.activeChannel = dmCol(0.6, 0.8, 0.2); + + return TRUE; +} + + +void dmDisplayChn(SDL_Surface *screen, int x0, int y0, int x1, int y1, int nchannel, JSSChannel *chn) +{ + int yh = y1 - y0 - 2; + if (yh < 10 || chn == NULL) + return; + + int xc, ym = y0 + (y1 - y0) / 2, vol = FP_GETH(chn->chVolume); + int pitch = screen->pitch / sizeof(Uint32); + int len = FP_GETH(chn->chSize); + DMFixedPoint offs = chn->chPos; + Uint32 coln = dmCol(0.0, 0.8, 0.0), colx = dmCol(1.0, 0, 0); + Uint32 *pix = screen->pixels; + Sint16 *data = chn->chData; + + + dmFillBox3D(screen, x0, y0, x1, y1, + (chn->chMute ? dmCol(0.3,0.1,0.1) : dmCol(0,0,0)), + nchannel == engine.actChannel ? colx : col.box2, + nchannel == engine.actChannel ? colx : col.box1); + + if (chn->chData == NULL || !chn->chPlaying) + return; + + if (chn->chDirection) + { + for (xc = x0 + 1; xc < x1 - 1; xc++) + { + if (FP_GETH(offs) >= len) + break; + Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255); + pix[xc + val * pitch] = coln; + FP_ADD(offs, chn->chDeltaO); + } + } + else + { + for (xc = x0 + 1; xc < x1 - 1; xc++) + { + if (FP_GETH(offs) < 0) + break; + Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255); + pix[xc + val * pitch] = coln; + FP_SUB(offs, chn->chDeltaO); + } + } +} + + +void dmDisplayChannels(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSMixer *dev) +{ + int nchannel, qx, qy, + qwidth = x1 - x0, + qheight = y1 - y0, + nwidth = jsetNChannels, + nheight = 1; + + if (qheight < 40) + return; + + while (qwidth / nwidth <= 60 && qheight / nheight >= 40) + { + nheight++; + nwidth /= nheight; + } + +// fprintf(stderr, "%d x %d\n", nwidth, nheight); + + if (qheight / nheight <= 40) + { + nwidth = qwidth / 60; + nheight = qheight / 40; + } + + qwidth /= nwidth; + qheight /= nheight; + + for (nchannel = qy = 0; qy < nheight && nchannel < jsetNChannels; qy++) + { + for (qx = 0; qx < nwidth && nchannel < jsetNChannels; qx++) + { + int xc = x0 + qx * qwidth, + yc = y0 + qy * qheight; + + dmDisplayChn(screen, xc + 1, yc + 1, + xc + qwidth - 1, yc + qheight - 1, + nchannel, &dev->channels[nchannel]); + + nchannel++; + } + } +} + + +static const char patNoteTable[12][3] = +{ + "C-", "C#", "D-", + "D#", "E-", "F-", + "F#", "G-", "G#", + "A-", "A#", "B-" +}; + + +#define jmpNMODEffectTable (36) +static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +static const char jmpHexTab[16] = "0123456789ABCDEF"; + +static inline char dmHexVal(int v) +{ + return jmpHexTab[v & 15]; +} + +void dmPrintNote(SDL_Surface *screen, int xc, int yc, JSSNote *n) +{ + char text[32]; + char *ptr = text; + + switch (n->note) + { + case jsetNotSet: + strcpy(ptr, "..._"); + break; + case jsetNoteOff: + strcpy(ptr, "===_"); + break; + default: + sprintf(ptr, "%s%i_", + patNoteTable[n->note % 12], + n->note / 12); + break; + } + + ptr += 4; + + if (n->instrument != jsetNotSet) + { + int v = n->instrument + 1; + *ptr++ = dmHexVal(v >> 4); + *ptr++ = dmHexVal(v); + } + else + { + *ptr++ = '.'; + *ptr++ = '.'; + } + *ptr++ = '_'; + + if (n->volume == jsetNotSet) + { + *ptr++ = '.'; + *ptr++ = '.'; + } + else + if (n->volume >= 0x00 && n->volume <= 0x40) + { + *ptr++ = dmHexVal(n->volume >> 4); + *ptr++ = dmHexVal(n->volume); + } + else + { + char c; + switch (n->volume & 0xf0) + { + case 0x50: c = '-'; break; + case 0x60: c = '+'; break; + case 0x70: c = '/'; break; + case 0x80: c = '\\'; break; + case 0x90: c = 'S'; break; + case 0xa0: c = 'V'; break; + case 0xb0: c = 'P'; break; + case 0xc0: c = '<'; break; + case 0xd0: c = '>'; break; + case 0xe0: c = 'M'; break; + default: c = '?'; break; + } + *ptr++ = c; + *ptr++ = dmHexVal(n->volume); + } + *ptr++ = '_'; + + if (n->effect >= 0 && n->effect < jmpNMODEffectTable) + *ptr++ = jmpMODEffectTable[n->effect]; + else + *ptr++ = (n->effect == jsetNotSet ? '.' : '?'); + + if (n->param != jsetNotSet) + { + *ptr++ = dmHexVal(n->param >> 4); + *ptr++ = dmHexVal(n->param); + } + else + { + *ptr++ = '.'; + *ptr++ = '.'; + } + + *ptr = 0; + + dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, xc, yc, text); +} + + +void dmDisplayPattern(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSPattern *pat, int row) +{ + int cwidth = (font->width * 10 + 3 * 4 + 5), + lwidth = 6 + font->width * 3, + qy0 = y0 + font->height + 2, + qy1 = y1 - font->height - 2, + qwidth = ((x1 - x0 - lwidth) / cwidth), + qheight = ((qy1 - qy0 - 4) / (font->height + 1)), + nrow, nchannel, yc, choffs, + midrow = qheight / 2; + + if (engine.actChannel < qwidth / 2) + choffs = 0; + else + if (engine.actChannel >= pat->nchannels - qwidth/2) + choffs = pat->nchannels - qwidth; + else + choffs = engine.actChannel - qwidth/2; + + dmDrawBox3D(screen, x0 + lwidth, qy0, x1, qy1, col.box2, col.box1); + + for (nchannel = 0; nchannel < qwidth; nchannel++) + { + int bx0 = x0 + lwidth + 1 + nchannel * cwidth, + bx1 = bx0 + cwidth; + + if (engine.actChannel == nchannel + choffs) + { + dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.activeChannel); + } + else + { + dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.inboxBg); + } + } + + yc = qy0 + 2 + (font->height + 1) * midrow; + dmFillRect(screen, x0 + lwidth + 1, yc - 1, x1 - 1, yc + font->height, col.activeRow); + + for (nchannel = 0; nchannel < qwidth; nchannel++) + { + int bx0 = x0 + lwidth + 1 + nchannel * cwidth, + bx1 = bx0 + cwidth; + + dmDrawVLine(screen, qy0 + 1, qy1 - 1, bx1, col.viewDiv); + + if (jvmGetMute(engine.dev, nchannel + choffs)) + { + dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, + bx0 + (cwidth - font->width * 5) / 2, qy1 + 3, "MUTED"); + } + + dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, + bx0 + (cwidth - font->width * 3) / 2, y0 + 1, "%3d", + nchannel + choffs); + } + + for (nrow = 0; nrow < qheight; nrow++) + { + int crow = nrow - midrow + row; + yc = qy0 + 2 + (font->height + 1) * nrow; + + if (crow >= 0 && crow < pat->nrows) + { + dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, x0, yc, "%03d", crow); + + for (nchannel = 0; nchannel < qwidth; nchannel++) + { + if (choffs + nchannel >= pat->nchannels) + break; + + dmPrintNote(screen, x0 + lwidth + 4 + nchannel * cwidth, yc, + pat->data + (pat->nchannels * crow) + choffs + nchannel); + } + } + } +} + + +void audioCallback(void *userdata, Uint8 *stream, int len) +{ + JSSMixer *d = (JSSMixer *) userdata; + + if (d != NULL) + { + jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); + } +} + + +void dmMuteChannels(BOOL mute) +{ + int i; + for (i = 0; i < engine.mod->nchannels; i++) + jvmMute(engine.dev, i, mute); +} + +int main(int argc, char *argv[]) +{ + BOOL initSDL = FALSE, audioInit = FALSE; + DMResource *file = NULL; + int result = -1; + BOOL muteState = FALSE; + + memset(&engine, 0, sizeof(engine)); + + engine.optScrWidth = 640; + engine.optScrHeight = 480; + engine.optScrDepth = 32; + + dmInitProg("CBP", "Cyrbe Basci Player", "0.1", NULL, NULL); + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Open the files + if (optFilename == NULL) + { + dmError("No filename specified.\n"); + return 1; + } + + if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) + { + int err = dmGetErrno(); + dmError("Error opening file '%s', %d: (%s)\n", + optFilename, err, dmErrorStr(err)); + return 1; + } + + // Initialize miniJSS + jssInit(); + + // Read module file + dmMsg(1, "Reading file: %s\n", optFilename); +#ifdef JSS_SUP_XM + dmMsg(2, "* Trying XM...\n"); + result = jssLoadXM(file, &engine.mod); +#endif +#ifdef JSS_SUP_JSSMOD + if (result != 0) + { + size_t bufgot, bufsize = dmfsize(file); + Uint8 *buf = dmMalloc(bufsize); + dmfseek(file, 0L, SEEK_SET); + dmMsg(2, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); + if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) + { + dmf_close(file); + dmError("Error reading file (not enough data %d), #%d: %s\n", + bufgot, dmferror(file), dmErrorStr(dmferror(file))); + goto error_exit; + } + result = jssLoadJSSMOD(buf, bufsize, &engine.mod); + dmFree(buf); + } +#endif + dmf_close(file); + + if (result != DMERR_OK) + { + dmError("Error loading module file, %d: %s\n", + result, dmErrorStr(result)); + goto error_exit; + } + + // Try to convert it + if ((result = jssConvertModuleForPlaying(engine.mod)) != DMERR_OK) + { + dmError("Could not convert module for playing, %d: %s\n", + result, dmErrorStr(result)); + goto error_exit; + } + + // Get font +// file = dmf_create_stdio("fnsmall.fnt", "rb"); + file = dmf_create_memio(NULL, "pplfont.fnt", engineSetupFont, sizeof(engineSetupFont)); + if (file == NULL) + { + dmError("Error opening font file 'pplfont.fnt'.\n"); + goto error_exit; + } + result = dmLoadBitmapFont(file, &font); + dmf_close(file); + if (result != DMERR_OK) + { + dmError("Could not load font from file, %d: %s\n", + result, dmErrorStr(result)); + goto error_exit; + } + + // Initialize SDL components + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error_exit; + } + initSDL = TRUE; + + + // Initialize mixing device + dmMsg(2, "Initializing miniJSS mixer with: %d, %d, %d\n", + optOutFormat, optOutChannels, optOutFreq); + + engine.dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); + if (engine.dev == NULL) + { + dmError("jvmInit() returned NULL\n"); + goto error_exit; + } + + switch (optOutFormat) + { + case JSS_AUDIO_S16: engine.afmt.format = AUDIO_S16SYS; break; + case JSS_AUDIO_U16: engine.afmt.format = AUDIO_U16SYS; break; + case JSS_AUDIO_S8: engine.afmt.format = AUDIO_S8; break; + case JSS_AUDIO_U8: engine.afmt.format = AUDIO_U8; break; + default: + dmError("Unsupported audio format %d (could not set matching SDL format)\n", + optOutFormat); + goto error_exit; + } + + engine.afmt.freq = optOutFreq; + engine.afmt.channels = optOutChannels; + engine.afmt.samples = optOutFreq / 16; + engine.afmt.callback = audioCallback; + engine.afmt.userdata = (void *) engine.dev; + + // Open the audio device + if (SDL_OpenAudio(&engine.afmt, NULL) < 0) + { + dmError("Couldn't open SDL audio: %s\n", + SDL_GetError()); + goto error_exit; + } + audioInit = TRUE; + + // Initialize player + if ((engine.plr = jmpInit(engine.dev)) == NULL) + { + dmError("jmpInit() returned NULL\n"); + goto error_exit; + } + + jvmSetCallback(engine.dev, jmpExec, engine.plr); + jmpSetModule(engine.plr, engine.mod); + jmpPlayOrder(engine.plr, optStartOrder); + jvmSetGlobalVol(engine.dev, 64); + + if (optMuteOChannels >= 0 && optMuteOChannels < engine.mod->nchannels) + { + dmMuteChannels(TRUE); + jvmMute(engine.dev, optMuteOChannels, FALSE); + engine.actChannel = optMuteOChannels; + muteState = TRUE; + } + + // Initialize video + if (!dmInitializeVideo()) + goto error_exit; + + SDL_WM_SetCaption(dmProgDesc, dmProgName); + + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + // okay, main loop here ... "play" module and print out info + SDL_LockAudio(); + SDL_PauseAudio(0); + SDL_UnlockAudio(); + + int currTick, prevTick = 0, prevRow = -1; + + while (!engine.exitFlag) + { + currTick = SDL_GetTicks(); + BOOL force = (currTick - prevTick > 500), updated = FALSE; + + while (SDL_PollEvent(&engine.event)) + switch (engine.event.type) + { + case SDL_KEYDOWN: + switch (engine.event.key.keysym.sym) + { + case SDLK_ESCAPE: + engine.exitFlag = TRUE; + break; + + case SDLK_SPACE: + engine.pauseFlag = !engine.pauseFlag; + SDL_PauseAudio(engine.pauseFlag); + break; + + case SDLK_LEFT: + if (engine.actChannel > 0) + { + engine.actChannel--; + force = TRUE; + } + break; + + case SDLK_RIGHT: + if (engine.actChannel < engine.mod->nchannels) + { + engine.actChannel++; + force = TRUE; + } + break; + + case SDLK_m: + if (engine.event.key.keysym.mod & KMOD_SHIFT) + { + muteState = !muteState; + dmMuteChannels(muteState); + } + else + if (engine.event.key.keysym.mod & KMOD_CTRL) + { + dmMuteChannels(FALSE); + } + else + { + jvmMute(engine.dev, engine.actChannel, !jvmGetMute(engine.dev, engine.actChannel)); + } + force = TRUE; + break; + + case SDLK_PAGEUP: + JSS_LOCK(engine.dev); + JSS_LOCK(engine.plr); + jmpChangeOrder(engine.plr, dmClamp(engine.plr->order - 1, 0, engine.mod->norders)); + JSS_UNLOCK(engine.plr); + JSS_UNLOCK(engine.dev); + force = TRUE; + break; + + case SDLK_PAGEDOWN: + JSS_LOCK(engine.dev); + JSS_LOCK(engine.plr); + jmpChangeOrder(engine.plr, dmClamp(engine.plr->order + 1, 0, engine.mod->norders)); + JSS_UNLOCK(engine.plr); + JSS_UNLOCK(engine.dev); + force = TRUE; + break; + + case SDLK_f: + engine.optVFlags ^= SDL_FULLSCREEN; + if (!dmInitializeVideo()) + goto error_exit; + force = TRUE; + break; + + default: + break; + } + + break; + + case SDL_VIDEORESIZE: + engine.optScrWidth = engine.event.resize.w; + engine.optScrHeight = engine.event.resize.h; + + if (!dmInitializeVideo()) + goto error_exit; + + break; + + case SDL_VIDEOEXPOSE: + break; + + case SDL_QUIT: + engine.exitFlag = TRUE; + break; + } + + +#if 1 + JSS_LOCK(engine.plr); + JSSPattern *currPattern = engine.plr->pattern; + int currRow = engine.plr->row; + if (!engine.plr->isPlaying) + engine.exitFlag = TRUE; + JSS_UNLOCK(engine.plr); + + if (currRow != prevRow || force) + { + prevRow = currRow; + force = TRUE; + } + + // Draw frame + if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0) + { + dmError("Can't lock surface.\n"); + goto error_exit; + } + + if (force) + { + dmClearSurface(engine.screen, col.boxBg); + + dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5, "%s v%s by ccr/TNSP - (c) Copyright 2012 TNSP", dmProgDesc, dmProgVersion); + + dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12 + 11, + "Song: '%s'", + engine.mod->moduleName); + + dmDisplayPattern(engine.screen, 5, 40, + engine.screen->w - 6, engine.screen->h * 0.8, + currPattern, currRow); + + JSS_LOCK(engine.plr); + dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12, + "Tempo: %3d | Speed: %3d | Row: %3d/%-3d | Order: %3d/%-3d | Pattern: %3d/%-3d", + engine.plr->tempo, engine.plr->speed, + engine.plr->row, engine.plr->pattern->nrows, + engine.plr->order, engine.mod->norders, + engine.plr->npattern, engine.mod->npatterns); + JSS_UNLOCK(engine.plr); + updated = TRUE; + } + + if (force || currTick - prevTick >= (engine.pauseFlag ? 100 : 20)) + { + JSS_LOCK(engine.dev); + dmDisplayChannels(engine.screen, 5, engine.screen->h * 0.8 + 5, + engine.screen->w - 5, engine.screen->h - 5, engine.dev); + JSS_UNLOCK(engine.dev); + updated = TRUE; + } + + if (force) + prevTick = currTick; + +#endif + // Flip screen + if (SDL_MUSTLOCK(engine.screen) != 0) + SDL_UnlockSurface(engine.screen); + + if (updated) + SDL_Flip(engine.screen); + + SDL_Delay(engine.pauseFlag ? 100 : 30); + } + +error_exit: + if (engine.screen) + SDL_FreeSurface(engine.screen); + + dmMsg(0, "Audio shutdown.\n"); + if (audioInit) + { + SDL_LockAudio(); + SDL_PauseAudio(1); + SDL_UnlockAudio(); + SDL_CloseAudio(); + } + + jmpClose(engine.plr); + jvmClose(engine.dev); + jssFreeModule(engine.mod); + + dmFreeBitmapFont(font); + + if (initSDL) + SDL_Quit(); + + jssClose(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/svg2qd.py Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,102 @@ +#!/usr/bin/python +import sys +import re +import xml.etree.ElementTree as ET + + +def bf(x) : + return int(round(float(x))) + + +def printVertex(v) : + if type(v) is list : + return "{:.2f},{:.2f},{:.2f}".format(v[0], v[1], v[2]) + else : + return v + + +def getTransform(elem) : + if "transform" in elem.attrib : + ntrans = elem.attrib["transform"] + tmatch = re.compile(r"translate\((.*?)\)", re.IGNORECASE) + for trns in tmatch.finditer(ntrans) : + coord = trns.group(1).split(",") + return [float(coord[0]), float(coord[1]), 0] + return None + + +def getStyle(elem) : + style = {} + if "style" in elem.attrib : + for elem in elem.attrib["style"].split(";") : + kv = elem.split(":") + style[kv[0]] = kv[1] + return style + + +def printVertices(type, vertices, width, level) : + if len(vertices) > 0 : + list = map(lambda v:printVertex(v), vertices) + str = "# "+ type + if type == "m" : + str = "R" + elif type == "M" : + str = "L" + elif type == "c" : + str = "R" + print "{}{}{} {} {}".format(" "*level, str, len(vertices)-1, " ".join(list), width) + + +def printPath(path, level) : + style = getStyle(path) + width = bf(style["stroke-width"]) + + trans = getTransform(path) + if trans : + print "{}G{}".format(" "*level, printVertex(trans)) + + vertices = [] + type = "" + for elem in path.attrib["d"].split(" ") : + if elem == "m" or elem == "M" : + printVertices(type, vertices, width, level) + vertices = [] + type = elem + elif elem == "z" : + vertices.append("Z") + elif elem == "c" or elem == "C" : + print "Curves not supported! Path ID '{}':\n{}".format(path.attrib["id"], path.attrib["d"]) + sys.exit(0) + else : + tmp = elem.split(",") + px = float(tmp[0]) + py = float(tmp[1]) + vertices.append([px, py, 0]) + + printVertices(type, vertices, width, level) + if trans : + print "{}E\n".format(" "*level) + + +def iterateDocument(elems, level) : + for elem in elems: + if elem.tag == "{http://www.w3.org/2000/svg}g" : + print "\n{}# GROUP".format(" "*level) + tmp = getTransform(elem) + if tmp : + print "{}G{}".format(" "*level, printVertex(getTransform(elem))) + iterateDocument(elem, level + 1) + print "{}E\n".format(" "*level) + else : + iterateDocument(elem, level) + elif elem.tag == "{http://www.w3.org/2000/svg}path" : + printPath(elem, level) + + +# Ns. paaohjelma +if len(sys.argv) != 2 : + print "Usage: "+sys.argv[0]+" <input.svg>" + sys.exit(1) + +tree = ET.parse(sys.argv[1]) +iterateDocument(tree.getroot(), 0)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/view64.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,321 @@ +/* + * view64 - Display some C64 etc graphics formats via libSDL + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include "dmlib.h" +#include "dmargs.h" +#include "dmfile.h" +#include "lib64gfx.h" +#include <SDL.h> + + +char * optFilename = NULL; +int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; +int optScrWidth, optScrHeight; +int optForcedFormat = -1; + + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 2, 0, "fs", "Fullscreen", OPT_NONE }, + { 3, 'S', "scale", "Scale image by factor (1-10)", OPT_ARGREQ }, + { 4, 'f', "format", "Force input format (see list below)", OPT_ARGREQ }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void dmSetScaleFactor(float factor) +{ + optScrWidth = (int) ((float) C64_SCR_WIDTH * factor * C64_SCR_PAR_XY); + optScrHeight = (int) ((float) C64_SCR_HEIGHT * factor); +} + + +void argShowHelp() +{ + int i; + + dmPrintBanner(stdout, dmProgName, "[options] <input image file>"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf("\nAvailable bitmap formats:\n"); + for (i = 0; i < ndmC64ImageFormats; i++) + { + const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; + char buf[64]; + printf("%3d | %-5s | %-15s | %s\n", + i, fmt->fext, + dmC64GetImageTypeString(buf, sizeof(buf), fmt->type), + fmt->name); + } +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + dmVerbosity++; + break; + + case 2: + optVFlags |= SDL_FULLSCREEN; + break; + + case 3: + { + float factor; + if (sscanf(optArg, "%f", &factor) == 1) + { + if (factor < 1 || factor >= 10) + { + dmError("Invalid scale factor %1.0f, see help for valid values.\n", factor); + return FALSE; + } + + dmSetScaleFactor(factor); + } + else + { + dmError("Invalid scale factor '%s'.\n", optArg); + return FALSE; + } + } + break; + + case 4: + { + int i; + if (sscanf(optArg, "%d", &i) == 1) + { + if (i < 0 || i >= ndmC64ImageFormats) + { + dmError("Invalid image format index %d, see help for valid values.\n", i); + return FALSE; + } + optForcedFormat = i; + } + else + { + dmError("Invalid image format argument '%s'.\n", optArg); + return FALSE; + } + } + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *filename) +{ + if (optFilename == NULL) + { + optFilename = dm_strdup(filename); + return TRUE; + } + else + { + dmError("Too many filenames specified ('%s')\n", filename); + return FALSE; + } +} + + +BOOL dmInitializeVideo(SDL_Surface **screen) +{ + *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE); + if (*screen == NULL) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + return FALSE; + } + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen = NULL, *surf = NULL; + DMImage bmap; + BOOL initSDL = FALSE, exitFlag, needRedraw; + const DMC64ImageFormat *fmt = NULL, *forced; + DMC64Image image; + char *windowTitle; + Uint8 *dataBuf = NULL; + size_t dataSize; + int ret; + + dmSetScaleFactor(2.0); + + dmInitProg("view64", "Display some C64 bitmap graphics formats", "0.2", NULL, NULL); + + /* Parse arguments */ + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, FALSE)) + exit(1); + + + if (optFilename == NULL) + { + dmError("No input file specified, perhaps you need some --help\n"); + goto error; + } + + if ((ret = dmReadDataFile(NULL, optFilename, &dataBuf, &dataSize)) != DMERR_OK) + goto error; + + dmMsg(1, "Read %d bytes of input.\n", dataSize); + + // Probe for format + if (optForcedFormat >= 0) + { + forced = &dmC64ImageFormats[optForcedFormat]; + dmMsg(0,"Forced %s format image, type %d, %s\n", + forced->name, forced->type, forced->fext); + } + else + forced = NULL; + + ret = dmC64DecodeBMP(&image, dataBuf, dataSize, 0, 2, &fmt, forced); + if (forced == NULL && fmt != NULL) + { + dmMsg(0,"Probed %s format image, type %d, %s\n", + fmt->name, fmt->type, fmt->fext); + } + + if (ret < 0) + { + dmError("Probing could not find any matching image format (%d). Perhaps try forcing a format via -f\n", ret); + return -1; + } + + + // Initialize libSDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error; + } + initSDL = TRUE; + + + // Open window/set video mode + screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE); + if (screen == NULL) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + goto error; + } + + // Create surface (we are lazy and ugly) + surf = SDL_CreateRGBSurface(SDL_SWSURFACE, C64_SCR_WIDTH, C64_SCR_HEIGHT, 8, 0, 0, 0, 0); + SDL_SetColors(surf, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS); + SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS); + + // Convert bitmap (this is a bit ugly and lazy here) + bmap.data = surf->pixels; + bmap.pitch = surf->pitch; + bmap.width = surf->w; + bmap.height = surf->h; + bmap.constpal = TRUE; + + if (fmt->convertFrom != NULL) + ret = fmt->convertFrom(&bmap, &image, TRUE); + else + ret = dmC64ConvertGenericBMP2Image(&bmap, &image, TRUE); + + + // Set window title and caption + windowTitle = dm_strdup_printf("%s - %s", dmProgName, optFilename); + SDL_WM_SetCaption(windowTitle, dmProgName); + dmFree(windowTitle); + + + // Start main loop + needRedraw = TRUE; + exitFlag = FALSE; + while (!exitFlag) + { + SDL_Event event; + while (SDL_PollEvent(&event)) + switch (event.type) + { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: exitFlag = TRUE; break; + + default: + break; + } + + needRedraw = TRUE; + break; + + case SDL_VIDEORESIZE: + optScrWidth = event.resize.w; + optScrHeight = event.resize.h; + + if (!dmInitializeVideo(&screen)) + goto error; + + needRedraw = TRUE; + break; + + case SDL_VIDEOEXPOSE: + needRedraw = TRUE; + break; + + case SDL_QUIT: + exit(0); + } + + if (needRedraw) + { + if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) + { + dmError("Can't lock surface.\n"); + goto error; + } + + dmScaledBlitSurface8to8(surf, 0, 0, screen->w, screen->h, screen); + SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS); + + if (SDL_MUSTLOCK(screen) != 0) + SDL_UnlockSurface(screen); + + SDL_Flip(screen); + needRedraw = FALSE; + } + + SDL_Delay(100); + } + + +error: + if (screen) + SDL_FreeSurface(screen); + + if (initSDL) + SDL_Quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/viewmod.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,475 @@ +/* + * viewmod - View information about given module file + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2006-2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include "jss.h" +#include "jssmod.h" +#include <errno.h> +#include <string.h> +#include "dmargs.h" +#include "dmmutex.h" + + +char *optFilename = NULL; +BOOL optViewPatterns = FALSE, + optViewInstruments = FALSE, + optViewExtInstruments = FALSE, + optViewGeneralInfo = FALSE; + + +DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help and exit", OPT_NONE }, + { 1, 'p', "patterns", "View patterns", OPT_NONE }, + { 2, 'i', "instruments", "View instruments", OPT_NONE }, + { 5, 'e', "extinstruments", "View extended instruments", OPT_NONE }, + { 3, 'g', "general", "General information", OPT_NONE }, + { 4, 'v', "verbose", "Be more verbose", OPT_NONE }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, "[options] [modfile]"); + dmArgsPrintHelp(stdout, optList, optListN); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + (void) optArg; + + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + optViewPatterns = TRUE; + break; + + case 2: + optViewInstruments = TRUE; + break; + + case 3: + optViewGeneralInfo = TRUE; + break; + + case 4: + dmVerbosity++; + break; + + case 5: + optViewExtInstruments = TRUE; + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + // Was not option argument + if (!optFilename) + optFilename = currArg; + else { + dmError("Gay error '%s'!\n", currArg); + return FALSE; + } + + return TRUE; +} + + +const char patNoteTable[12][3] = +{ + "C-", "C#", "D-", + "D#", "E-", "F-", + "F#", "G-", "G#", + "A-", "A#", "B-" +}; + +#define jmpNMODEffectTable (36) +static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +/* Print a given pattern + */ +void printPattern(FILE *f, JSSPattern *p) +{ + int i, j; + char c; + JSSNote *n; + + if (!p) + return; + + n = p->data; + + for (i = 0; i < p->nrows; i++) + { + fprintf(f, "%.2x: ", i); + + for (j = 0; j < p->nchannels; j++) + { + switch (n->note) + { + case jsetNotSet: + fprintf(f, "... "); + break; + case jsetNoteOff: + fprintf(f, "=== "); + break; + default: + fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12); + break; + } + + if (n->instrument != jsetNotSet) + fprintf(f, "%.2x ", n->instrument + 1); // Because FT2 is 1-based and we use 0 internally + else + fprintf(f, ".. "); + + if (n->volume == jsetNotSet) + fprintf(f, ".. "); + else if (n->volume >= 0x00 && n->volume <= 0x40) + fprintf(f, "%.2x ", n->volume); + else + { + switch (n->volume & 0xf0) + { + case 0x50: c = '-'; break; + case 0x60: c = '+'; break; + case 0x70: c = '/'; break; + case 0x80: c = '\\'; break; + case 0x90: c = 'S'; break; + case 0xa0: c = 'V'; break; + case 0xb0: c = 'P'; break; + case 0xc0: c = '<'; break; + case 0xd0: c = '>'; break; + case 0xe0: c = 'M'; break; + default: c = '?'; break; + } + fprintf(f, "%c%x ", c, (n->volume & 0x0f)); + } + + if (n->effect >= 0 && n->effect < jmpNMODEffectTable) + fprintf(f, "%c", jmpMODEffectTable[n->effect]); + else if (n->effect == jsetNotSet) + fprintf(f, "."); + else + fprintf(f, "?"); + + if (n->param != jsetNotSet) + fprintf(f, "%.2x|", n->param); + else + fprintf(f, "..|"); + + n++; + } + + fprintf(f, "\n"); + } +} + + +/* + * Print given extended instrument + */ +void printEnvelope(FILE *f, JSSEnvelope *e, char *s) +{ + int i; + + fprintf(f, + "\t%s-envelope:\n" + "\t - flags.....: %.4x", s, e->flags); + + if (e->flags & jenvfUsed) + fprintf(f, " [used]"); + if (e->flags & jenvfSustain) + fprintf(f, " [sust]"); + if (e->flags & jenvfLooped) + fprintf(f, " [loop]"); + + fprintf(f, "\n" + "\t - npoints...: %i\n" + "\t - sustain...: %i\n" + "\t - loopS.....: %i\n" + "\t - loopE.....: %i\n", + e->npoints, e->sustain, e->loopS, e->loopE); + + if (dmVerbosity >= 2) + { + fprintf(f, "\t - Points....:"); + for (i = 0; i < e->npoints; i++) + { + fprintf(f, " [%i:%i]", + e->points[i].frame, e->points[i].value); + } + + fprintf(f, "\n"); + } +} + + +void printExtInstrument(FILE *f, JSSExtInstrument *i) +{ + if (!i) + { + fprintf(f, "\n"); + return; + } + +#ifndef JSS_LIGHT + if (i->desc) + fprintf(f, + "Description: '%s'\n", i->desc); +#endif + fprintf(f, + "nsamples.......: %i\n" + "vibratoType....: %i\n" + "vibratoSweep...: %i\n" + "vibratoDepth...: %i\n" + "vibratoRate....: %i\n" + "fadeOut........: %i\n", + i->nsamples, i->vibratoType, i->vibratoSweep, + i->vibratoDepth, i->vibratoRate, i->fadeOut); + + if (dmVerbosity >= 1) + { + printEnvelope(f, &i->volumeEnv, "Volume"); + printEnvelope(f, &i->panningEnv, "Panning"); + } + fprintf(f, "\n"); +} + + +void printInstrument(FILE *f, JSSInstrument *i) +{ + if (!i) + { + fprintf(f, "\n"); + return; + } + + if (dmVerbosity >= 1) + { +#ifndef JSS_LIGHT + if (i->desc) + fprintf(f, "Description: '%s'\n", i->desc); +#endif + fprintf(f, + "size...........: %ld (0x%lx)\n" + "loopStart......: %ld (0x%lx)\n" + "loopEnd........: %ld (0x%lx)\n" + "volume.........: %d (0x%x)\n" + "flags..........: 0x%x ", + (unsigned long) i->size, (unsigned long) i->size, + (unsigned long) i->loopS, (unsigned long) i->loopE, + (unsigned long) i->loopS, (unsigned long) i->loopE, + i->volume, i->volume, + i->flags); + + if (i->flags & jsfLooped) fprintf(f, "[loop] "); + if (i->flags & jsfBiDi) fprintf(f, "[bi-di] "); + if (i->flags & jsf16bit) fprintf(f, "[16bit] "); + + fprintf(f, + "\nC4BaseSpeed....: %d (0x%x)\n" + "ERelNote.......: %d (%s%d)\n" + "EFineTune......: %d\n" + "EPanning,,,....: %d (0x%x)\n\n", + i->C4BaseSpeed, i->C4BaseSpeed, + i->ERelNote, patNoteTable[(48 + i->ERelNote) % 12], (48 + i->ERelNote) / 12, + i->EFineTune, i->EPanning, i->EPanning); + } + else + { +#ifndef JSS_LIGHT + if (i->desc) + fprintf(f, "'%s', ", i->desc); +#endif + fprintf(f, + "s=%ld (%lx), l=%ld-%ld (%lx-%lx), v=%i (%x), f=0x%x, c4=%i (%x), rn=%i (%s%i), ft=%i, pn=%i (%x)\n", + (unsigned long) i->size, (unsigned long) i->size, + (unsigned long) i->loopS, (unsigned long) i->loopE, + (unsigned long) i->loopS, (unsigned long) i->loopE, + i->volume, i->volume, i->flags, i->C4BaseSpeed, + i->C4BaseSpeed, i->ERelNote, + patNoteTable[(48 + i->ERelNote) % 12], + (48 + i->ERelNote) / 12, i->EFineTune, + i->EPanning, i->EPanning); + } +} + + +void printGeneralInfo(FILE *f, JSSModule *m) +{ + int i; + + if (!m) + return; + + fprintf(f, "Module type.....: %i\n", m->moduleType); +#ifndef JSS_LIGHT + if (m->moduleName) + fprintf(f, "Module name.....: '%s'\n", m->moduleName); + if (m->trackerName) + fprintf(f, "Tracker name....: '%s'\n", m->trackerName); +#endif + fprintf(f, + "Speed...........: %d ticks\n" + "Tempo...........: %d bpm\n" + "Flags...........: %x ", + m->defSpeed, m->defTempo, m->defFlags); + + if (m->defFlags & jmdfAmigaPeriods) fprintf(f, "[Amiga periods] "); + if (m->defFlags & jmdfAmigaLimits) fprintf(f, "[Amiga limits] "); + if (m->defFlags & jmdfStereo) fprintf(f, "[stereo] "); + if (m->defFlags & jmdfFT2Replay) fprintf(f, "[FT2 replay] "); + if (m->defFlags & jmdfST300Slides) fprintf(f, "[ST300 slides] "); + if (m->defFlags & jmdfByteLStart) fprintf(f, "[ByteStart] "); + + fprintf(f, "\n" + "Restart pos.....: %d (order)\n" + "IntVersion......: %x\n" + "Channels........: %d\n" + "Instruments.....: %d\n" + "Ext.instruments.: %d\n" + "Patterns........: %d\n" + "Orders..........: %d\n", + m->defRestartPos, m->intVersion, m->nchannels, + m->ninstruments, m->nextInstruments, m->npatterns, + m->norders); + + if (dmVerbosity >= 1) + { + fprintf(f, "Orderlist: "); + for (i = 0; i < m->norders - 1; i++) + fprintf(f, "%d, ", m->orderList[i]); + if (i < m->norders) + fprintf(f, "%d", m->orderList[i]); + fprintf(f, "\n"); + } +} + + + +int main(int argc, char *argv[]) +{ + int result = -1, i; + DMResource *file; + JSSModule *mod; + + dmInitProg("viewmod", "miniJSS Module Viewer", "0.4", NULL, NULL); + dmVerbosity = 0; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Initialize miniJSS + jssInit(); + + // Open the file + dmMsg(1, "Reading module file '%s'\n", optFilename); + if (optFilename == NULL) + file = dmf_create_stdio_stream(stdin); + else if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) + { + dmError("Error opening input file '%s'. (%s)\n", + optFilename, strerror(errno)); + return 1; + } + + // Read module file + dmMsg(1, "Reading file: %s\n", optFilename); +#ifdef JSS_SUP_XM + dmMsg(1, "* Trying XM...\n"); + result = jssLoadXM(file, &mod); +#endif +#ifdef JSS_SUP_JSSMOD + if (result != 0) + { + size_t bufgot, bufsize = dmfsize(file); + Uint8 *buf = dmMalloc(bufsize); + dmfseek(file, 0L, SEEK_SET); + dmMsg(1, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); + if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) + { + dmError("Error reading file (not enough data %d), #%d: %s\n", + bufgot, dmferror(file), dmErrorStr(dmferror(file))); + return 2; + } + result = jssLoadJSSMOD(buf, bufsize, &mod); + dmFree(buf); + } +#endif + dmf_close(file); + if (result != DMERR_OK) + { + dmError("Error loading module file, %d: %s\n", + result, dmErrorStr(result)); + return 3; + } + + // Print out information + if (optViewGeneralInfo) + printGeneralInfo(stdout, mod); + + if (optViewPatterns) + { + for (i = 0; i < mod->npatterns; i++) + { + printf("\nPattern #%03i:\n", i); + printPattern(stdout, mod->patterns[i]); + } + } + + if (optViewExtInstruments) + { + printf("\n" + "ExtInstruments:\n" + "---------------\n" + ); + for (i = 0; i < mod->nextInstruments; i++) + { + printf("#%03i: ", i + 1); + printExtInstrument(stdout, mod->extInstruments[i]); + } + } + + if (optViewInstruments) + { + printf("\n" + "Instruments:\n" + "------------\n" + ); + for (i = 0; i < mod->ninstruments; i++) + { + printf("#%03i: ", i + 1); + printInstrument(stdout, mod->instruments[i]); + } + } + + // Free module data + jssFreeModule(mod); + jssClose(); + + exit(0); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/xm2jss.c Tue Apr 16 06:04:22 2013 +0300 @@ -0,0 +1,1040 @@ +/* + * xm2jss - Convert XM module to JSSMOD + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2006-2009 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <stdio.h> +#include <errno.h> +#include "jss.h" +#include "jssmod.h" +#include "jssplr.h" +#include "dmlib.h" +#include "dmargs.h" +#include "dmres.h" +#include "dmmutex.h" + + +#define jmpNMODEffectTable (36) +static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +char *optInFilename = NULL, *optOutFilename = NULL; +BOOL optIgnoreErrors = FALSE, + optStripExtInstr = FALSE, + optStripInstr = FALSE, + optStripSamples = FALSE, + optOptimize = FALSE; + +int optPatternMode = PATMODE_COMP_HORIZ, + optSampMode16 = jsampDelta, + optSampMode8 = jsampFlipSign | jsampDelta; + +#define SAMPMODE_MASK (jsampFlipSign | jsampSwapEndianess | jsampSplit | jsampDelta) + + +static const char* patModeTable[PATMODE_LAST] = +{ + "Raw horizontal", + "Compressed horizontal (similar to XM modules)", + "Raw vertical", + "Compressed vertical", + "Raw vertical for each element", +}; + + +DMOptArg optList[] = { + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 2, 'i', "ignore", "Ignore errors", OPT_NONE }, + { 3, 'p', "patterns", "Pattern storage mode", OPT_ARGREQ }, + { 4, 'E', "strip-ext-instr","Strip ext. instruments (implies -I -S)", OPT_NONE }, + { 5, 'I', "strip-instr", "Strip instruments (implies -S)", OPT_NONE }, + { 6, 'S', "strip-samples", "Strip instr. sampledata", OPT_NONE }, + { 7, '8', "smode8", "8-bit sample conversion flags", OPT_ARGREQ }, + { 8, '1', "smode16", "16-bit sample conversion flags", OPT_ARGREQ }, + { 9, 'O', "optimize", "Optimize module", OPT_NONE }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + int i; + + dmPrintBanner(stdout, dmProgName, "[options] <input.xm> <output.jmod>"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf("\n" + "Pattern storage modes:\n"); + + for (i = 1; i < PATMODE_LAST; i++) + printf(" %d = %s\n", i, patModeTable[i-1]); + + printf( + "\n" + "Sample data conversion flags (summative):\n" + " 1 = Delta encoding (DEF 8 & 16)\n" + " 2 = Flip signedness (DEF 8)\n" + " 4 = Swap endianess (affects 16-bit only)\n" + " 8 = Split and de-interleave hi/lo bytes (affects 16-bit only)\n" + "\n" + ); +} + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + (void) optArg; + + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + dmVerbosity++; + break; + + case 2: + optIgnoreErrors = TRUE; + break; + + case 3: + optPatternMode = atoi(optArg); + if (optPatternMode <= 0 || optPatternMode >= PATMODE_LAST) + { + dmError("Unknown pattern conversion mode %d\n", optPatternMode); + return FALSE; + } + break; + + case 4: optStripExtInstr = TRUE; break; + case 5: optStripInstr = TRUE; break; + case 6: optStripSamples = TRUE; break; + + case 7: optSampMode8 = atoi(optArg) & SAMPMODE_MASK; break; + case 8: optSampMode16 = atoi(optArg) & SAMPMODE_MASK; break; + + case 9: optOptimize = TRUE; break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + // Was not option argument + if (!optInFilename) + optInFilename = currArg; + else + if (!optOutFilename) + optOutFilename = currArg; + else + { + dmError("Too many filename arguments specified, '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +/* These functions and the macro mess are meant to make the + * conversion routines themselves clearer and simpler. + */ +BOOL jsPutByte(Uint8 *patBuf, size_t patBufSize, size_t *npatBuf, Uint8 val) +{ + if (*npatBuf >= patBufSize) + return FALSE; + else + { + patBuf[*npatBuf] = val; + (*npatBuf)++; + return TRUE; + } +} + +#define JSPUTBYTE(x) do { if (!jsPutByte(patBuf, patBufSize, patSize, x)) return DMERR_BOUNDS; } while (0) + +#define JSCOMP(x,z) do { if ((x) != jsetNotSet) { qflags |= (z); qcomp++; } } while (0) + +#define JSCOMPPUT(xf,xv,qv) do { \ + if (qflags & (xf)) { \ + if ((xv) < 0 || (xv) > 255) \ + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ + "%s value out of bounds %d.\n", qv, (xv)); \ + JSPUTBYTE(xv); \ + } \ +} while (0) + +#define JSCONVPUT(xv,qv) do { \ + if ((xv) != jsetNotSet) { \ + if ((xv) < 0 || (xv) > 254) \ + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ + "%s value out of bounds %d.\n", qv, (xv)); \ + JSPUTBYTE((xv) + 1); \ + } else { \ + JSPUTBYTE(0); \ + } \ +} while (0) + + +/* Convert a note + */ +static int jssConvertNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) +{ + Uint8 tmp; + if (note->note == jsetNotSet) + tmp = 0; + else if (note->note == jsetNoteOff) + tmp = 127; + else + tmp = note->note + 1; + + if (tmp > 0x7f) + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); + + JSPUTBYTE(tmp & 0x7f); + + JSCONVPUT(note->instrument, "Instrument"); + JSCONVPUT(note->volume, "Volume"); + JSCONVPUT(note->effect, "Effect"); + + tmp = (note->param != jsetNotSet) ? note->param : 0; + JSPUTBYTE(tmp); + + return DMERR_OK; +} + + +/* Compress a note + */ +static int jssCompressNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) +{ + Uint8 qflags = 0; + int qcomp = 0; + + JSCOMP(note->note, COMP_NOTE); + JSCOMP(note->instrument, COMP_INSTRUMENT); + JSCOMP(note->volume, COMP_VOLUME); + JSCOMP(note->effect, COMP_EFFECT); + if (note->param != jsetNotSet && note->param != 0) + { + qflags |= COMP_PARAM; + qcomp++; + } + + if (qcomp < 4) + { + JSPUTBYTE(qflags | 0x80); + + if (note->note != jsetNotSet) + { + Uint8 tmp = (note->note != jsetNoteOff) ? note->note : 127; + if (tmp > 0x7f) + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); + JSPUTBYTE(tmp); + } + + JSCOMPPUT(COMP_INSTRUMENT, note->instrument, "Instrument"); + JSCOMPPUT(COMP_VOLUME, note->volume, "Volume"); + JSCOMPPUT(COMP_EFFECT, note->effect, "Effect"); + JSCOMPPUT(COMP_PARAM, note->param, "Param"); + } else + return jssConvertNote(patBuf, patBufSize, patSize, note); + + return DMERR_OK; +} + + +/* Compress pattern + */ +static int jssConvertPatternCompHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + int row, channel; + *patSize = 0; + + for (row = 0; row < pattern->nrows; row++) + for (channel = 0; channel < pattern->nchannels; channel++) + { + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + const int res = jssCompressNote(patBuf, patBufSize, patSize, note); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + + return DMERR_OK; +} + + +static int jssConvertPatternCompVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + int row, channel; + *patSize = 0; + + for (channel = 0; channel < pattern->nchannels; channel++) + for (row = 0; row < pattern->nrows; row++) + { + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + const int res = jssCompressNote(patBuf, patBufSize, patSize, note); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + + return DMERR_OK; +} + + +/* Convert a pattern + */ +static int jssConvertPatternRawHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + int row, channel; + *patSize = 0; + + for (row = 0; row < pattern->nrows; row++) + for (channel = 0; channel < pattern->nchannels; channel++) + { + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + const int res = jssConvertNote(patBuf, patBufSize, patSize, note); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + + return DMERR_OK; +} + + +static int jssConvertPatternRawVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + int row, channel; + *patSize = 0; + + for (channel = 0; channel < pattern->nchannels; channel++) + for (row = 0; row < pattern->nrows; row++) + { + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + const int res = jssConvertNote(patBuf, patBufSize, patSize, note); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + + return DMERR_OK; +} + + +#define JSFOREACHNOTE1 \ + for (channel = 0; channel < pattern->nchannels; channel++) \ + for (row = 0; row < pattern->nrows; row++) { \ + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + +#define JSFOREACHNOTE2 } + +static int jssConvertPatternRawElem(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + Uint8 tmp; + int row, channel; + *patSize = 0; + + JSFOREACHNOTE1; + if (note->note == jsetNotSet) + tmp = 0; + else if (note->note == jsetNoteOff) + tmp = 127; + else + tmp = note->note + 1; + if (tmp > 0x7f) + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); + JSPUTBYTE(tmp); + JSFOREACHNOTE2; + + JSFOREACHNOTE1; + JSCONVPUT(note->instrument, "Instrument"); + JSFOREACHNOTE2; + + JSFOREACHNOTE1; + JSCONVPUT(note->volume, "Volume"); + JSFOREACHNOTE2; + + JSFOREACHNOTE1; + JSCONVPUT(note->effect, "Effect"); + JSFOREACHNOTE2; + + JSFOREACHNOTE1; + tmp = (note->param != jsetNotSet) ? note->param : 0; + JSPUTBYTE(tmp); + JSFOREACHNOTE2; + + return DMERR_OK; +} + +#undef JSFOREACHNOTE1 +#undef JSFOREACHNOTE2 + + +static void jssCopyEnvelope(JSSMODEnvelope *je, JSSEnvelope *e) +{ + int i; + + je->flags = e->flags; + je->npoints = e->npoints; + je->sustain = e->sustain; + je->loopS = e->loopS; + je->loopE = e->loopE; + + for (i = 0; i < e->npoints; i++) + { + je->points[i].frame = e->points[i].frame; + je->points[i].value = e->points[i].value; + } +} + + +/* Save a JSSMOD file + */ +int jssSaveJSSMOD(FILE *outFile, JSSModule *m, int patMode, int flags8, int flags16) +{ + JSSMODHeader jssH; + int i, pattern, order, instr, totalSize; + const size_t patBufSize = 64*1024; // 64kB pattern buffer + Uint8 *patBuf; + + // Check the module + if (m == NULL) + JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, "Module pointer was NULL\n"); + + if ((m->nchannels < 1) || (m->npatterns < 1) || (m->norders < 1)) + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, + "Module had invalid values (nchannels=%i, npatterns=%i, norders=%i)\n", + m->nchannels, m->npatterns, m->norders); + + // Create the JSSMOD header + jssH.idMagic[0] = 'J'; + jssH.idMagic[1] = 'M'; + jssH.idVersion = JSSMOD_VERSION; + jssH.norders = m->norders; + jssH.npatterns = m->npatterns; + jssH.nchannels = m->nchannels; + jssH.nextInstruments = m->nextInstruments; + jssH.ninstruments = m->ninstruments; + jssH.defFlags = m->defFlags; + jssH.intVersion = m->intVersion; + jssH.defRestartPos = m->defRestartPos; + jssH.defSpeed = m->defSpeed; + jssH.defTempo = m->defTempo; + jssH.patMode = patMode; + + // Write header + totalSize = sizeof(jssH); + if (fwrite(&jssH, sizeof(jssH), 1, outFile) != 1) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD header!\n"); + + dmMsg(1," * JSSMOD-header 0x%04x, %d bytes.\n", JSSMOD_VERSION, totalSize); + + // Write orders list + for (totalSize = order = 0; order < m->norders; order++) + { + Uint16 tmp = m->orderList[order]; + totalSize += sizeof(tmp); + if (fwrite(&tmp, sizeof(tmp), 1, outFile) != 1) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD orders list.\n"); + } + + dmMsg(1," * %d item orders list, %d bytes.\n", + m->norders, totalSize); + + // Allocate pattern compression buffer + if ((patBuf = dmMalloc(patBufSize)) == NULL) + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Error allocating memory for pattern compression buffer.\n"); + + + // Write patterns + for (totalSize = pattern = 0; pattern < m->npatterns; pattern++) + { + JSSMODPattern patHead; + size_t finalSize = 0; + + switch (patMode) + { + case PATMODE_RAW_HORIZ: + i = jssConvertPatternRawHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + case PATMODE_COMP_HORIZ: + i = jssConvertPatternCompHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + case PATMODE_RAW_VERT: + i = jssConvertPatternRawVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + case PATMODE_COMP_VERT: + i = jssConvertPatternCompVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + case PATMODE_RAW_ELEM: + i = jssConvertPatternRawElem(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + default: + i = DMERR_INVALID_DATA; + dmFree(patBuf); + JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Unsupported pattern conversion mode %d.\n", patMode); + break; + } + + if (i != DMERR_OK) + { + dmFree(patBuf); + JSSERROR(i, i, "Error converting pattern data #%i\n", pattern); + } + else + { + dmMsg(3, " - Pattern %d size %d bytes\n", pattern, finalSize); + patHead.nrows = m->patterns[pattern]->nrows; + patHead.size = finalSize; + totalSize += finalSize + sizeof(patHead); + + if (fwrite(&patHead, sizeof(patHead), 1, outFile) != 1) + { + dmFree(patBuf); + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Error writing pattern #%d header\n", pattern); + } + + if (fwrite(patBuf, sizeof(Uint8), finalSize, outFile) != finalSize) + { + dmFree(patBuf); + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Error writing pattern #%d data\n", pattern); + } + } + } + dmFree(patBuf); + dmMsg(1," * %d patterns, %d bytes.\n", m->npatterns, totalSize); + + // Write extended instruments + for (totalSize = instr = 0; instr < m->nextInstruments; instr++) + { + JSSMODExtInstrument jssE; + JSSExtInstrument *einst = m->extInstruments[instr]; + + memset(&jssE, 0, sizeof(jssE)); + + if (einst) + { + // Create header + jssE.nsamples = einst->nsamples; + for (i = 0; i < jsetNNotes; i++) + { + int snum = einst->sNumForNotes[i]; + jssE.sNumForNotes[i] = (snum != jsetNotSet) ? snum : 0; + } + + jssCopyEnvelope(&jssE.volumeEnv, &(einst->volumeEnv)); + jssCopyEnvelope(&jssE.panningEnv, &(einst->panningEnv)); + jssE.vibratoType = einst->vibratoType; + jssE.vibratoSweep = einst->vibratoSweep; + jssE.vibratoDepth = einst->vibratoDepth; + jssE.fadeOut = einst->fadeOut; + } else + JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Extended instrument #%i NULL!\n", instr); + + // Write to file + totalSize += sizeof(jssE); + if (fwrite(&jssE, sizeof(jssE), 1, outFile) != 1) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Could not write JSSMOD extended instrument #%i to file!\n", instr); + } + dmMsg(1," * %d Extended Instruments, %d bytes.\n", m->nextInstruments, totalSize); + + + // Write sample instrument headers + for (totalSize = instr = 0; instr < m->ninstruments; instr++) + { + JSSMODInstrument jssI; + JSSInstrument *pInst = m->instruments[instr]; + + memset(&jssI, 0, sizeof(jssI)); + + // Create header + if (pInst) + { + jssI.size = pInst->size; + jssI.loopS = pInst->loopS; + jssI.loopE = pInst->loopE; + jssI.volume = pInst->volume; + jssI.flags = pInst->flags; + jssI.C4BaseSpeed = pInst->C4BaseSpeed; + jssI.ERelNote = pInst->ERelNote; + jssI.EFineTune = pInst->EFineTune; + jssI.EPanning = pInst->EPanning; + jssI.hasData = (pInst->data != NULL) ? TRUE : FALSE; + jssI.convFlags = (pInst->flags & jsf16bit) ? flags16 : flags8; + } + else + JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Instrument #%i NULL!\n", instr); + + // Write to file + totalSize += sizeof(jssI); + if (fwrite(&jssI, sizeof(jssI), 1, outFile) != 1) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Could not write JSSMOD instrument #%i to file!\n", instr); + } + dmMsg(1," * %d Instrument headers, %d bytes.\n", m->ninstruments, totalSize); + + // Write sample data + for (totalSize = instr = 0; instr < m->ninstruments; instr++) + if (m->instruments[instr]) + { + JSSInstrument *inst = m->instruments[instr]; + if (inst->data != NULL) + { + size_t res; + if (inst->flags & jsf16bit) + { + jssEncodeSample16(inst->data, inst->size, flags16); + res = fwrite(inst->data, sizeof(Uint16), inst->size, outFile); + } + else + { + jssEncodeSample8(inst->data, inst->size, flags8); + res = fwrite(inst->data, sizeof(Uint8), inst->size, outFile); + } + + totalSize += inst->size; + if (res != (size_t) inst->size) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Could not write JSSMOD sample #%i to file!\n", instr); + } + } + dmMsg(1," * %d samples, %d bytes.\n", m->ninstruments, totalSize); + + return DMERR_OK; +} + + +/* Optimize a given module + */ +JSSModule *optimizeModule(JSSModule *m) +{ + BOOL usedPatterns[jsetMaxPatterns + 1], + usedInstruments[jsetMaxInstruments + 1], + usedExtInstruments[jsetMaxInstruments + 1]; + int mapExtInstruments[jsetMaxInstruments + 1], + mapInstruments[jsetMaxInstruments + 1], + mapPatterns[jsetMaxPatterns + 1]; + JSSModule *r = NULL; + int i, n8, n16; + + // Allocate a new module + if ((r = jssAllocateModule()) == NULL) + return NULL; + + // Allocate tables + + // Copy things + r->moduleType = m->moduleType; + r->moduleName = dm_strdup(m->moduleName); + r->trackerName = dm_strdup(m->trackerName); + r->defSpeed = m->defSpeed; + r->defTempo = m->defTempo; + r->defFlags = m->defFlags; + r->defRestartPos = m->defRestartPos; + r->intVersion = m->intVersion; + r->nchannels = m->nchannels; + r->norders = m->norders; + for (i = 0; i < jsetNChannels; i++) + r->defPanning[i] = m->defPanning[i]; + + // Initialize values + for (i = 0; i <= jsetMaxInstruments; i++) + { + usedExtInstruments[i] = FALSE; + usedInstruments[i] = FALSE; + mapExtInstruments[i] = jsetNotSet; + mapInstruments[i] = jsetNotSet; + } + + for (i = 0; i <= jsetMaxPatterns; i++) + { + usedPatterns[i] = FALSE; + mapPatterns[i] = jsetNotSet; + } + + // Find out all used patterns and ext.instruments + for (i = 0; i < m->norders; i++) + { + int pattern = m->orderList[i]; + if (pattern >= 0 && pattern < m->npatterns) + { + JSSPattern *p = m->patterns[pattern]; + if (p != NULL) + { + int row, channel; + JSSNote *n = p->data; + + // Mark pattern as used + usedPatterns[pattern] = TRUE; + + // Check all notes + for (row = 0; row < p->nrows; row++) + for (channel = 0; channel < p->nchannels; channel++, n++) + { + if (n->instrument != jsetNotSet) + { + if (optStripExtInstr || (n->instrument >= 0 && n->instrument < m->nextInstruments)) + usedExtInstruments[n->instrument] = TRUE; + else + dmMsg(2, "Pattern 0x%x, row=0x%x, chn=%d has invalid instrument 0x%x\n", + pattern, row, channel, n->instrument); + } + } + } + else + { + dmError("Pattern 0x%x is used on order 0x%x, but has no data!\n", + pattern, i); + } + } + else + if (pattern != jsetMaxPatterns) + { + dmError("Order 0x%x has invalid pattern number 0x%x!\n", + i, pattern); + } + } + + // Find out used instruments + for (i = 0; i <= jsetMaxInstruments; i++) + if (usedExtInstruments[i] && m->extInstruments[i] != NULL) + { + int note; + JSSExtInstrument *e = m->extInstruments[i]; + + for (note = 0; note < jsetNNotes; note++) + if (e->sNumForNotes[note] != jsetNotSet) + { + int q = e->sNumForNotes[note]; + if (q >= 0 && q < m->ninstruments) + { + usedInstruments[q] = TRUE; + } + else + { + dmError("Ext.instrument #%d sNumForNotes[%d] value out range (%d < %d).\n", + i, m->ninstruments, q); + } + } + } + + // Create pattern mappings + r->npatterns = 0; + dmMsg(1, "Unused patterns: "); + + for (i = 0; i <= jsetMaxPatterns; i++) + if (m->patterns[i] != NULL) + { + if (!usedPatterns[i]) + { + dmPrint(2, "0x%x, ", i); + } + else + { + if (i >= m->npatterns) + dmError("Pattern 0x%x >= 0x%x, but used!\n", i, m->npatterns); + + mapPatterns[i] = r->npatterns; + r->patterns[r->npatterns] = m->patterns[i]; + (r->npatterns)++; + } + } + dmPrint(2, "\n"); + + dmMsg(1, "%d used patterns, %d unused.\n", + r->npatterns, m->npatterns - r->npatterns); + + + // Re-map instruments + dmMsg(1, "Unused instruments: "); + for (n8 = n16 = i = 0; i <= jsetMaxInstruments; i++) + if (m->instruments[i] != NULL) + { + if (!usedInstruments[i] && !optStripInstr) + { + dmPrint(2, "0x%x, ", i); + } + else + { + JSSInstrument *ip = m->instruments[i]; + if (i >= m->ninstruments) + dmError("Instrument 0x%x >= 0x%x, but used!\n", i, m->ninstruments); + + mapInstruments[i] = r->ninstruments; + r->instruments[r->ninstruments] = ip; + (r->ninstruments)++; + + if (ip->flags & jsf16bit) + n16++; + else + n8++; + } + } + dmPrint(2, "\n"); + dmMsg(1, "Total of (%d) 16-bit, (%d) 8-bit samples, (%d) instruments.\n", + n16, n8, r->ninstruments); + + // Re-map ext.instruments + dmMsg(1, "Unused ext.instruments: "); + for (i = 0; i < jsetMaxInstruments; i++) + if (usedExtInstruments[i]) + { + if (i >= m->nextInstruments && !optStripExtInstr) + { + dmError("Ext.instrument 0x%x >= 0x%x, but used!\n", + i, m->nextInstruments); + } + else + if (m->extInstruments[i] != NULL) + { + JSSExtInstrument *e = m->extInstruments[i]; + int note; + + mapExtInstruments[i] = r->nextInstruments; + r->extInstruments[r->nextInstruments] = e; + (r->nextInstruments)++; + + // Re-map sNumForNotes + for (note = 0; note < jsetNNotes; note++) + { + int q = e->sNumForNotes[note]; + if (q != jsetNotSet) + { + int map; + if (q >= 0 && q <= jsetMaxInstruments) + { + map = mapInstruments[q]; + } + else + { + map = jsetNotSet; + dmError("e=%d, note=%d, q=%d/%d\n", i, note, q, r->ninstruments); + } + e->sNumForNotes[note] = map; + } + } + } + else + { + dmPrint(2, "[0x%x==NULL], ", i); + mapExtInstruments[i] = jsetNotSet; + } + } + else + { + if (i < m->nextInstruments && m->extInstruments[i] != NULL) + { + dmPrint(2, "0x%x, ", i); + } + } + dmPrint(2, "\n"); + dmMsg(1, "%d extended instruments.\n", r->nextInstruments); + + + // Remap pattern instrument data + for (i = 0; i < r->npatterns; i++) + { + int row, channel; + JSSPattern *p = r->patterns[i]; + JSSNote *n = p->data; + + for (row = 0; row < p->nrows; row++) + for (channel = 0; channel < p->nchannels; channel++, n++) + { + char effect; + + if (!optStripExtInstr) + { + if (n->instrument >= 0 && n->instrument <= jsetMaxInstruments) + n->instrument = mapExtInstruments[n->instrument]; + + if (n->instrument != jsetNotSet && r->extInstruments[n->instrument] == NULL) + dmError("Non-existing instrument used #%d.\n", n->instrument); + } + + JMPGETEFFECT(effect, n->effect); + + switch (effect) + { + case 'C': // Cxx = Set volume + if (n->volume == jsetNotSet) + { + n->volume = n->param; + n->effect = jsetNotSet; + n->param = jsetNotSet; + } + break; + } + } + } + + // Remap orders list + for (i = 0; i < m->norders; i++) + { + r->orderList[i] = mapPatterns[m->orderList[i]]; + } + + return r; +} + + +int main(int argc, char *argv[]) +{ + DMResource *sfile = NULL; + FILE *dfile = NULL; + JSSModule *sm, *dm; + int result; + + dmInitProg("xm2jss", "XM to JSSMOD converter", "0.6", NULL, NULL); + dmVerbosity = 0; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Check arguments + if (optInFilename == NULL || optOutFilename == NULL) + { + dmError("Input or output file not specified. Try --help.\n"); + return 1; + } + + // Read the source file + if ((sfile = dmf_create_stdio(optInFilename, "rb")) == NULL) + { + dmError("Error opening input file '%s', %d: %s\n", + optInFilename, errno, strerror(errno)); + return 1; + } + + // Initialize miniJSS + jssInit(); + + // Read file + dmMsg(1, "Reading XM-format file ...\n"); + result = jssLoadXM(sfile, &sm); + dmf_close(sfile); + if (result != 0) + { + dmError("Error while loading XM file (%i), ", result); + if (optIgnoreErrors) + fprintf(stderr, "ignoring. This may cause problems.\n"); + else + { + fprintf(stderr, "giving up. Use --ignore if you want to try to convert anyway.\n"); + return 2; + } + } + + // Check stripping settings + if (optStripExtInstr) optStripInstr = TRUE; + if (optStripInstr) optStripSamples = TRUE; + + // Remove samples + if (optStripSamples) + { + int i; + + dmMsg(1, "Stripping samples...\n"); + for (i = 0; i < sm->ninstruments; i++) + { + dmFree(sm->instruments[i]->data); + sm->instruments[i]->data = NULL; + } + } + + // Remove instruments + if (optStripInstr) + { + int i; + + dmMsg(1, "Stripping instruments...\n"); + for (i = 0; i < sm->ninstruments; i++) + { + dmFree(sm->instruments[i]); + sm->instruments[i] = NULL; + } + sm->ninstruments = 0; + } + + // Remove ext.instruments + if (optStripExtInstr) + { + int i; + + dmMsg(1, "Stripping ext.instruments...\n"); + for (i = 0; i < sm->nextInstruments; i++) + { + dmFree(sm->extInstruments[i]); + sm->extInstruments[i] = NULL; + } + sm->nextInstruments = 0; + } + // Run the optimization procedure + if (optOptimize) + { + dmMsg(1, "Optimizing module data...\n"); + dm = optimizeModule(sm); + } else + dm = sm; + + // Write output file + if ((dfile = fopen(optOutFilename, "wb")) == NULL) + { + dmError("Error creating output file '%s', %d: %s\n", + optOutFilename, errno, strerror(errno)); + return 1; + } + + dmMsg(1, "Writing JSSMOD-format file [patMode=0x%04x, samp8=0x%02x, samp16=0x%02x]\n", + optPatternMode, optSampMode8, optSampMode16); + + result = jssSaveJSSMOD(dfile, dm, optPatternMode, optSampMode8, optSampMode16); + + fclose(dfile); + + if (result != 0) + { + dmError("Error while saving JSSMOD file, %d: %s\n", + result, dmErrorStr(result)); + dmError("WARNING: The resulting file may be broken!\n"); + } + else + { + dmMsg(1, "Conversion complete.\n"); + } + return 0; +}
--- a/utils/data2inc.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,404 +0,0 @@ -/* - * data2inc - Convert binary data to "C"-source or XA-compatible include file - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2003,2009-2012 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <errno.h> -#include "dmlib.h" -#include "dmargs.h" -#include "dmmutex.h" - -#define RA_LINEBUF (16) - -enum -{ - FMT_AUTO = 0, - FMT_C, - FMT_ASM -}; - -char *optInFilename = NULL, - *optOutFilename = NULL, - *optObjName = "default_object", - *optDataType = NULL, - *optAddLine = NULL; - -int optIndentation = -1; -int optFormat = FMT_AUTO; -BOOL optHexMode = FALSE, - optQuiet = FALSE, - optExtraData = FALSE, - optFormatting = TRUE; - - -void (*writeHeader) (FILE *, char *) = NULL; -void (*writeDecl) (FILE *, size_t, char *) = NULL; -void (*writeData) (FILE *, Uint8 *, size_t) = NULL; -void (*writeFooter) (FILE *, size_t, char *) = NULL; - - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 4, 'A', "format-asm", "Output in XA-compatible asm", OPT_NONE }, - { 5, 'C', "format-c", "Output in ANSI C", OPT_NONE }, - { 1, 'n', "name", "Set object name", OPT_ARGREQ }, - { 2, 't', "type", "Set datatype (unsigned char/byte)", OPT_ARGREQ }, - { 3, 'a', "add-line", "Add this line to start of file", OPT_ARGREQ }, - { 6, 'x', "hexadecimal", "Use hexadecimal output", OPT_NONE }, - { 7, 'q', "quiet", "Do not add comments", OPT_NONE }, - { 8, 'f', "no-formatting", "Disable additional output formatting", OPT_NONE }, - { 9, 'i', "indentation", "Set indentation (negative value = tab)", OPT_ARGREQ }, - { 10, 'e', "extra-data", "Add object end labels and size in asm output", OPT_NONE }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, - "[options] [sourcefile] [destfile]"); - - dmArgsPrintHelp(stdout, optList, optListN); - - printf( - "\n" - "To convert a data file to a C structure using 'Uint8' as type:\n" - "$ data2inc -C -n variable_name -t Uint8 input.bin output.h\n" - "\n" - ); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - optObjName = optArg; - break; - - case 2: - optDataType = optArg; - break; - - case 3: - optAddLine = optArg; - break; - - case 4: - optFormat = FMT_ASM; - break; - case 5: - optFormat = FMT_C; - break; - case 6: - optHexMode = TRUE; - break; - case 7: - optQuiet = TRUE; - break; - case 8: - optFormatting = FALSE; - break; - - case 9: - optIndentation = atoi(optArg); - break; - - case 10: - optExtraData = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char * currArg) -{ - if (!optInFilename) - optInFilename = currArg; - else - if (!optOutFilename) - optOutFilename = currArg; - else - dmError("Source and destination filenames already specified, extraneous argument '%s'.\n", currArg); - - return TRUE; -} - - -/* Assembler include data output functions - */ -void writeHeader_ASM(FILE * f, char *name) -{ - if (name) - fprintf(f, "; '%s'", name); - else - fprintf(f, "; Generated"); - fprintf(f, " by %s v%s\n", - dmProgName, dmProgVersion); -} - -void writeDecl_ASM(FILE * f, size_t len, char *name) -{ - if (optExtraData) - fprintf(f, "%s_size = %u\n", name, len); - fprintf(f, "%s:\n", name); -} - -void writeData_ASM(FILE * f, Uint8 * buf, size_t len) -{ - size_t i; - - fprintf(f, "%s ", optDataType); - for (i = 0; i < len; i++) - { - if (optFormatting) - { - if (optHexMode) - fprintf(f, "$%.2x", buf[i]); - else - fprintf(f, "%3d", buf[i]); - } - else - { - if (optHexMode) - fprintf(f, "$%x", buf[i]); - else - fprintf(f, "%d", buf[i]); - } - - if (i < (len - 1)) - fprintf(f, ","); - } -} - -void writeFooter_ASM(FILE * f, size_t len, char *name) -{ - (void) len; - if (optExtraData) - fprintf(f, "%s_end: \n", name); - else - fprintf(f, "\n"); -} - - -/* ANSI-C include data output functions - */ -void writeHeader_C(FILE * f, char *name) -{ - if (name) - fprintf(f, "/* '%s' generated", name); - else - fprintf(f, "/* Generated"); - - fprintf(f, " by %s v%s\n" " */\n", - dmProgName, dmProgVersion); -} - -void writeDecl_C(FILE * f, size_t len, char *name) -{ - fprintf(f, "%s %s[%u] = {\n", - optDataType, name, len); - - printf("extern %s %s[%u];\n", - optDataType, name, len); -} - -void writeData_C(FILE * f, Uint8 * buf, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) - { - if (optFormatting) - { - if (optHexMode) - fprintf(f, "0x%.2x", buf[i]); - else - fprintf(f, "%3d", buf[i]); - } - else - { - if (optHexMode) - fprintf(f, "0x%x", buf[i]); - else - fprintf(f, "%d", buf[i]); - } - - fprintf(f, ","); - } -} - -void writeFooter_C(FILE * f, size_t len, char *name) -{ - (void) len; - (void) name; - fprintf(f, "};\n"); -} - - -off_t dmGetFileSize(FILE *f) -{ - off_t len, pos = ftell(f); - fseeko(f, 0, SEEK_END); - len = ftell(f); - fseek(f, pos, SEEK_SET); - return len; -} - - -int main(int argc, char *argv[]) -{ - FILE *sfile = NULL, *dfile = NULL; - off_t inSize; - Uint8 inBuf[RA_LINEBUF]; - int tmpRes; - - /* Initialize */ - dmInitProg("data2inc", "Data to include converter", "0.6", NULL, NULL); - dmVerbosity = 0; - - /* Parse arguments */ - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - /* Determine output type, if not specified */ - if (optFormat == FMT_AUTO) - { - char *dext; - - if (optOutFilename == NULL) - { - dmError("Output format not specified and no output filename given (try --help)\n"); - exit(1); - } - - /* Check filename extension */ - dext = strrchr(optOutFilename, '.'); - if (dext) - { - dext++; - if (!strcasecmp(dext, "c") || !strcasecmp(dext, "h") || - !strcasecmp(dext, "cc") || !strcasecmp(dext, "cpp") || - !strcasecmp(dext, "hpp") || !strcasecmp(dext, "c++")) - optFormat = FMT_C; - else - optFormat = FMT_ASM; - } else - optFormat = FMT_ASM; - } - - /* Set functions */ - switch (optFormat) - { - case FMT_ASM: - if (!optDataType) - optDataType = ".byte"; - - writeHeader = writeHeader_ASM; - writeDecl = writeDecl_ASM; - writeData = writeData_ASM; - writeFooter = writeFooter_ASM; - break; - - case FMT_C: - if (!optDataType) - optDataType = "unsigned char"; - - writeHeader = writeHeader_C; - writeDecl = writeDecl_C; - writeData = writeData_C; - writeFooter = writeFooter_C; - break; - - case FMT_AUTO: - default: - dmError("Internal error, FMT_AUTO at output function init.\n"); - exit(2); - } - - /* Open the files */ - if (optInFilename == NULL) - sfile = stdin; - else - if ((sfile = fopen(optInFilename, "rb")) == NULL) - { - tmpRes = errno; - dmError("Error opening input file '%s'. (%s)\n", - optInFilename, strerror(tmpRes)); - exit(3); - } - - if (optOutFilename == NULL) - dfile = stdout; - else - if ((dfile = fopen(optOutFilename, "wa")) == NULL) - { - tmpRes = errno; - dmError("Error creating output file '%s'. (%s)\n", - optOutFilename, strerror(tmpRes)); - exit(4); - } - - /* Get sourcefile size */ - inSize = dmGetFileSize(sfile); - - /* Output header */ - if (!optQuiet) - writeHeader(dfile, optOutFilename); - - if (optAddLine) - fprintf(dfile, "%s\n", optAddLine); - - /* Output declaration */ - writeDecl(dfile, inSize, optObjName); - - /* Output data */ - while (!feof(sfile)) - { - tmpRes = fread(inBuf, sizeof(Uint8), RA_LINEBUF, sfile); - if (tmpRes > 0) - { - if (optIndentation < 0) - fprintf(dfile, "\t"); - else - if (optIndentation > 0) - { - int i; - for (i = 0; i < optIndentation; i++) - fputs(" ", dfile); - } - - writeData(dfile, inBuf, tmpRes); - - fprintf(dfile, "\n"); - } - } - - - /* Output footer */ - writeFooter(dfile, inSize, optObjName); - - /* Exit */ - fclose(sfile); - fclose(dfile); - - exit(0); - return 0; -}
--- a/utils/gentab.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -#include "dmlib.h" -#include "dmargs.h" -#include <math.h> - -enum -{ - MT_SIN, - MT_COS, - MT_SMOOTH1, - MT_SCURVE, - MT_SMOOTH1_CLAMP, - MT_SCURVE_CLAMP, - MT_SIN_SCURVE, - - MT_LAST -}; - - -typedef struct -{ - char *name; - char *desc; -} DMTransType; - -static DMTransType dmTransTypes[MT_LAST] = -{ - { "sin", "Sine" }, - { "cos", "Cosine" }, - { "smooth1", "Smoothstep1 LERP" }, - { "scurve", "S-curve LERP" }, - { "smooth1-clamp", "Clamped smoothstep1 LERP" }, - { "scurve-clamp", "Clamped S-curve LERP" }, - { "sin-scurve", "Sine S-curve" }, -}; - - -DMFloat - optSOffset = 0.0f, - optSAmplitude = 1.0f, - optSOmega = 1.0f, - optStartValue = 0.0f, - optEndValue = 1.0f; - -int optNSteps = 64, - optPerLine = 16, - optTransType = -1; - -char - *optObjectName = NULL, - *optOutFilename = NULL; - - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'v', "verbose", "Increase verbosity", OPT_NONE }, - { 2, 'o', "output", "Set output file (default stdout)", OPT_ARGREQ }, - { 3, 'n', "name", "Set output object name", OPT_ARGREQ }, - - { 4, 's', "steps", "Number of steps/values in output table", OPT_ARGREQ }, - { 5, 't', "type", "Curve/interpolation type (see list)", OPT_ARGREQ }, - - { 6, 'O', "offset", "Output data offset", OPT_ARGREQ }, - { 7, 'A', "amplitude", "Output amplitude scale", OPT_ARGREQ }, - { 8, 'W', "omega", "Omega (w) multiplier", OPT_ARGREQ }, - - { 9, 'S', "start", "Start value (only smooth/scurve)", OPT_ARGREQ }, - { 10, 'E', "end", "End value (only smooth/scurve)", OPT_ARGREQ }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - int index; - dmPrintBanner(stdout, dmProgName, "[options]"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf("\nAvailable types:\n"); - for (index = 0; index < MT_LAST; index++) - { - DMTransType *tm = &dmTransTypes[index]; - printf("%-15s | %s\n", tm->name, tm->desc); - } - printf("\n"); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - dmVerbosity++; - break; - - case 2: - optOutFilename = optArg; - break; - - case 3: - optObjectName = optArg; - break; - - case 4: - { - int tmp; - if (sscanf(optArg, "%d", &tmp) != 1) - { - dmError("Invalid number of steps argument '%s'.\n", optArg); - return FALSE; - } - optNSteps = tmp; - } - break; - - case 5: - { - int index; - for (index = 0; index < MT_LAST; index++) - { - DMTransType *tm = &dmTransTypes[index]; - if (strcasecmp(tm->name, optArg) == 0) - { - optTransType = index; - return TRUE; - } - } - dmError("Invalid transformation type option '%s'.\n", - optArg); - return FALSE; - } - break; - - case 6: - case 7: - case 8: - case 9: - case 10: - { - DMFloat tmp; - if (sscanf(optArg, "%f", &tmp) != 1) - { - dmError("Invalid %s option argument '%s', expected a floating point value.\n", - currArg, optArg); - return FALSE; - } - switch (optN) - { - case 6: optSOffset = tmp; break; - case 7: optSAmplitude = tmp; break; - case 8: optSOmega = tmp; break; - case 9: optStartValue = tmp; break; - case 10: optEndValue = tmp; break; - } - } - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -int main(int argc, char *argv[]) -{ - FILE *outFile; - DMLerpContext ctx; - int step, n; - - dmInitProg("gentab", "Sine, etc. table generator", "0.1", NULL, NULL); - dmVerbosity = 1; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, NULL, TRUE)) - exit(1); - - // Check settings - if (optTransType < 0) - { - dmError("No transformation type set, perhaps try --help\n"); - return -1; - } - - if (optObjectName == NULL) - { - dmError("Object name not specified, try --help\n"); - return -2; - } - - if (optOutFilename == NULL) - outFile = stdout; - else - if ((outFile = fopen(optOutFilename, "w")) == NULL) - { - int err = dmGetErrno(); - dmError("Could not open output file '%s', %d: %s\n", - optOutFilename, err, dmErrorStr(err)); - return -2; - } - - - // Generate table - dmLerpInit(&ctx, optStartValue, optEndValue, optNSteps); - - fprintf(outFile, - "cnt_%s = %d\n" - "vtab_%s: ", - optObjectName, - optNSteps, - optObjectName - ); - - for (n = 0, step = 0; step < optNSteps; step++) - { - DMFloat t = ((DMFloat) step * optSOmega) / (DMFloat) optNSteps, delta, value; - - switch (optTransType) - { - case MT_SIN: delta = sin(t * 2 * DM_PI); break; - case MT_COS: delta = cos(t * 2 * DM_PI); break; - - case MT_SMOOTH1: delta = dmLerp1(&ctx, step); break; - case MT_SCURVE: delta = dmLerpSCurve(&ctx, step); break; - case MT_SMOOTH1_CLAMP: delta = dmLerp1Clamp(&ctx, step); break; - case MT_SCURVE_CLAMP: delta = dmLerpSCurveClamp(&ctx, step); break; - case MT_SIN_SCURVE: delta = dmLerpSCurveClamp(&ctx, step); break; - - default: delta = 0; - } - - value = optSOffset + delta * optSAmplitude; - - // Print the value - if (n == 0) - fprintf(outFile, "\t.byte "); - - fprintf(outFile, "%ld%s", - lrint(value), - (n < optPerLine - 1) ? "," : ""); - - if (++n >= optPerLine) - { - fprintf(outFile, "\n"); - n = 0; - } - } - if (n > 0) - fprintf(outFile, "\n"); - - fprintf(outFile, "\n"); - - return 0; -}
--- a/utils/gfxconv.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1697 +0,0 @@ -/* - * gfxconv - Convert various graphics formats - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2012 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include "dmlib.h" -#include "dmargs.h" -#include "dmfile.h" -#include "dmmutex.h" -#include "libgfx.h" -#include "lib64gfx.h" - -//#define UNFINISHED 1 - -#define DM_MAX_COLORS 256 - -#define ASC_NBITS 8 -#define ASC_NCOLORS 4 -static const char dmASCIIPalette[ASC_NCOLORS] = ".:X#"; - -enum -{ - FFMT_AUTO = 0, - - FFMT_ASCII, - FFMT_ANSI, - FFMT_IMAGE, - - FFMT_CHAR, - FFMT_SPRITE, - FFMT_BITMAP, - - FFMT_LAST -}; - - -typedef struct -{ - char *name; - char *fext; - BOOL in, out; - int format; - int subformat; -} DMConvFormat; - - -static DMConvFormat convFormatList[] = -{ - { - "ASCII text", "asc", FALSE, TRUE, - FFMT_ASCII , 0, - }, - { - "ANSI colored text", "ansi", FALSE, TRUE, - FFMT_ANSI , 0, - }, - { - "PNG image file", "png", TRUE, TRUE, - FFMT_IMAGE , IMGFMT_PNG, - }, - { - "PPM image file", "ppm", FALSE, TRUE, - FFMT_IMAGE , IMGFMT_PPM, - }, - { - "PCX image file", "pcx", TRUE, TRUE, - FFMT_IMAGE , IMGFMT_PCX, - }, - { - "IFF ILBM file", "lbm", TRUE, FALSE, - FFMT_IMAGE , IMGFMT_ILBM, - }, - { - "Bitplaned RAW (intl/non-intl) image file", "raw", FALSE, TRUE, - FFMT_IMAGE , IMGFMT_RAW, - }, - { - "IFFMaster RAW image file", "araw", FALSE, TRUE, - FFMT_IMAGE , IMGFMT_ARAW, - }, - - { - "C64 bitmap image file", NULL, TRUE, TRUE, - FFMT_BITMAP , -1, - }, - - { - "C64 character/font data", "chr", TRUE, TRUE, - FFMT_CHAR , 0 - }, - { - "C64 sprite data", "spr", TRUE, TRUE, - FFMT_SPRITE , 0 - }, -}; - -static const int nconvFormatList = sizeof(convFormatList) / sizeof(convFormatList[0]); - - -typedef struct -{ - BOOL triplet, alpha; - DMColor color; - int from, to; -} DMMapValue; - - - -char *optInFilename = NULL, - *optOutFilename = NULL; -int optInFormat = FFMT_AUTO, - optOutFormat = FFMT_ASCII, - optInSubFormat = IMGFMT_PNG, - optOutSubFormat = IMGFMT_PNG, - optItemCount = -1, - optPlanedWidth = 1, - optForcedFormat = -1; -int optInSkip = 0; -BOOL optInMulticolor = FALSE, - optSequential = FALSE, - optRemapColors = FALSE, - optRemapRemove = FALSE; -int optNRemapTable = 0; -DMMapValue optRemapTable[DM_MAX_COLORS]; -int optColors[C64_MAX_COLORS]; - -DMImageSpec optSpec = -{ - .scale = 1, - .nplanes = 4, - .interleave = FALSE, - .paletted = FALSE, - .format = 0, -}; - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 15, 'v', "verbose", "Increase verbosity", OPT_NONE }, - { 3, 'o', "output", "Output filename", OPT_ARGREQ }, - { 1, 'i', "informat", "Set input format ([s]prite, [c]har, [b]itmap, [i]mage)", OPT_ARGREQ }, - { 2, 'm', "multicolor", "Input is multicolor / output in multicolor", OPT_NONE }, - { 4, 's', "skip", "Skip bytes in input", OPT_ARGREQ }, - { 5, 'f', "format", "Output format (see --formats)", OPT_ARGREQ }, - { 17, 'F', "formats", "Output format (see list below)", OPT_NONE }, - { 8, 'q', "sequential", "Output sequential files (image output only)", OPT_NONE }, - { 6, 'c', "colormap", "Color mappings (see below for information)", OPT_ARGREQ }, - { 7, 'n', "numitems", "How many 'items' to view (default: all)", OPT_ARGREQ }, - { 9, 'S', "scale", "Scale output by x (image output only)", OPT_ARGREQ }, - { 10, 'b', "bformat", "Force input bitmap format (see below)", OPT_ARGREQ }, - { 11, 'w', "width", "Item width (number of items per row, min 1)", OPT_ARGREQ }, - { 12, 'P', "paletted", "Use indexed/paletted output (png, pcx output only)", OPT_NONE }, - { 13, 'B', "bplanes", "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ }, - { 14, 'I', "interleave", "Interleave scanlines (default: output whole planes)", OPT_NONE }, - { 16, 'R', "remap", "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>] | -R @map.txt)", OPT_ARGREQ }, - { 18, 'r', "remap-remove", "Remove unused colors from remapped palette (requires -R)", OPT_NONE }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowFormats() -{ - int i; - - printf( - "Available input/output formats:\n" - " Ext | I | O | Description\n" - "------+---+---+-----------------------------------------------\n" - ); - - for (i = 0; i < nconvFormatList; i++) - { - DMConvFormat *fmt = &convFormatList[i]; - printf("%-5s | %c | %c | %s\n", - fmt->fext ? fmt->fext : "", - fmt->in ? 'X' : ' ', - fmt->out ? 'X' : ' ', - fmt->name); - } - - printf( - "\n" - "(Not all input->output combinations are actually supported.)\n" - "\n" - "Available bitmap formats:\n" - " Ext | Type | Description\n" - "------+-----------------+-------------------------------------\n" - ); - - for (i = 0; i < ndmC64ImageFormats; i++) - { - const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; - char buf[64]; - printf("%-5s | %-15s | %s\n", - fmt->fext, - dmC64GetImageTypeString(buf, sizeof(buf), fmt->type), - fmt->name); - } -} - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, "[options] <input file>"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf( - "\n" - "Color map definitions are used for ANSI and image output, to declare what\n" - "output colors of the C64 palette are used for each single color/multi color\n" - "bit-combination. For example, if the input is multi color sprite or char,\n" - "you can define colors like: -c 0,8,3,15 .. for single color: -c 0,1\n" - "The numbers are palette indexes, and the order is for bit(pair)-values\n" - "00, 01, 10, 11 (multi color) and 0, 1 (single color). NOTICE! 255 is the\n" - "special color that can be used for transparency.\n" - ); -} - - -int dmGetConvFormat(int format, int subformat) -{ - int i; - for (i = 0; i < nconvFormatList; i++) - { - DMConvFormat *fmt = &convFormatList[i]; - if (fmt->format == format && - fmt->subformat == subformat) - return i; - } - return -1; -} - - -BOOL dmGetFormatByExt(const char *fext, int *format, int *subformat) -{ - int i; - if (fext == NULL) - return FALSE; - - for (i = 0; i < nconvFormatList; i++) - { - DMConvFormat *fmt = &convFormatList[i]; - if (fmt->fext != NULL && - strcasecmp(fext, fmt->fext) == 0) - { - *format = fmt->format; - *subformat = fmt->subformat; - return TRUE; - } - } - - for (i = 0; i < ndmC64ImageFormats; i++) - { - const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; - if (fmt->fext != NULL && - strcasecmp(fext, fmt->fext) == 0) - { - *format = FFMT_BITMAP; - *subformat = i; - return TRUE; - } - } - - return FALSE; -} - - -static BOOL dmParseMapOptionMapItem(const char *popt, DMMapValue *value, const int nmax, const char *msg) -{ - char *end, *split, *opt = dm_strdup(popt); - - if (opt == NULL) - goto error; - - if ((end = split = strchr(opt, ':')) == NULL) - { - dmError("Invalid %s value '%s', expected <(#|%)RRGGBB|[$|0x]index>:<[$|0x]index>.\n", msg, opt); - goto error; - } - - // Trim whitespace - *end = 0; - for (end--; end > opt && *end && isspace(*end); end--) - *end = 0; - - // Parse either a hex triplet color definition or a normal value - if (*opt == '#' || *opt == '%') - { - int colR, colG, colB, colA; - - if (sscanf(opt + 1, "%2x%2x%2x%2x", &colR, &colG, &colB, &colA) == 4 || - sscanf(opt + 1, "%2X%2X%2X%2X", &colR, &colG, &colB, &colA) == 4) - { - value->alpha = TRUE; - value->color.a = colA; - } - else - if (sscanf(opt + 1, "%2x%2x%2x", &colR, &colG, &colB) != 3 && - sscanf(opt + 1, "%2X%2X%2X", &colR, &colG, &colB) != 3) - { - dmError("Invalid %s value '%s', expected a hex triplet, got '%s'.\n", msg, popt, opt + 1); - goto error; - } - - value->color.r = colR; - value->color.g = colG; - value->color.b = colB; - value->triplet = TRUE; - } - else - { - if (!dmGetIntVal(opt, &value->from)) - { - dmError("Invalid %s value '%s', could not parse source value '%s'.\n", msg, popt, opt); - goto error; - } - value->triplet = FALSE; - } - - // Trim whitespace - split++; - while (*split && isspace(*split)) split++; - - // Parse destination value - if (!dmGetIntVal(split, &value->to)) - { - dmError("Invalid %s value '%s', could not parse destination value '%s'.\n", msg, popt, split); - goto error; - } - - if (!value->triplet && (value->from < 0 || value->from > 255)) - { - dmError("Invalid %s map source color index value %d, must be [0..255].\n", msg, value->from); - goto error; - } - - if (value->to < 0 || value->to > nmax) - { - dmError("Invalid %s map destination color index value %d, must be [0..%d].\n", msg, value->to, nmax); - goto error; - } - - dmFree(opt); - return TRUE; - -error: - dmFree(opt); - return FALSE; -} - - -static BOOL dmParseMapOptionItem(char *opt, char *end, void *pvalue, const int index, const int nmax, const BOOL requireIndex, const char *msg) -{ - // Trim whitespace - if (end != NULL) - { - *end = 0; - for (end--; end > opt && *end && isspace(*end); end--) - *end = 0; - } - while (*opt && isspace(*opt)) opt++; - - // Parse item based on mode - if (requireIndex) - { - DMMapValue *value = (DMMapValue *) pvalue; - if (!dmParseMapOptionMapItem(opt, &value[index], nmax, msg)) - return FALSE; - } - else - { - int *value = (int *) pvalue; - char *split = strchr(opt, ':'); - if (split != NULL) - { - dmError("Unexpected ':' in indexed %s '%s'.\n", msg, opt); - return FALSE; - } - - if (!dmGetIntVal(opt, &value[index])) - { - dmError("Invalid %s value '%s', could not parse.\n", msg, opt); - return FALSE; - } - } - - return TRUE; -} - - -BOOL dmParseMapOptionString(char *opt, void *values, int *nvalues, const int nmax, const BOOL requireIndex, const char *msg) -{ - char *end, *start = opt; - - *nvalues = 0; - while (*nvalues < nmax && *start && (end = strchr(start, ',')) != NULL) - { - if (!dmParseMapOptionItem(start, end, values, *nvalues, nmax, requireIndex, msg)) - return FALSE; - - start = end + 1; - (*nvalues)++; - } - - if (*start && *nvalues < nmax) - { - if (!dmParseMapOptionItem(start, NULL, values, *nvalues, nmax, requireIndex, msg)) - return FALSE; - - (*nvalues)++; - } - - return TRUE; -} - - -int dmParseColorRemapFile(const char *filename, DMMapValue *values, int *nvalue, const int nmax) -{ - FILE *fp; - char line[512]; - int res = DMERR_OK; - - if ((fp = fopen(filename, "r")) == NULL) - { - res = dmGetErrno(); - dmError("Could not open color remap file '%s' for reading, %d: %s\n", - res, dmErrorStr(res)); - return res; - } - - while (fgets(line, sizeof(line), fp)) - { - char *start = line; - while (*start && isspace(*start)) start++; - - if (*start != 0 && *start != ';') - { - if (!dmParseMapOptionMapItem(line, &values[*nvalue], nmax, "mapping file")) - goto error; - else - { - (*nvalue)++; - if (*nvalue >= nmax) - { - dmError("Too many mapping pairs in '%s', maximum is %d.\n", - filename, nmax); - goto error; - } - } - } - } - -error: - fclose(fp); - return res; -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 17: - argShowFormats(); - exit(0); - break; - - case 15: - dmVerbosity++; - break; - - case 1: - switch (tolower(optArg[0])) - { - case 's': - optInFormat = FFMT_SPRITE; - break; - case 'c': - optInFormat = FFMT_CHAR; - break; - case 'b': - optInFormat = FFMT_BITMAP; - break; - case 'i': - optInFormat = FFMT_IMAGE; - break; - default: - dmError("Invalid input format '%s'.\n", optArg); - return FALSE; - } - break; - - case 2: - optInMulticolor = TRUE; - break; - - case 3: - optOutFilename = optArg; - break; - - case 4: - if (!dmGetIntVal(optArg, &optInSkip)) - { - dmError("Invalid skip value argument '%s'.\n", optArg); - return FALSE; - } - break; - - case 5: - if (!dmGetFormatByExt(optArg, &optOutFormat, &optOutSubFormat)) - { - dmError("Invalid output format '%s'.\n", optArg); - return FALSE; - } - break; - - case 6: - { - int index, ncolors; - if (!dmParseMapOptionString(optArg, optColors, - &ncolors, C64_MAX_COLORS, FALSE, "color table option")) - return FALSE; - - dmMsg(1, "Set color table: "); - for (index = 0; index < ncolors; index++) - { - dmPrint(1, "[%d:%d]%s", - index, optColors[index], - (index < ncolors) ? ", " : ""); - } - dmPrint(1, "\n"); - } - break; - - case 7: - if (sscanf(optArg, "%d", &optItemCount) != 1) - { - dmError("Invalid count value argument '%s'.\n", optArg); - return FALSE; - } - break; - - case 8: - optSequential = TRUE; - break; - - case 9: - { - int tmp = atoi(optArg); - if (tmp < 1 || tmp > 50) - { - dmError("Invalid scale value '%s'.\n", optArg); - return FALSE; - } - optSpec.scale = tmp; - } - break; - - case 11: - { - int tmp = atoi(optArg); - if (tmp < 1 || tmp > 512) - { - dmError("Invalid width value '%s'.\n", optArg); - return FALSE; - } - optPlanedWidth = tmp; - } - break; - - case 12: - optSpec.paletted = TRUE; - break; - - case 13: - { - int tmp = atoi(optArg); - if (tmp < 1 || tmp > 8) - { - dmError("Invalid bitplanes/bpp value '%s'.\n", optArg); - return FALSE; - } - optSpec.nplanes = tmp; - } - break; - - case 14: - optSpec.interleave = TRUE; - break; - - - case 16: - if (optArg[0] == '@') - { - if (optArg[1] != 0) - { - int res; - if ((res = dmParseColorRemapFile(optArg + 1, - optRemapTable, &optNRemapTable, DM_MAX_COLORS)) != DMERR_OK) - return FALSE; - } - else - { - dmError("No remap filename given.\n"); - return FALSE; - } - } - else - { - if (!dmParseMapOptionString(optArg, optRemapTable, - &optNRemapTable, DM_MAX_COLORS, TRUE, "color remap option")) - return FALSE; - } - - optRemapColors = TRUE; - break; - - case 18: - optRemapRemove = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - if (!optInFilename) - optInFilename = currArg; - else - { - dmError("Source filename already specified, extraneous argument '%s'.\n", - currArg); - return FALSE; - } - - return TRUE; -} - - -void dmPrintByte(FILE *out, int byte, int format, BOOL multicolor) -{ - int i; - - if (multicolor) - { - for (i = ASC_NBITS; i; i -= 2) - { - int val = (byte & (3ULL << (i - 2))) >> (i - 2); - char ch; - switch (format) - { - case FFMT_ASCII: - ch = dmASCIIPalette[val]; - fprintf(out, "%c%c", ch, ch); - break; - case FFMT_ANSI: - fprintf(out, "%c[0;%d;%dm##%c[0m", - 0x1b, - 1, - 31 + optColors[val], - 0x1b); - break; - } - } - } - else - { - for (i = ASC_NBITS; i; i--) - { - int val = (byte & (1ULL << (i - 1))) >> (i - 1); - char ch; - switch (format) - { - case FFMT_ASCII: - ch = val ? '#' : '.'; - fputc(ch, out); - break; - case FFMT_ANSI: - fprintf(out, "%c[0;%d;%dm %c[0m", - 0x1b, - 1, - 31 + optColors[val], - 0x1b); - break; - } - } - } -} - - -void dmDumpCharASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor) -{ - int yc; - - for (yc = 0; yc < C64_CHR_HEIGHT; yc++) - { - fprintf(outFile, "%04x : ", *offs); - dmPrintByte(outFile, buf[yc], format, multicolor); - fprintf(outFile, "\n"); - (*offs)++; - } -} - - -void dmDumpSpriteASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor) -{ - int bufOffs, xc, yc; - - for (bufOffs = yc = 0; yc < C64_SPR_HEIGHT; yc++) - { - fprintf(outFile, "%04x : ", *offs); - for (xc = 0; xc < C64_SPR_WIDTH; xc++) - { - dmPrintByte(outFile, buf[bufOffs], format, multicolor); - fprintf(outFile, " "); - bufOffs++; - (*offs)++; - } - fprintf(outFile, "\n"); - } - (*offs)++; -} - - -#ifdef UNFINISHED -int dmConvertBMP2(DMImage *screen, const DM64Image *img) -{ - int yc; - Uint8 *dp = screen->data; - - for (yc = 0; yc < screen->height; yc++) - { - Uint8 *d = dp; - const int y = yc / 8, yb = yc & 7; - const int scroffsy = y * C64_SCR_CH_WIDTH; - const int bmoffsy = y * C64_SCR_WIDTH; - int xc; - - for (xc = 0; xc < screen->width / 2; xc++) - { - const int x = xc / 4; - const int scroffs = scroffsy + x; - const int b = img->bitmap[0][bmoffsy + (x * 8) + yb]; - const int v = 6 - ((xc * 2) & 6); - Uint8 c; - - switch ((b >> v) & 3) - { - case 0: c = img->bgcolor; break; - case 1: c = img->screen[0][scroffs] >> 4; break; - case 2: c = img->screen[0][scroffs] & 15; break; - case 3: c = img->color[0][scroffs] & 15; break; - } - - *d++ = c; - *d++ = c; - } - - dp += screen->pitch; - } - - return 0; -} -#endif - - -int dmRemapImageColors(DMImage *image) -{ - DMColor *npal = dmCalloc(image->ncolors, sizeof(DMColor)); - int *mapping = dmMalloc(image->ncolors * sizeof(int)); - BOOL *mapped = dmMalloc(image->ncolors * sizeof(BOOL)); - BOOL *used = dmMalloc(image->ncolors * sizeof(BOOL)); - int n, index, xc, yc, ncolors; - - dmMsg(1, "Remapping %d output image colors of %d colors.\n", optNRemapTable, image->ncolors); - - if (npal == NULL || mapping == NULL || mapped == NULL || used == NULL) - { - dmError("Could not allocate memory for reused palette.\n"); - return DMERR_MALLOC; - } - - for (index = 0; index < image->ncolors; index++) - { - mapping[index] = -1; - mapped[index] = used[index] = FALSE; - } - - // Find used colors - dmMsg(2, "Scanning image for used colors...\n"); - for (ncolors = yc = 0; yc < image->height; yc++) - { - Uint8 *dp = image->data + image->pitch * yc; - for (xc = 0; xc < image->width; xc++) - { - Uint8 col = dp[xc]; - if (col < image->ncolors && !used[col]) - { - used[col] = TRUE; - ncolors++; - } - } - } - dmMsg(2, "Found %d used colors, creating remap-table.\n", ncolors); - - // Match and mark mapped colors - for (index = 0; index < optNRemapTable; index++) - { - DMMapValue *map = &optRemapTable[index]; - if (map->triplet) - { - BOOL found = FALSE; - for (n = 0; n < image->ncolors; n++) - { - if (dmCompareColor(&(image->pal[n]), &(map->color), map->alpha)) - { - dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n", - map->color.r, map->color.g, map->color.b, map->color.a, - n, - map->to); - - mapping[n] = map->to; - mapped[map->to] = TRUE; - found = TRUE; - } - } - - if (!found) - { - dmMsg(3, "No RGBA match found for map index %d, #%02x%02x%02x%02x\n", - index, - map->color.r, map->color.g, map->color.b, map->color.a); - } - } - else - { - dmMsg(3, "Map index: %d -> %d\n", - map->from, map->to); - - mapping[map->from] = map->to; - mapped[map->to] = TRUE; - } - } - - - // Fill in the rest - if (optRemapRemove) - { - dmMsg(2, "Removing unused colors.\n"); - for (index = 0; index < image->ncolors; index++) - if (mapping[index] < 0 && used[index]) - { - for (n = 0; n < image->ncolors; n++) - if (!mapped[n]) - { - mapping[index] = n; - mapped[n] = TRUE; - break; - } - } - } - else - { - for (index = 0; index < image->ncolors; index++) - if (mapping[index] < 0) - { - for (n = 0; n < image->ncolors; n++) - if (!mapped[n]) - { - mapping[index] = n; - mapped[n] = TRUE; - break; - } - } - } - - // Calculate final number of palette colors - ncolors = 0; - for (index = 0; index < image->ncolors; index++) - { - if (mapping[index] + 1 > ncolors) - ncolors = mapping[index] + 1; - } - - // Copy palette entries - for (index = 0; index < image->ncolors; index++) - { - if (mapping[index] >= 0) - { - memcpy(&npal[mapping[index]], &(image->pal[index]), sizeof(DMColor)); - } - } - - // Remap image - dmMsg(1, "Remapping image to %d colors...\n", ncolors); - for (yc = 0; yc < image->height; yc++) - { - Uint8 *dp = image->data + image->pitch * yc; - for (xc = 0; xc < image->width; xc++) - { - Uint8 col = dp[xc]; - if (col < image->ncolors && mapping[col] >= 0 && mapping[col] < image->ncolors) - dp[xc] = mapping[col]; - else - dp[xc] = 0; - } - } - - // Set new palette, free memory - dmFree(image->pal); - image->pal = npal; - image->ncolors = ncolors; - - dmFree(mapping); - dmFree(mapped); - dmFree(used); - return DMERR_OK; -} - - -int dmWriteBitmap(const char *filename, DMC64Image *image, int iformat, BOOL enableFixUps) -{ - FILE *outFile = NULL; - Uint8 *buf = NULL; - size_t bufSize; - int res = DMERR_OK; - const DMC64ImageFormat *fmt = &dmC64ImageFormats[iformat]; - - dmMsg(1, "Converting to %s format bitmap.\n", fmt->name); - if (image->type != fmt->type && enableFixUps) - { - // Try to do some simple fixups - if ((fmt->type & D64_FMT_FLI) && (image->type & D64_FMT_FLI) == 0) - { - dmMsg(1, "Upconverting multicolor to FLI.\n"); - int i; - for (i = 1; i < C64_SCR_MAX_BANK; i++) - { - memcpy(image->color[i], image->color[0], C64_SCR_COLOR_SIZE); - memcpy(image->screen[i], image->screen[0], C64_SCR_SCREEN_SIZE); - } - } - } - - - if ((res = dmC64EncodeGenericBMP(&buf, &bufSize, image, fmt)) != DMERR_OK) - goto error; - - dmMsg(2, "Result: %d bytes\n", bufSize); - - if ((outFile = fopen(filename, "wb")) == NULL) - { - res = dmGetErrno(); - dmError("Error opening output file '%s', %d: %s\n", - filename, res, dmErrorStr(res)); - goto error; - } - - if (!dm_fwrite_str(outFile, buf, bufSize)) - { - res = dmGetErrno(); - dmError("Error writing image data to '%s', %d: %s\n", - filename, res, dmErrorStr(res)); - } - -error: - if (outFile != NULL) - fclose(outFile); - dmFree(buf); - return res; -} - - -int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info) -{ - if (info) - { - dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n", - dmImageFormatList[iformat].fext, - image->width, image->height, - image->width * spec->scale, image->height * spec->scale, - spec->scale); - } - - // Perform color remapping - if (optRemapColors) - { - int res; - if ((res = dmRemapImageColors(image)) != DMERR_OK) - return res; - } - - switch (iformat) - { -#ifdef DM_USE_LIBPNG - case IMGFMT_PNG: - if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "32bit RGBA"); - spec->format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA; - return dmWritePNGImage(filename, image, spec); -#endif - - case IMGFMT_PPM: - if (info) dmMsg(2, "24bit RGB output.\n"); - spec->format = DM_IFMT_RGB; - return dmWritePPMImage(filename, image, spec); - - case IMGFMT_PCX: - if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "24bit RGB"); - return dmWritePCXImage(filename, image, spec); - - case IMGFMT_RAW: - case IMGFMT_ARAW: - { - FILE *fp; - char *dataFilename, *fext, *tmpFilename = dm_strdup(filename); - - // Form data file filename - if (tmpFilename == NULL) - return DMERR_MALLOC; - - fext = strrchr(tmpFilename, '.'); - if (fext != NULL) - *fext = 0; - dataFilename = dm_strdup_printf("%s.inc", tmpFilename); - dmFree(tmpFilename); - - // Open data file for writing - if ((fp = fopen(dataFilename, "w")) == NULL) - dmError("Could not create '%s'.\n", dataFilename); - dmFree(dataFilename); - - if (fp != NULL) - { - // Strip extension - int i; - char *palID = dm_strdup_printf("img_%s", filename); - char *fext = strrchr(palID, '.'); - if (fext != NULL) - *fext = 0; - - // Replace any non-alphanumerics - for (i = 0; palID[i]; i++) - { - if (isalnum(palID[i])) - palID[i] = tolower(palID[i]); - else - palID[i] = '_'; - } - - if (iformat == IMGFMT_ARAW) - { - fprintf(fp, - "%s_width: dw.w %d\n" - "%s_height: dw.w %d\n" - "%s_nplanes: dw.w %d\n" - "%s_ncolors: dw.w %d\n" - "%s_palette:\n", - palID, image->width, - palID, image->height, - palID, spec->nplanes, - palID, image->ncolors, - palID); - - dmWriteIFFMasterRAWPalette(fp, image, 1 << optSpec.nplanes, NULL, NULL); - - fprintf(fp, - "%s: incbin \"%s\"\n", - palID, filename); - } - else - { - fprintf(fp, - "%s_width: dw.w %d\n" - "%s_height: dw.w %d\n" - "%s_nplanes: dw.w %d\n", - palID, image->width, - palID, image->height, - palID, spec->nplanes); - } - - fclose(fp); - dmFree(palID); - } - - if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", spec->nplanes, spec->interleave ? "with" : "without"); - return dmWriteRAWImage(filename, image, spec); - } - break; - - default: - return DMERR_INVALID_DATA; - } -} - - -static Uint8 dmConvertByte(const Uint8 *sp, const BOOL multicolor) -{ - Uint8 byte = 0; - int xc; - - if (multicolor) - { - for (xc = 0; xc < 8 / 2; xc++) - { - Uint8 pixel = sp[xc * 2] & 3; - byte |= pixel << (6 - (xc * 2)); - } - } - else - { - for (xc = 0; xc < 8; xc++) - { - Uint8 pixel = sp[xc] == 0 ? 0 : 1; - byte |= pixel << (7 - xc); - } - } - - return byte; -} - - -BOOL dmConvertImage2Char(Uint8 *buf, const DMImage *image, - const int xoffs, const int yoffs, const BOOL multicolor) -{ - int yc; - - if (xoffs < 0 || yoffs < 0 || - xoffs + C64_CHR_WIDTH_PX > image->width || - yoffs + C64_CHR_HEIGHT > image->height) - return FALSE; - - for (yc = 0; yc < C64_CHR_HEIGHT; yc++) - { - const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + xoffs; - buf[yc] = dmConvertByte(sp, multicolor); - } - - return TRUE; -} - - -BOOL dmConvertImage2Sprite(Uint8 *buf, const DMImage *image, - const int xoffs, const int yoffs, const BOOL multicolor) -{ - int yc, xc; - - if (xoffs < 0 || yoffs < 0 || - xoffs + C64_SPR_WIDTH_PX > image->width || - yoffs + C64_SPR_HEIGHT > image->height) - return FALSE; - - for (yc = 0; yc < C64_SPR_HEIGHT; yc++) - { - for (xc = 0; xc < C64_SPR_WIDTH_PX / C64_SPR_WIDTH; xc++) - { - const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + (xc * 8) + xoffs; - buf[(yc * C64_SPR_WIDTH) + xc] = dmConvertByte(sp, multicolor); - } - } - - return TRUE; -} - - -int dmWriteSpritesAndChars(const char *filename, DMImage *image, int outFormat, BOOL multicolor) -{ - int outBlockW, outBlockH, bx, by; - FILE *outFile = NULL; - Uint8 *buf = NULL; - size_t bufSize; - char *outType; - - switch (outFormat) - { - case FFMT_CHAR: - bufSize = C64_CHR_SIZE; - outBlockW = image->width / C64_CHR_WIDTH_PX; - outBlockH = image->height / C64_CHR_HEIGHT; - outType = "char"; - break; - - case FFMT_SPRITE: - bufSize = C64_SPR_SIZE; - outBlockW = image->width / C64_SPR_WIDTH_PX; - outBlockH = image->height / C64_SPR_HEIGHT; - outType = "sprite"; - break; - - default: - dmError("Invalid output format %d, internal error.\n", outFormat); - goto error; - } - - if (outBlockW <= 0 || outBlockH <= 0) - { - dmError("Source image dimensions too small for conversion, block dimensions %d x %d.\n", - outBlockW, outBlockH); - goto error; - } - - if ((outFile = fopen(filename, "wb")) == NULL) - { - int err = dmGetErrno(); - dmError("Could not open '%s' for writing, %d: %s.\n", - filename, err, dmErrorStr(err)); - goto error; - } - - if ((buf = dmMalloc(bufSize)) == NULL) - { - dmError("Could not allocate %d bytes for conversion buffer.\n", - bufSize); - goto error; - } - - dmMsg(1, "Writing %d x %d = %d blocks of %s data...\n", - outBlockW, outBlockH, outBlockW * outBlockH, outType); - - for (by = 0; by < outBlockH; by++) - for (bx = 0; bx < outBlockW; bx++) - { - switch (outFormat) - { - case FFMT_CHAR: - if (!dmConvertImage2Char(buf, image, - bx * C64_CHR_WIDTH_PX, by * C64_CHR_HEIGHT, - multicolor)) - goto error; - break; - - case FFMT_SPRITE: - if (!dmConvertImage2Sprite(buf, image, - bx * C64_SPR_WIDTH_PX, by * C64_SPR_HEIGHT, - multicolor)) - goto error; - } - - if (!dm_fwrite_str(outFile, buf, bufSize)) - { - int err = dmGetErrno(); - dmError("Error writing data block %d,%d to '%s', %d: %s\n", - bx, by, filename, err, dmErrorStr(err)); - goto error; - } - } - - fclose(outFile); - dmFree(buf); - return 0; - -error: - if (outFile != NULL) - fclose(outFile); - dmFree(buf); - return -1; -} - - -int dmDumpSpritesAndChars(FILE *inFile) -{ - int dataOffs, itemCount, outWidth, outWidthPX, outHeight; - size_t bufSize; - Uint8 *bufData; - - switch (optInFormat) - { - case FFMT_CHAR: - bufSize = C64_CHR_SIZE; - outWidth = C64_CHR_WIDTH; - outWidthPX = C64_CHR_WIDTH_PX; - outHeight = C64_CHR_HEIGHT; - break; - - case FFMT_SPRITE: - bufSize = C64_SPR_SIZE; - outWidth = C64_SPR_WIDTH; - outWidthPX = C64_SPR_WIDTH_PX; - outHeight = C64_SPR_HEIGHT; - break; - - default: - dmError("Invalid input format %d, internal error.\n", optInFormat); - return -1; - } - - if ((bufData = dmMalloc(bufSize)) == NULL) - { - dmError("Could not allocate temporary buffer of %d bytes.\n", bufSize); - return -2; - } - - - dataOffs = optInSkip; - itemCount = 0; - - if (optOutFormat == FFMT_ANSI || optOutFormat == FFMT_ASCII) - { - BOOL error = FALSE; - FILE *outFile; - - if (optOutFilename == NULL) - outFile = stdout; - else - if ((outFile = fopen(optOutFilename, "w")) == NULL) - { - int res = dmGetErrno(); - dmError("Error opening output file '%s', %d: %s\n", - optOutFilename, res, dmErrorStr(res)); - goto error; - } - - while (!feof(inFile) && !error && (optItemCount < 0 || itemCount < optItemCount)) - { - memset(bufData, 0, bufSize); - - if (fread(bufData, 1, bufSize, inFile) != bufSize) - { - dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n", - bufSize, dataOffs); - error = TRUE; - } - - fprintf(outFile, "---- : -------------- #%d\n", itemCount); - - switch (optInFormat) - { - case FFMT_CHAR: - dmDumpCharASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor); - break; - case FFMT_SPRITE: - dmDumpSpriteASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor); - break; - } - itemCount++; - } - - fclose(outFile); - } - else - if (optOutFormat == FFMT_IMAGE) - { - DMImage *outImage = NULL; - char *outFilename = NULL; - int outX = 0, outY = 0, err; - - if (optSequential) - { - if (optOutFilename == NULL) - { - dmError("Sequential image output requires filename template.\n"); - goto error; - } - - outImage = dmImageAlloc(outWidthPX, outHeight); - dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n", - optItemCount, - outImage->width, outImage->height, - outImage->width * optSpec.scale, outImage->height * optSpec.scale); - } - else - { - int outIWidth, outIHeight; - if (optItemCount <= 0) - { - dmError("Single-image output requires count to be set (-n).\n"); - goto error; - } - - outIWidth = optPlanedWidth; - outIHeight = (optItemCount / optPlanedWidth); - if (optItemCount % optPlanedWidth) - outIHeight++; - - outImage = dmImageAlloc(outWidthPX * outIWidth, outIHeight * outHeight); - } - - outImage->constpal = TRUE; - outImage->pal = dmC64Palette; - outImage->ncolors = C64_NCOLORS; - outImage->ctransp = 255; - - while (!feof(inFile) && (optItemCount < 0 || itemCount < optItemCount)) - { - memset(bufData, 0, bufSize); - - if (fread(bufData, 1, bufSize, inFile) != bufSize) - { - dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n", - bufSize, dataOffs); - break; - } - - if ((err = dmC64ConvertCSData(outImage, outX * outWidthPX, outY * outHeight, - bufData, outWidth, outHeight, optInMulticolor, optColors)) != DMERR_OK) - { - dmError("Internal error in conversion of raw data to bitmap: %d.\n", err); - break; - } - - if (optSequential) - { - outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, convFormatList[optOutFormat].fext); - if (outFilename == NULL) - { - dmError("Could not allocate memory for filename template?\n"); - goto error; - } - - dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); - dmFree(outFilename); - } - else - { - if (++outX >= optPlanedWidth) - { - outX = 0; - outY++; - } - } - - itemCount++; - } - - if (!optSequential) - { - dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); - } - - dmImageFree(outImage); - } - else - if (optOutFormat == FFMT_BITMAP) - { - if (optSequential) - { - dmError("Sequential output not supported for spr/char -> bitmap conversion.\n"); - goto error; - } - } - - dmFree(bufData); - return 0; - -error: - dmFree(bufData); - return -1; -} - - -int main(int argc, char *argv[]) -{ - FILE *inFile; - const DMC64ImageFormat *cfmt; - DMC64Image cimage; - Uint8 *dataBuf = NULL; - size_t dataSize; - int i; - - // Default colors - for (i = 0; i < C64_MAX_COLORS; i++) - optColors[i] = i; - - // Initialize and parse commandline - dmInitProg("gfxconv", "Simple graphics converter", "0.75", NULL, NULL); - - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - -#ifndef DM_USE_LIBPNG - if (optOutFormat == IMGFMT_PNG) - { - dmError("PNG output format support not compiled in, sorry.\n"); - goto error; - } -#endif - - // Determine input format, if not specified' - if (optInFormat == FFMT_AUTO && optInFilename != NULL) - { - char *dext = strrchr(optInFilename, '.'); - dmMsg(4, "Trying to determine file format by extension.\n"); - if (dext) - { - dmGetFormatByExt(dext + 1, &optInFormat, &optInSubFormat); - } - } - - if (optInFilename == NULL) - { - if (optInFormat == FFMT_AUTO) - { - dmError("Standard input cannot be used without specifying input format.\n"); - dmError("Perhaps you should try using --help\n"); - goto error; - } - inFile = stdin; - } - else - if ((inFile = fopen(optInFilename, "rb")) == NULL) - { - int res = dmGetErrno(); - dmError("Error opening input file '%s', %d: %s\n", - optInFilename, res, dmErrorStr(res)); - goto error; - } - - if (dmReadDataFile(inFile, NULL, &dataBuf, &dataSize) != 0) - goto error; - - if (optInFormat == FFMT_AUTO || optInFormat == FFMT_BITMAP) - { - // Probe for format - const DMC64ImageFormat *forced = NULL; - int res; - - if (optForcedFormat >= 0) - { - forced = &dmC64ImageFormats[optForcedFormat]; - dmMsg(0,"Forced %s format image, type %d, %s\n", - forced->name, forced->type, forced->fext); - } - - res = dmC64DecodeBMP(&cimage, dataBuf, dataSize, optInSkip, optInSkip + 2, &cfmt, forced); - if (forced == NULL && cfmt != NULL) - { - dmMsg(1,"Probed %s format image, type %d, %s\n", - cfmt->name, cfmt->type, cfmt->fext); - } - - if (res == 0) - optInFormat = FFMT_BITMAP; - } - - if (optInFormat == FFMT_AUTO || optInFormat == FFMT_IMAGE) - { - DMImageFormat *ifmt = NULL; - int index; - dmMsg(4, "Trying to probe image formats.\n"); - if (dmImageProbeGeneric(dataBuf + optInSkip, dataSize - optInSkip, &ifmt, &index) > 0) - { - optInFormat = FFMT_IMAGE; - optInSubFormat = index; - dmMsg(2, "Probed %s format image.\n", ifmt->fext); - } - } - - if (optInFormat == FFMT_AUTO) - { - dmError("No input format specified, and could not be determined automatically.\n"); - exit(1); - } - - // Skip, if needed - if (fseek(inFile, optInSkip, SEEK_SET) != 0) - { - int res = dmGetErrno(); - dmError("Could not seek to file position %d (0x%x): %s\n", - optInSkip, optInSkip, dmErrorStr(res)); - goto error; - } - - int inFormat = dmGetConvFormat(optInFormat, optInSubFormat), - outFormat = dmGetConvFormat(optOutFormat, optOutSubFormat); - - if (inFormat != -1 && outFormat != -1) - { - char *inFmtName = convFormatList[inFormat].name, - *inFmtExt = convFormatList[inFormat].fext, - *outFmtName = convFormatList[outFormat].name, - *outFmtExt = convFormatList[outFormat].fext; - - if (optInFormat == FFMT_BITMAP) - inFmtExt = cfmt->name; - - dmMsg(1, "Attempting conversion %s (%s) -> %s (%s)\n", - inFmtName, inFmtExt, outFmtName, outFmtExt); - } - - switch (optInFormat) - { - case FFMT_SPRITE: - case FFMT_CHAR: - dmDumpSpritesAndChars(inFile); - break; - - case FFMT_BITMAP: - { - DMImage *outImage = NULL; - int res = DMERR_OK; - - if (optOutFilename == NULL) - { - dmError("Output filename not set, required for image formats.\n"); - goto error; - } - - switch (optOutFormat) - { - case FFMT_IMAGE: - res = dmC64ConvertBMP2Image(&outImage, &cimage, cfmt, TRUE); - - if (res != DMERR_OK || outImage == NULL) - { - dmError("Error in bitmap to image conversion.\n"); - goto error; - } - - res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); - break; - - - case FFMT_BITMAP: - res = dmWriteBitmap(optOutFilename, &cimage, optOutSubFormat, TRUE); - break; - - case FFMT_CHAR: - case FFMT_SPRITE: - res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor); - break; - - default: - dmError("Unsupported output format for bitmap/image conversion.\n"); - break; - } - - dmImageFree(outImage); - } - break; - - case FFMT_IMAGE: - { - DMImage *outImage = NULL; - int res = DMERR_OK; - - if (optOutFilename == NULL) - { - dmError("Output filename not set, required for image formats.\n"); - goto error; - } - - // Read input - DMImageFormat *ifmt = &dmImageFormatList[optInSubFormat]; - if (ifmt->readFILE != NULL) - res = ifmt->readFILE(inFile, &outImage); - else - dmError("Unsupported input image format for bitmap/image conversion.\n"); - - if (res != DMERR_OK || outImage == NULL) - break; - - switch (optOutFormat) - { - case FFMT_IMAGE: - res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); - break; - - case FFMT_CHAR: - case FFMT_SPRITE: - res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor); - break; - - default: - dmError("Unsupported output format for bitmap/image conversion.\n"); - break; - } - - dmImageFree(outImage); - } - break; - } - - fclose(inFile); - - dmFree(dataBuf); - exit(0); - return 0; - -error: - dmFree(dataBuf); - return -3; - exit(3); -}
--- a/utils/mod2wav.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,314 +0,0 @@ -/* - * mod2wav - Render XM/JSSMOD module to WAV waveform file - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2007 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include "jss.h" -#include "jssmod.h" -#include "jssmix.h" -#include "jssplr.h" -#include "dmlib.h" -#include "dmargs.h" -#include "dmwav.h" -#include "dmmutex.h" - - -char *optInFilename = NULL, *optOutFilename = NULL; -int optOutFormat = JSS_AUDIO_S16, - optOutChannels = 2, - optOutFreq = 44100, - optMuteOChannels = -1, - optStartOrder = -1; -BOOL optUsePlayTime = FALSE; -size_t optPlayTime; - - -DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 3, '1', "16bit", "16-bit output", OPT_NONE }, - { 4, '8', "8bit", "8-bit output", OPT_NONE }, - { 5, 'm', "mono", "Mono output", OPT_NONE }, - { 6, 's', "stereo", "Stereo output", OPT_NONE }, - { 7, 'f', "freq", "Output frequency", OPT_ARGREQ }, - { 8, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, - { 9, 'o', "order", "Start from order #", OPT_ARGREQ }, - { 10, 't', "time", "Play for # seconds", OPT_ARGREQ }, -// {10, 'l', "loop", "Loop for # times", OPT_ARGREQ }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - (void) optArg; - - switch (optN) - { - case 0: - dmPrintBanner(stdout, dmProgName, - "[options] [sourcefile] [destfile]"); - - dmArgsPrintHelp(stdout, optList, optListN); - exit(0); - break; - - case 2: - dmVerbosity++; - break; - - case 3: - optOutFormat = JSS_AUDIO_S16; - break; - - case 4: - optOutFormat = JSS_AUDIO_U8; - break; - - case 5: - optOutChannels = JSS_AUDIO_MONO; - break; - - case 6: - optOutChannels = JSS_AUDIO_STEREO; - break; - - case 7: - optOutFreq = atoi(optArg); - break; - - case 8: - optMuteOChannels = atoi(optArg); - break; - - case 9: - optStartOrder = atoi(optArg); - break; - - case 10: - optPlayTime = atoi(optArg); - optUsePlayTime = TRUE; - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - if (!optInFilename) - optInFilename = currArg; - else - if (!optOutFilename) - optOutFilename = currArg; - else - { - dmError("Too many filename arguments (only source and dest needed) '%s'\n", currArg); - return FALSE; - } - - return TRUE; -} - - -int main(int argc, char *argv[]) -{ - DMResource *inFile = NULL; - FILE *outFile = NULL; - JSSModule *mod = NULL; - JSSMixer *dev = NULL; - JSSPlayer *plr = NULL; - int result = -1; - size_t bufLen = 1024*4, dataTotal, dataWritten, sampSize; - Uint8 *mb = NULL; - - dmInitProg("mod2wav", "XM/JSSMOD to WAV renderer", "0.2", NULL, NULL); - dmVerbosity = 1; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Check arguments - if (optInFilename == NULL || optOutFilename == NULL) - { - dmError("Input or output file not specified. Try --help.\n"); - return 1; - } - - // Initialize miniJSS - jssInit(); - - // Open the source file - if ((inFile = dmf_create_stdio(optInFilename, "rb")) == NULL) - { - dmError("Error opening input file '%s', %d: %s\n", - optInFilename, errno, strerror(errno)); - return 1; - } - - // Read module file - fprintf(stderr, "Reading file: %s\n", optInFilename); -#ifdef JSS_SUP_XM - fprintf(stderr, "* Trying XM...\n"); - result = jssLoadXM(inFile, &mod); -#endif -#ifdef JSS_SUP_JSSMOD - if (result != 0) - { - size_t bufgot, bufsize = dmfsize(inFile); - Uint8 *buf = dmMalloc(bufsize); - dmfseek(inFile, 0L, SEEK_SET); - fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); - if ((bufgot = dmfread(buf, 1, bufsize, inFile)) != bufsize) - { - fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n", - bufgot, dmferror(inFile), dmErrorStr(dmferror(inFile))); - return 2; - } - result = jssLoadJSSMOD(buf, bufsize, &mod); - dmFree(buf); - } -#endif - dmf_close(inFile); - if (result != DMERR_OK) - { - dmError("Error loading module file, %d: %s\n", - result, dmErrorStr(result)); - return 3; - } - - // Try to convert it - if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK) - { - dmError("Could not convert module for playing, %d: %s\n", - result, dmErrorStr(result)); - return 3; - } - - // Open mixer - dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); - if (dev == NULL) - { - dmError("jvmInit() returned NULL\n"); - return 4; - } - - sampSize = jvmGetSampleSize(dev); - if ((mb = dmMalloc(bufLen * sampSize)) == NULL) - { - dmError("Could not allocate mixing buffer\n"); - return 5; - } - - dmMsg(1, "Using fmt=%d, bits=%d, channels=%d, freq=%d [%d / sample]\n", - optOutFormat, jvmGetSampleRes(dev), optOutChannels, optOutFreq, - sampSize); - - // Initialize player - if ((plr = jmpInit(dev)) == NULL) - { - dmError("jmpInit() returned NULL.\n"); - return 6; - } - - // Set callback - jvmSetCallback(dev, jmpExec, plr); - - // Initialize playing - jmpSetModule(plr, mod); - if (optStartOrder >= 0) - { - dmMsg(1, "Starting from song order #%d\n", optStartOrder); - } else - optStartOrder = 0; - - jmpPlayOrder(plr, optStartOrder); - jvmSetGlobalVol(dev, 150); - - if (optMuteOChannels > 0 && optMuteOChannels <= mod->nchannels) - { - int i; - for (i = 0; i < mod->nchannels; i++) - jvmMute(dev, i, TRUE); - jvmMute(dev, optMuteOChannels - 1, FALSE); - } - - // Open output file - if ((outFile = fopen(optOutFilename, "wb")) == NULL) - { - dmError("Error opening output file '%s'. (%s)\n", optInFilename, strerror(errno)); - return 7; - } - - // Write initial header - dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, 1024); - - // Render audio data and output to file - if (optUsePlayTime) - dmMsg(1, "Rendering module (%d seconds) ...\n", optPlayTime); - else - dmMsg(1, "Rendering module ...\n"); - - optPlayTime *= optOutFreq; - dataTotal = 0; - dataWritten = 1; - while (plr->isPlaying && dataWritten > 0) - { - size_t writeLen = bufLen; - if (optUsePlayTime && (writeLen + dataTotal) > optPlayTime) - writeLen = optPlayTime - dataTotal; - - if (writeLen > 0) - { - jvmRenderAudio(dev, mb, writeLen); -#if (SDL_BYTEORDER == SDL_BIG_ENDIAN) - jssEncodeSample16((Uint16 *)mb, writeLen * optOutChannels, jsampSwapEndianess); -#endif - dataWritten = fwrite(mb, sampSize, writeLen, outFile); - if (dataWritten < writeLen) - { - dmError("Error writing data!\n"); - fclose(outFile); - return 8; - } - dataTotal += dataWritten; - } - - if (optUsePlayTime && dataTotal >= optPlayTime) - break; - } - - // Write the correct header - if (fseek(outFile, 0L, SEEK_SET) != 0) - { - dmError("Error rewinding to header position!\n"); - return 9; - } - - dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, dataTotal); - - // Done! - fclose(outFile); - - jmpClose(plr); - jvmClose(dev); - jssFreeModule(mod); - jssClose(); - - dmMsg(1, "OK.\n"); - return 0; -}
--- a/utils/objlink.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,990 +0,0 @@ -/* - * objlink - Link files (RAW and PRG) into one PRG object - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2002-2012 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <errno.h> -#include "dmlib.h" -#include "dmargs.h" -#include "dmfile.h" -#include "dmmutex.h" - -#define MAX_FILENAMES (128) -#define MAX_MEMBLOCKS (128) - - -/* Typedefs - */ -typedef struct -{ - ssize_t start, end; // Start and end address - int type; // Type - char *name; // Name of the block - int placement; -} DMMemBlock; - -typedef struct -{ - char *name; // Description of memory model - char *desc; - ssize_t size; // Total addressable memory size - ssize_t nmemBlocks; // Defined memory areas - DMMemBlock memBlocks[MAX_MEMBLOCKS]; -} DMMemModel; - -typedef struct -{ - char *filename; - int type; - int placement; - ssize_t addr; -} DMSourceFile; - -// Source file type -enum -{ - STYPE_RAW = 1, - STYPE_PRG, - STYPE_PRGA -}; - -// How to determine block placement / address -enum -{ - PLACE_STATIC = 1, // Already known - PLACE_ARGUMENT, // Commandline argument - PLACE_FILE, // From file -}; - -enum -{ - FMT_GENERIC = 1, - FMT_PLAIN, - FMT_DECIMAL -}; - -enum -{ - MTYPE_NONE = 0, - MTYPE_ROM, // Hard ROM - MTYPE_ROM_WT, // Write to RAM through ROM - MTYPE_IO, // I/O lines - MTYPE_RES // RESERVED -}; - -enum -{ - LA_NONE = -2, - LA_AUTO = -1 -}; - -/* Memory models - */ -const DMMemModel memoryModels[] = { - { "C64 unrestricted", "$01 = $34", (64*1024), 0, { - { 0, 0, 0, NULL, 0 } - }}, - - { "C64 normal (IO+Basic+Kernal)", "$01 = $37", (64*1024), 3, { - { 0xA000, 0xBFFF, MTYPE_ROM_WT, "Basic ROM", PLACE_STATIC }, - { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, - { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, - }}, - - { "C64 modified (IO+Kernal)", "$01 = $36", (64*1024), 2, { - { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, - { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, - }}, - - { "C64 modified (IO only)", "$01 = $35", (64*1024), 1, { - { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, - }}, - - { "C64 modified (Char+Kernal+Basic)", "$01 = $33", (64*1024), 3, { - { 0xA000, 0xBFFF, MTYPE_ROM_WT, "Basic ROM", PLACE_STATIC }, - { 0xD000, 0xDFFF, MTYPE_ROM, "Char ROM", PLACE_STATIC }, - { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, - }}, - -/* - { "C64 normal", "$01 = $37", (64*1024), 0, { - { 0x0000, 0x0000, MTYPE_RAM, "" }, - }}, -*/ -}; - -static const int nmemoryModels = sizeof(memoryModels) / sizeof(memoryModels[0]); - - -/* Global variables - */ -int nsrcFiles = 0; // Number of source files -DMSourceFile srcFiles[MAX_FILENAMES]; // Source file names - -int nmemBlocks = 0; -DMMemBlock memBlocks[MAX_FILENAMES]; - -char *optLinkFileName = NULL; -int optLinkFileFormat = FMT_GENERIC; - -BOOL optDescribe = FALSE, - optAllowOverlap = FALSE; - -Uint32 optInitValue = 0; -int optInitValueType = 1; -ssize_t optCropStart, optCropEnd; -BOOL optCropOutput = FALSE; - -ssize_t optLoadAddress = LA_AUTO; - -int optMemModel = 0; -const DMMemModel *memModel = NULL; -Uint8 *memory = NULL; - -char *optDestName = NULL; - - -/* Arguments - */ -static DMOptArg optList[] = { - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'r', "input-raw", "RAW input: -r <file>:<addr>", OPT_ARGREQ }, - { 2, 'p', "input-prg", "PRG input: -p <file>[:<addr>]", OPT_ARGREQ }, - { 12, 's', "section", "Reserved section: -s <start>-<end>[,name] or <start>:<len>[,name]", OPT_ARGREQ }, - { 5, 'o', "output", "Specify output file, -o <file>", OPT_ARGREQ }, - { 6, 'O', "overlap", "Allow overlapping memory areas", OPT_NONE }, - { 7, 'm', "model", "Set memory model", OPT_ARGREQ }, - { 8, 'l', "link-file", "Output addresses and labels into file", OPT_ARGREQ }, - { 9, 'f', "format", "Format of link-file: (g)eneric, (p)lain, (d)ecimal", OPT_ARGREQ }, - { 10, 'i', "initvalue", "Initialize memory with: -i <byte/word/dword>:[bwd]", OPT_ARGREQ }, - { 11, 'd', "describe", "Output ASCII memory map description", OPT_NONE }, - { 13, 'c', "crop", "Crop output file to: -c <start>-<end> or <start>:<len>", OPT_ARGREQ }, - { 14, 'L', "load-address","Set output file load address (or 'none' for 'raw' output)", OPT_ARGREQ }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - int i; - - dmPrintBanner(stdout, dmProgName, "[options]"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf( - "\n" - "Each numeric argument can be prefixed with $ or 0x for hexadecimal values.\n" - "NOTICE! -p filename:<addr> will ignore load address and use <addr> instead!\n" - "\n" - "Available memory models:\n"); - - for (i = 0; i < nmemoryModels; i++) - { - const DMMemModel *m = &memoryModels[i]; - printf(" %d = %-40s [%s] (%d kB)\n", - i, m->name, m->desc, m->size / 1024); - } -} - - -off_t dmGetFileSize(FILE *f) -{ - off_t len, pos = ftell(f); - fseeko(f, 0, SEEK_END); - len = ftell(f); - fseek(f, pos, SEEK_SET); - return len; -} - - -/* Memory block handling - */ -void reserveMemBlock(ssize_t startAddr, ssize_t endAddr, const char *blockName, int blockType) -{ - if (startAddr > endAddr) - { - dmError("ERROR! Block '%s' has startAddr=$%.4x > endAddr=$%.4x!\n", - blockName, startAddr, endAddr); - exit(4); - } - - if (nmemBlocks < MAX_FILENAMES) - { - memBlocks[nmemBlocks].start = startAddr; - memBlocks[nmemBlocks].end = endAddr; - memBlocks[nmemBlocks].name = dm_strdup(blockName); - memBlocks[nmemBlocks].type = blockType; - nmemBlocks++; - } - else - { - dmError("Maximum number of memBlock definitions (%d) exceeded!\n", - MAX_FILENAMES); - exit(4); - } -} - - -int compareMemBlock(const void *cva, const void *cvb) -{ - const DMMemBlock *a = cva, *b = cvb; - return a->start - b->start; -} - - -BOOL dmParseSection(const char *arg, ssize_t *sectStart, ssize_t *sectEnd, char **sectName, BOOL canHasName) -{ - char sectMode, *sep, *str, *namesep; - ssize_t tmpi; - - // Define reserved section - // Create a copy of the argument - if ((str = dm_strdup(arg)) == NULL) - { - dmError("Could not allocate temporary string!\n"); - exit(128); - } - - // Get start address - if ((sep = strchr(str, '-')) == NULL && - (sep = strchr(str, ':')) == NULL) - { - dmError("Section definition '%s' invalid.\n", arg); - goto error; - } - sectMode = *sep; - *sep = 0; - - // Get value - if (!dmGetIntVal(str, sectStart)) - { - dmError("Section start address '%s' in '%s' invalid.\n", str, arg); - goto error; - } - - // Check for name - namesep = strchr(sep + 1, ','); - if (canHasName && namesep != NULL) - { - *namesep = 0; - namesep++; - if (*namesep == 0) - { - dmError("Section definition '%s' name is empty. Either specify name or leave it out.\n", - arg); - goto error; - } - *sectName = dm_strdup(namesep); - } - else - if (namesep != NULL) - { - dmError("Section definition does not allow a name, syntax error in '%s' at '%s'.\n", - arg, namesep); - goto error; - } - - // Get end address or length - if (!dmGetIntVal(sep + 1, &tmpi)) - { - dmError("Section %s '%s' in '%s' invalid.\n", - sectMode == '-' ? "end address" : "length", - sep + 1, arg); - goto error; - } - - if (sectMode == ':') - { - *sectEnd = *sectStart + tmpi - 1; - } - else - { - if (tmpi < *sectStart) - { - dmError("Section start address > end address in '%s'.\n", - arg); - goto error; - } - *sectEnd = tmpi; - } - - dmFree(str); - return TRUE; - -error: - dmFree(str); - return FALSE; -} - - -BOOL dmParseInputFile(char *arg, const int type1, const int type2, const char *desc, BOOL requireAddr) -{ - ssize_t tmpi = 0; - BOOL hasAddr = FALSE; - char *sep; - - if ((sep = strrchr(arg, ':')) != NULL) - { - *sep = 0; - if (!dmGetIntVal(sep + 1, &tmpi)) - { - dmError("Invalid %s address '%s' specified for '%s'.\n", - desc, sep + 1, arg); - return FALSE; - } - hasAddr = TRUE; - } - else - if (requireAddr) - { - dmError("No %s loading address specified for '%s'.\n", desc, arg); - return FALSE; - } - - srcFiles[nsrcFiles].filename = arg; - srcFiles[nsrcFiles].type = hasAddr ? type1 : type2; - srcFiles[nsrcFiles].addr = tmpi; - nsrcFiles++; - return TRUE; -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - char *p; - ssize_t tmpi; - - switch (optN) { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - // Add RAW - if (!dmParseInputFile(optArg, STYPE_RAW, STYPE_RAW, "RAW", TRUE)) - return FALSE; - break; - - case 2: - // Add PRG - if (!dmParseInputFile(optArg, STYPE_PRGA, STYPE_PRG, "PRG", FALSE)) - return FALSE; - break; - - case 5: - // Set output file name - optDestName = optArg; - break; - - case 6: - // Allow overlapping segments - optAllowOverlap = TRUE; - dmError("Warning, allowing overlapping data.\n"); - break; - - case 7: - // Set memory model - optMemModel = atoi(optArg); - if (optMemModel < 0 || optMemModel >= nmemoryModels) - { - dmError("Invalid memory model number %i!\n", optMemModel); - return FALSE; - } - break; - - case 8: - // Linker file - optLinkFileName = optArg; - break; - - case 9: - // Linker file format - switch (tolower(optArg[0])) - { - case 'g': - optLinkFileFormat = FMT_GENERIC; - break; - case 'p': - optLinkFileFormat = FMT_PLAIN; - break; - case 'd': - optLinkFileFormat = FMT_DECIMAL; - break; - - default: - dmError("Invalid/unknown linker file format '%s'!\n", - optArg); - return FALSE; - } - break; - - case 10: - // Initialization value - optInitValueType = 1; - if ((p = strrchr(optArg, ':')) != NULL) - { - *p = 0; - switch (tolower(p[1])) - { - case 'b': optInitValueType = 1; break; - case 'w': optInitValueType = 2; break; - case 'd': optInitValueType = 4; break; - default: - dmError("Invalid init value type '%c' specified for '%s'.\n", - p[1], optArg); - return FALSE; - } - } - if (!dmGetIntVal(optArg, &tmpi)) - { - dmError("Invalid initvalue '%s'.\n", optArg); - return FALSE; - } - optInitValue = tmpi; - break; - - case 11: - // Set describe mode - optDescribe = TRUE; - break; - - case 12: - { - char *sectName = "Clear"; - ssize_t sectStart, sectEnd, sectLen; - if (!dmParseSection(optArg, §Start, §End, §Name, TRUE)) - return FALSE; - - // Allocate memory block - sectLen = sectEnd - sectStart + 1; - dmMsg(1, "Reserve $%.4x - $%.4x ($%x, %d bytes) as '%s'\n", - sectStart, sectEnd, sectLen, sectLen, sectName); - - reserveMemBlock(sectStart, sectEnd, sectName, MTYPE_RES); - } - break; - - case 13: - { - size_t cropLen; - if (!dmParseSection(optArg, &optCropStart, &optCropEnd, NULL, FALSE)) - return FALSE; - - cropLen = optCropEnd - optCropEnd + 1; - dmMsg(1, "Cutting output to $%.4x - $%.4x ($%x, %d bytes)\n", - optCropStart, optCropEnd, cropLen, cropLen); - - optCropOutput = TRUE; - } - break; - - case 14: - // Set loading address - if (strcasecmp(optArg, "none") == 0) - optLoadAddress = LA_NONE; - else - { - if (!dmGetIntVal(optArg, &tmpi)) - { - dmError("Invalid loading address '%s'.\n", optArg); - return FALSE; - } - if (tmpi < 0 || tmpi >= 64*1024) - { - dmError("Invalid or insane loading address %d/$%x!\n", - tmpi); - return FALSE; - } - optLoadAddress = tmpi; - } - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -int dmLoadPRG(const char *filename, BOOL forceAddr, const ssize_t destAddr) -{ - FILE *f; - ssize_t dataSize, loadAddr, endAddr; - Uint16 tmpAddr; - - // Open the input file - if ((f = fopen(filename, "rb")) == NULL) - { - dmError("Error opening input file '%s' (%s).\n", - filename, strerror(errno)); - return 1; - } - - // Get filesize - if ((dataSize = dmGetFileSize(f) - 2) < 0) - { - dmError("Error getting file size for '%s'.\n", filename); - return 6; - } - - // Get loading address - if (!dm_fread_le16(f, &tmpAddr)) - { - dmError("Error reading input file '%s' (%s).\n", - filename, strerror(errno)); - return 2; - } - - // Show information - loadAddr = forceAddr ? destAddr : tmpAddr; - endAddr = loadAddr + dataSize - 1; - - dmPrint(1, "* Loading '%s', %s at $%.4x-$%.4x", - filename, forceAddr ? "PRGA" : "PRG", loadAddr, endAddr); - - if (endAddr >= memModel->size) - { - dmPrint(1, " .. Does not fit into the memory!\n"); - return 5; - } - - // Load data - if (fread(&memory[loadAddr], dataSize, 1, f) < 1) - { - dmPrint(1, " .. Error: %s.\n", - strerror(errno)); - return 4; - } - - dmPrint(1, " .. OK\n"); - - // Add to list of blocks - reserveMemBlock(loadAddr, endAddr, filename, MTYPE_RES); - - return 0; -} - - -int dmLoadRAW(const char *filename, const ssize_t destAddr) -{ - FILE *f; - ssize_t dataSize, endAddr; - - // Open the input file - if ((f = fopen(filename, "rb")) == NULL) - { - dmError("Error opening input file '%s' (%s).\n", - filename, strerror(errno)); - return 1; - } - - // Get filesize - if ((dataSize = dmGetFileSize(f)) < 0) - { - dmError("Error getting file size for '%s'.\n", filename); - return 6; - } - - // Show information - endAddr = destAddr + dataSize - 1; - dmPrint(1, "* Loading '%s', RAW at $%.4x-$%.4x", - filename, destAddr, endAddr); - - if (endAddr >= memModel->size) - { - dmPrint(1, " .. Does not fit into the memory!\n"); - return 5; - } - - // Load data - if (fread(&memory[destAddr], dataSize, 1, f) < 1) - { - dmPrint(1, " .. Error: %s.\n", - strerror(errno)); - return 4; - } - - dmPrint(1, " .. OK\n"); - - // Add info to list - reserveMemBlock(destAddr, endAddr, filename, MTYPE_RES); - - return 0; -} - - -int outputLinkData(FILE *dfile, const char *blockName, const int blockStart, const int blockEnd) -{ - char *tmpStr, *s, *t; - int blockSize; - - blockSize = (blockEnd - blockStart + 1); - - // Create label name from filename - tmpStr = dm_strdup(blockName); - if (tmpStr == NULL) - { - dmError("Could not allocate memory for string '%s'!\n", - blockName); - return -1; - } - - if ((t = strrchr(tmpStr, '/'))) - s = (t + 1); - else if ((t = strrchr(tmpStr, '\\'))) - s = (t + 1); - else - s = tmpStr; - - if ((t = strrchr(s, '.'))) - *t = 0; - - for (t = s; *t; t++) - { - if (!isalnum(*t)) - *t = '_'; - } - - // Print the label line - switch (optLinkFileFormat) - { - case FMT_PLAIN: - fprintf(dfile, "%s = $%.4x\n", tmpStr, blockStart); - break; - - case FMT_DECIMAL: - fprintf(dfile, "%s = %d\n", tmpStr, blockStart); - break; - - case FMT_GENERIC: - default: - fprintf(dfile, "; %s ($%.4x - $%.4x, %d/$%x bytes)\n", - blockName, blockStart, blockEnd, blockSize, blockSize); - fprintf(dfile, "%s = $%.4x\n", s, blockStart); - break; - } - - dmFree(tmpStr); - return 0; -} - - -/* Print out an ASCII presentation of memory map - */ -void memPrintLine(FILE *f) -{ - fprintf(f, " +------------------------------------------+\n"); -} - -void memPrintEmpty(FILE *f, ssize_t n) -{ - ssize_t i; - for (i = 0; i < n; i++) - fprintf(f, " | |\n"); -} - -void dmDescribeMemory(FILE *f) -{ - int i; - DMMemBlock *prev = NULL; - - memPrintLine(f); - - for (i = 0; i < nmemBlocks; i++) - { - DMMemBlock *curr = &memBlocks[i]; - char desc[512], *s; - ssize_t siz, kz; - - // Check for empty, unreserved areas - siz = (curr->start - 1) - (prev->end + 1) + 1; - if (prev != NULL && siz > 1) - { - kz = siz / (1024 * 2); - - if (kz > 1) memPrintEmpty(f, kz); - - snprintf(desc, sizeof(desc), "EMPTY (%d)", siz); - fprintf(f, "$%.4x - $%.4x | %-40s |\n", prev->end + 1, curr->start - 1, desc); - - if (kz > 1) memPrintEmpty(f, kz); - memPrintLine(f); - } - prev = curr; - - // Print current block - switch (curr->type) - { - case MTYPE_NONE: s = "N/A (NC)"; break; - case MTYPE_ROM: s = "ROM"; break; - case MTYPE_ROM_WT: s = "ROM/WT"; break; - case MTYPE_IO: s = "I/O"; break; - case MTYPE_RES: s = "RSVD"; break; - default: s = "????"; break; - } - - siz = curr->end - curr->start + 1; - kz = siz / (1024 * 2); - - if (kz > 1) memPrintEmpty(f, kz); - snprintf(desc, sizeof(desc), "%s (%s, %d)", curr->name, s, siz); - fprintf(f, "$%.4x - $%.4x | %-40s |\n", curr->start, curr->end, desc); - if (kz > 1) memPrintEmpty(f, kz); - memPrintLine(f); - - } - - fprintf(f, - "\n" - "NC = Not Connected\n" - "RSVD = Reserved\n" - "ROM/WT = RAM under 'write-through' ROM\n" - "\n" - ); -} - - -/* - * The main program - */ -int main(int argc, char *argv[]) -{ - FILE *dfile = NULL; - BOOL hasOverlaps; - int i, j; - ssize_t startAddr, endAddr, dataSize, totalSize; - - dmInitProg("objlink", "Simple file-linker", "0.80", NULL, NULL); - dmVerbosity = 1; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, NULL, TRUE)) - exit(1); - - if (nsrcFiles < 1) - { - dmError("Nothing to do. (try --help)\n"); - exit(0); - } - - // Allocate memory - memModel = &memoryModels[optMemModel]; - dmMsg(1, "Using memory model #%d '%s', %d bytes.\n", - optMemModel, memModel->name, memModel->size); - - memory = (Uint8 *) dmMalloc(memModel->size + 32); - if (memory == NULL) - { - dmError("Could not allocate memory.\n"); - exit(2); - } - - // Initialize memory - dmMsg(1, "Initializing memory with "); - - if (optInitValueType == 1 || optInitValue <= 0xff) - { - dmPrint(1, "BYTE 0x%.2x\n", optInitValue); - memset(memory, optInitValue, memModel->size); - } - else - if (optInitValueType == 2 || optInitValue <= 0xffff) - { - uint16_t *mp = (uint16_t *) memory; - dmPrint(1, "WORD 0x%.4x\n", optInitValue); - for (i = memModel->size / sizeof(*mp); i; i--) - { - *mp++ = optInitValue; - } - } - else - { - Uint32 *mp = (Uint32 *) memory; - dmPrint(1, "DWORD 0x%.8x\n", optInitValue); - for (i = memModel->size / sizeof(*mp); i; i--) - { - *mp++ = optInitValue; - } - } - - // Load the datafiles - for (i = 0; i < nsrcFiles; i++) - switch (srcFiles[i].type) - { - case STYPE_RAW: - dmLoadRAW(srcFiles[i].filename, srcFiles[i].addr); - break; - - case STYPE_PRG: - dmLoadPRG(srcFiles[i].filename, FALSE, 0); - break; - - case STYPE_PRGA: - dmLoadPRG(srcFiles[i].filename, TRUE, srcFiles[i].addr); - break; - } - - // Add memory model blocks - dmMsg(1, "Applying memory model restrictions...\n"); - for (i = 0; i < memModel->nmemBlocks; i++) - { - reserveMemBlock( - memModel->memBlocks[i].start, - memModel->memBlocks[i].end, - memModel->memBlocks[i].name, - memModel->memBlocks[i].type); - } - - // Sort the blocks - qsort(memBlocks, nmemBlocks, sizeof(DMMemBlock), compareMemBlock); - - // Check for overlapping conflicts - hasOverlaps = FALSE; - for (i = 0; i < nmemBlocks; i++) - for (j = 0; j < nmemBlocks; j++) - if (j != i && memBlocks[i].type == MTYPE_RES) - { - DMMemBlock *mbi = &memBlocks[i], - *mbj = &memBlocks[j]; - - // Check for per-file conflicts - if ((mbj->start >= mbi->start && mbj->start <= mbi->end) || - (mbj->end >= mbi->start && mbj->end <= mbi->end)) - { - dmPrint(1, "* '%s' and '%s' overlap ($%.4x-$%.4x vs $%.4x-$%.4x)\n", - mbi->name, mbj->name, mbi->start, - mbi->end, mbj->start, mbj->end); - hasOverlaps = TRUE; - } - } - - if (!optAllowOverlap && hasOverlaps) - { - dmError("Error occured, overlaps not allowed.\n"); - exit(5); - } - - // Find out start and end-addresses - startAddr = memModel->size; - totalSize = endAddr = 0; - for (i = 0; i < nmemBlocks; i++) - { - DMMemBlock *mbi = &memBlocks[i]; - if (mbi->type == MTYPE_RES) - { - if (mbi->start < startAddr) - startAddr = mbi->start; - - if (mbi->end > endAddr) - endAddr = mbi->end; - - totalSize += (mbi->end - mbi->start + 1); - } - } - - if (startAddr >= memModel->size || endAddr < startAddr) - { - dmError("Invalid saveblock addresses (start=$%.4x, end=$%.4x)!\n", startAddr, endAddr); - exit(8); - } - - // Output linkfile - if (optLinkFileName) - { - dmMsg(1, "Writing linkfile to '%s'\n", optLinkFileName); - if ((dfile = fopen(optLinkFileName, "wb")) == NULL) - { - dmError("Error creating file '%s' (%s).\n", optLinkFileName, strerror(errno)); - exit(1); - } - - switch (optLinkFileFormat) - { - case FMT_GENERIC: - default: - fprintf(dfile, "; Definitions generated by %s v%s\n", - dmProgName, dmProgVersion); - break; - } - - for (i = 0; i < nmemBlocks; i++) - { - DMMemBlock *mbi = &memBlocks[i]; - outputLinkData(dfile, mbi->name, mbi->start, mbi->end); - } - - fclose(dfile); - } - - // Show some information - if (optCropOutput) - { - startAddr = optCropStart; - endAddr = optCropEnd; - } - - dataSize = endAddr - startAddr + 1; - - if (dataSize - totalSize > 0) - { - dmMsg(1, "Total of %d/$%x bytes unused(?) areas.\n", - dataSize - totalSize, dataSize - totalSize); - } - - dmMsg(1, "Writing $%.4x - $%.4x (%d/$%x bytes) ", - startAddr, endAddr, dataSize, dataSize); - - - // Open the destination file - if (optDestName == NULL) - { - dfile = stdout; - dmPrint(1, "...\n"); - } - else if ((dfile = fopen(optDestName, "wb")) == NULL) - { - dmError("Error creating output file '%s' (%s).\n", optDestName, strerror(errno)); - exit(1); - } - else - dmPrint(1, "to '%s'\n", optDestName); - - // Save loading address - if (optLoadAddress >= 0) - { - dmMsg(1, "Using specified loading address $%.4x\n", optLoadAddress); - dm_fwrite_le16(dfile, optLoadAddress); - } - else - if (optLoadAddress == LA_AUTO) - { - dmMsg(1, "Using automatic loading address $%.4x\n", startAddr); - dm_fwrite_le16(dfile, startAddr); - } - else - { - dmMsg(1, "Writing raw output, without loading address.\n"); - } - - // Save the data - if (fwrite(&memory[startAddr], dataSize, 1, dfile) < 1) - { - dmError("Error writing to file (%s)\n", strerror(errno)); - } - - fclose(dfile); - - // Describe - if (optDescribe) - dmDescribeMemory(stdout); - - exit(0); - return 0; -}
--- a/utils/packed.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,465 +0,0 @@ -/* - * PACKed - PACKfile EDitor - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2011 Tecnic Software productions (TNSP) - */ -#include "dmlib.h" -#include "dmargs.h" -#include "dmpack.h" -#include "dmpackutil.h" -#include "dmres.h" -#include "dmmutex.h" -#include <errno.h> - -#define SET_MAX_FILES (4096) -#define SET_DEFAULT_PACK "data.pak" - -enum -{ - CMD_NONE = 0, - CMD_CREATE, - CMD_ADD, - CMD_LIST, - CMD_EXTRACT -} DCOMMAND; - -enum -{ - PACK_EXTRACTED = 0x0001, -}; - -int nsrcFilenames = 0; -char * srcFilenames[SET_MAX_FILES]; -char * optPackFilename = NULL; -BOOL optCompress = TRUE; -int optCommand = CMD_NONE; -int optDefResFlags = 0; - - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'p', "pack", "Set pack filename (default: " SET_DEFAULT_PACK ")", OPT_ARGREQ }, - { 2, 'c', "create", "Create and add files to PACK", OPT_NONE }, - { 3, 'a', "add", "Add files to PACK", OPT_NONE }, - { 4, 'l', "list", "List files in PACK", OPT_NONE }, - { 5, 'e', "extract", "Extract files from PACK", OPT_NONE }, - { 6, 'n', "nocompress", "No compression", OPT_NONE }, - { 7, 'v', "verbose", "Increase verbosity", OPT_NONE }, - { 8, 'f', "resflags", "Set default resource flags (-f 0xff)", OPT_ARGREQ }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, "[options] [-p <packfilename>] [filename[s]]"); - dmArgsPrintHelp(stdout, optList, optListN); - fprintf(stdout, - "\n" - "Examples:\n" - "$ %s -p test.pak -l -- list files in test.pak\n" - "$ %s -a foobar.jpg -- add foobar.jpg in " SET_DEFAULT_PACK "\n" - "$ %s -x foobar.jpg -- extract foobar.jpg from " SET_DEFAULT_PACK "\n", - dmProgName, dmProgName, dmProgName); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - (void) optArg; - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - optPackFilename = optArg; - break; - case 2: - optCommand = CMD_CREATE; - break; - case 3: - optCommand = CMD_ADD; - break; - case 4: - optCommand = CMD_LIST; - break; - case 5: - optCommand = CMD_EXTRACT; - break; - - case 6: - optCompress = FALSE; - break; - - case 7: - dmVerbosity++; - break; - - case 8: - { - int i; - if (!dmGetIntVal(optArg, &i)) - { - dmError("Invalid flags value '%s'.\n", optArg); - return FALSE; - } - optDefResFlags = i; - } - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - if (nsrcFilenames < SET_MAX_FILES) - { - srcFilenames[nsrcFilenames] = currArg; - nsrcFilenames++; - } - else - { - dmError("Maximum number of input files (%d) exceeded!\n", - SET_MAX_FILES); - return FALSE; - } - return TRUE; -} - - -/* Compare a string to a pattern. Case-SENSITIVE version. - * The matching pattern can consist of any normal characters plus - * wildcards ? and *. "?" matches any character and "*" matches - * any number of characters. - */ -BOOL dm_strmatch(const char *str, const char *pattern) -{ - BOOL didMatch = TRUE, isAnyMode = FALSE, isEnd = FALSE; - const char *tmpPattern = NULL; - - // Check given pattern and string - if (str == NULL || pattern == NULL) - return FALSE; - - // Start comparision - do { - didMatch = FALSE; - switch (*pattern) - { - case '?': - // Any single character matches - if (*str) - { - didMatch = TRUE; - pattern++; - str++; - } - break; - - case '*': - didMatch = TRUE; - pattern++; - if (!*pattern) - isEnd = TRUE; - isAnyMode = TRUE; - tmpPattern = pattern; - break; - - case 0: - if (isAnyMode) - { - if (*str) - str++; - else - isEnd = TRUE; - } - else - { - if (*str) - { - if (tmpPattern) - { - isAnyMode = TRUE; - pattern = tmpPattern; - } - else - didMatch = FALSE; - } - else - isEnd = TRUE; - } - break; - default: - if (isAnyMode) - { - if (*pattern == *str) - { - isAnyMode = FALSE; - didMatch = TRUE; - } - else - { - if (*str) - { - didMatch = TRUE; - str++; - } - } - } - else - { - if (*pattern == *str) - { - didMatch = TRUE; - if (*pattern) - pattern++; - if (*str) - str++; - } - else - { - if (tmpPattern) - { - didMatch = TRUE; - isAnyMode = TRUE; - pattern = tmpPattern; - } - } - } - - if (!*str && !*pattern) - isEnd = TRUE; - break; - - } // switch - - } while (didMatch && !isEnd); - - return didMatch; -} - - -int dmAddFileToPack(DMPackFile *pack, const char *filename, int compression, int resFlags) -{ - DMPackEntry *node; - int res = dm_pack_add_file(pack, filename, compression, resFlags, &node); - - if (res != DMERR_OK) - { - dmPrint(1, "%-32s [ERROR:%d]\n", - filename, res); - } - else - { - char tmp[16]; - dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); - dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=%s]\n", - filename, node->filename, - node->size, node->length, node->offset, - tmp); - } - - return res; -} - - -int main(int argc, char *argv[]) -{ - int i, res = 0; - DMPackFile *pack = NULL; - -#ifndef __WIN32 - stderr = stdout; -#endif - - // Parse arguments - dmInitProg("packed", "Pack File Editor", "0.4", NULL, NULL); - dmVerbosity = 1; - - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Check PACK filename - if (optPackFilename == NULL) - optPackFilename = SET_DEFAULT_PACK; - - if (optCommand == CMD_NONE) - { - argShowHelp(); - dmError("Nothing to do.\n"); - exit(0); - return 0; - } - - dmMsg(1, "Processing %s ...\n", optPackFilename); - - // Execute command - switch (optCommand) - { - case CMD_CREATE: - case CMD_ADD: - switch (optCommand) - { - case CMD_CREATE: - dmMsg(1, "Creating new PACK\n"); - res = dm_pack_create(optPackFilename, &pack); - break; - - case CMD_ADD: - dmMsg(1, "Opening existing PACK\n"); - res = dm_pack_open(optPackFilename, &pack, FALSE); - break; - } - - // Add files into PACK - if (res == DMERR_OK) - { - dmMsg(1, "Adding %d files...\n", nsrcFilenames); - - for (i = 0; i < nsrcFilenames; i++) - { - // Handle resource definition files - if (srcFilenames[i][0] == '@') - { - } - else - { - dmAddFileToPack(pack, srcFilenames[i], optCompress, optDefResFlags); - } - } - - dmMsg(1, "w=%d\n", dm_pack_write(pack)); - dmMsg(1, "c=%d\n", dm_pack_close(pack)); - } - else - { - dmError("Could not open packfile, error #%d: %s\n", res, - dmErrorStr(res)); - } - break; - - case CMD_LIST: - // List files in PACK - res = dm_pack_open(optPackFilename, &pack, TRUE); - if (res == DMERR_OK) - { - DMPackEntry *node; - for (i = 0, node = pack->entries; node; i++) - node = node->next; - dmMsg(1, "%d files total\n", i); - - dmPrint(0, "%-32s | %8s | %8s | %8s | %s\n", - "Name", "Size", "CSize", "Offset", "ResFlags"); - - for (node = pack->entries; node != NULL; node = node->next) - { - BOOL match; - - // Check for matches - if (nsrcFilenames > 0) - { - match = FALSE; - for (i = 0; i < nsrcFilenames && !match; i++) - { - match = dm_strmatch(node->filename, srcFilenames[i]); - } - } - else - match = TRUE; - - if (match) - { - char flags[16]; - dmres_flags_to_symbolic(flags, sizeof(flags), node->resFlags); - - dmPrint(0, "%-32s | %8d | %8d | %08x | %s\n", - node->filename, node->size, node->length, - node->offset, flags); - } - } - - dmMsg(1, "c=%d\n", dm_pack_close(pack)); - } - else - dmError("Could not open packfile, error #%d: %s\n", res, - dmErrorStr(res)); - break; - - case CMD_EXTRACT: - // Extract files from PACK - res = dm_pack_open(optPackFilename, &pack, TRUE); - if (res == DMERR_OK) - { - DMPackEntry *node; - FILE *resFile = fopen(DMRES_RES_FILE, "w"); - if (resFile == NULL) - { - dmError("Could not create resource output file '%s' #%d: %s\n", - DMRES_RES_FILE, errno, strerror(errno)); - } - - for (node = pack->entries; node != NULL; node = node->next) - { - BOOL match; - - // Check for matches - if (nsrcFilenames > 0) - { - match = FALSE; - for (i = 0; (i < nsrcFilenames) && !match; i++) - { - match = dm_strmatch(node->filename, srcFilenames[i]); - } - } - else - match = TRUE; - - if (match && (node->privFlags & PACK_EXTRACTED) == 0) - { - char tmp[16]; - - // Mark as done - node->privFlags |= PACK_EXTRACTED; - - // Print one entry - dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); - dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=%s]\n", - node->filename, node->size, node->length, - node->offset, tmp); - - dm_pack_extract_file(pack, node); - - if (resFile != NULL) - { - fprintf(resFile, - "%s|%s\n", node->filename, tmp); - } - } - } - - dmMsg(1, "c=%d\n", dm_pack_close(pack)); - - if (resFile != NULL) - fclose(resFile); - } - else - dmError("Could not open packfile, error #%d: %s\n", res, - dmErrorStr(res)); - break; - - } - - return 0; -}
--- a/utils/ppl.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,932 +0,0 @@ -/* - * Cyrbe Pasci Player - A simple SDL-based UI for XM module playing - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2012 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <SDL.h> -#include "dmlib.h" - -#include "jss.h" -#include "jssmod.h" -#include "jssmix.h" -#include "jssplr.h" - -#include "dmargs.h" -#include "dmimage.h" -#include "dmtext.h" - -#include "setupfont.h" - - -struct -{ - BOOL exitFlag; - SDL_Surface *screen; - SDL_Event event; - int optScrWidth, optScrHeight, optVFlags, optScrDepth; - - int actChannel; - BOOL pauseFlag; - - JSSModule *mod; - JSSMixer *dev; - JSSPlayer *plr; - SDL_AudioSpec afmt; -} engine; - -struct -{ - Uint32 boxBg, inboxBg, box1, box2, viewDiv, activeRow, activeChannel; -} col; - - -DMBitmapFont *font = NULL; - -char *optFilename = NULL; -int optOutFormat = JSS_AUDIO_S16, - optOutChannels = 2, - optOutFreq = 48000, - optMuteOChannels = -1, - optStartOrder = 0; -BOOL optUsePlayTime = FALSE; -size_t optPlayTime; - - -DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 2, 0, "fs", "Fullscreen", OPT_NONE }, - { 3, 'w', "window", "Initial window size/resolution -w 640x480", OPT_ARGREQ }, - - { 4, '1', "16bit", "16-bit output", OPT_NONE }, - { 5, '8', "8bit", "8-bit output", OPT_NONE }, - { 6, 'm', "mono", "Mono output", OPT_NONE }, - { 7, 's', "stereo", "Stereo output", OPT_NONE }, - { 8, 'f', "freq", "Output frequency", OPT_ARGREQ }, - - { 9, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, - { 10, 'o', "order", "Start from order #", OPT_ARGREQ }, - { 11, 't', "time", "Play for # seconds", OPT_ARGREQ }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, "[options] <module>"); - dmArgsPrintHelp(stdout, optList, optListN); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - dmVerbosity++; - break; - - case 2: - engine.optVFlags |= SDL_FULLSCREEN; - break; - - case 3: - { - int w, h; - if (sscanf(optArg, "%dx%d", &w, &h) == 2) - { - if (w < 320 || h < 200 || w > 3200 || h > 3200) - { - dmError("Invalid width or height: %d x %d\n", w, h); - return FALSE; - } - engine.optScrWidth = w; - engine.optScrHeight = h; - } - else - { - dmError("Invalid size argument '%s'.\n", optArg); - return FALSE; - } - } - break; - - case 4: - optOutFormat = JSS_AUDIO_S16; - break; - - case 5: - optOutFormat = JSS_AUDIO_U8; - break; - - case 6: - optOutChannels = JSS_AUDIO_MONO; - break; - - case 7: - optOutChannels = JSS_AUDIO_STEREO; - break; - - case 8: - optOutFreq = atoi(optArg); - break; - - case 9: - optMuteOChannels = atoi(optArg); - break; - - case 10: - optStartOrder = atoi(optArg); - break; - - case 11: - optPlayTime = atoi(optArg); - optUsePlayTime = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - if (!optFilename) - optFilename = currArg; - else - { - dmError("Too many filename arguments '%s'\n", currArg); - return FALSE; - } - - return TRUE; -} - - -void dmDrawBMTextConstQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt) -{ - const char *ptr = fmt; - DMUnscaledBlitFunc blit = NULL; - - while (*ptr) - { - int ch = *ptr++; - SDL_Surface *glyph; - - if (ch == '_') - { - xc += 4; - continue; - } - - if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL) - { - if (blit == NULL) - blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode); - - blit(glyph, xc, yc, screen); - xc += font->width; - } - else - xc += font->width; - } -} - - -void dmDrawBMTextVAQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, va_list ap) -{ - char tmp[512]; - vsnprintf(tmp, sizeof(tmp), fmt, ap); - dmDrawBMTextConstQ(screen, font, mode, xc, yc, tmp); -} - - -void dmDrawBMTextQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - dmDrawBMTextVAQ(screen, font, mode, xc, yc, fmt, ap); - va_end(ap); -} - - -Uint32 dmCol(float r, float g, float b) -{ - return dmMapRGB(engine.screen, 255.0f * r, 255.0f * g, 255.0f * b); -} - - -BOOL dmInitializeVideo() -{ - SDL_FreeSurface(engine.screen); - - engine.screen = SDL_SetVideoMode( - engine.optScrWidth, engine.optScrHeight, engine.optScrDepth, - engine.optVFlags | SDL_RESIZABLE | SDL_SWSURFACE | SDL_HWPALETTE); - - if (engine.screen == NULL) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - return FALSE; - } - - col.inboxBg = dmCol(0.6, 0.5, 0.2); - col.boxBg = dmCol(0.7, 0.6, 0.3); - col.box1 = dmCol(1.0, 0.9, 0.6); - col.box2 = dmCol(0.3, 0.3, 0.15); - col.viewDiv = dmCol(0,0,0); - col.activeRow = dmCol(0.5,0.4,0.1); - col.activeChannel = dmCol(0.6, 0.8, 0.2); - - return TRUE; -} - - -void dmDisplayChn(SDL_Surface *screen, int x0, int y0, int x1, int y1, int nchannel, JSSChannel *chn) -{ - int yh = y1 - y0 - 2; - if (yh < 10 || chn == NULL) - return; - - int xc, ym = y0 + (y1 - y0) / 2, vol = FP_GETH(chn->chVolume); - int pitch = screen->pitch / sizeof(Uint32); - int len = FP_GETH(chn->chSize); - DMFixedPoint offs = chn->chPos; - Uint32 coln = dmCol(0.0, 0.8, 0.0), colx = dmCol(1.0, 0, 0); - Uint32 *pix = screen->pixels; - Sint16 *data = chn->chData; - - - dmFillBox3D(screen, x0, y0, x1, y1, - (chn->chMute ? dmCol(0.3,0.1,0.1) : dmCol(0,0,0)), - nchannel == engine.actChannel ? colx : col.box2, - nchannel == engine.actChannel ? colx : col.box1); - - if (chn->chData == NULL || !chn->chPlaying) - return; - - if (chn->chDirection) - { - for (xc = x0 + 1; xc < x1 - 1; xc++) - { - if (FP_GETH(offs) >= len) - break; - Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255); - pix[xc + val * pitch] = coln; - FP_ADD(offs, chn->chDeltaO); - } - } - else - { - for (xc = x0 + 1; xc < x1 - 1; xc++) - { - if (FP_GETH(offs) < 0) - break; - Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255); - pix[xc + val * pitch] = coln; - FP_SUB(offs, chn->chDeltaO); - } - } -} - - -void dmDisplayChannels(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSMixer *dev) -{ - int nchannel, qx, qy, - qwidth = x1 - x0, - qheight = y1 - y0, - nwidth = jsetNChannels, - nheight = 1; - - if (qheight < 40) - return; - - while (qwidth / nwidth <= 60 && qheight / nheight >= 40) - { - nheight++; - nwidth /= nheight; - } - -// fprintf(stderr, "%d x %d\n", nwidth, nheight); - - if (qheight / nheight <= 40) - { - nwidth = qwidth / 60; - nheight = qheight / 40; - } - - qwidth /= nwidth; - qheight /= nheight; - - for (nchannel = qy = 0; qy < nheight && nchannel < jsetNChannels; qy++) - { - for (qx = 0; qx < nwidth && nchannel < jsetNChannels; qx++) - { - int xc = x0 + qx * qwidth, - yc = y0 + qy * qheight; - - dmDisplayChn(screen, xc + 1, yc + 1, - xc + qwidth - 1, yc + qheight - 1, - nchannel, &dev->channels[nchannel]); - - nchannel++; - } - } -} - - -static const char patNoteTable[12][3] = -{ - "C-", "C#", "D-", - "D#", "E-", "F-", - "F#", "G-", "G#", - "A-", "A#", "B-" -}; - - -#define jmpNMODEffectTable (36) -static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -static const char jmpHexTab[16] = "0123456789ABCDEF"; - -static inline char dmHexVal(int v) -{ - return jmpHexTab[v & 15]; -} - -void dmPrintNote(SDL_Surface *screen, int xc, int yc, JSSNote *n) -{ - char text[32]; - char *ptr = text; - - switch (n->note) - { - case jsetNotSet: - strcpy(ptr, "..._"); - break; - case jsetNoteOff: - strcpy(ptr, "===_"); - break; - default: - sprintf(ptr, "%s%i_", - patNoteTable[n->note % 12], - n->note / 12); - break; - } - - ptr += 4; - - if (n->instrument != jsetNotSet) - { - int v = n->instrument + 1; - *ptr++ = dmHexVal(v >> 4); - *ptr++ = dmHexVal(v); - } - else - { - *ptr++ = '.'; - *ptr++ = '.'; - } - *ptr++ = '_'; - - if (n->volume == jsetNotSet) - { - *ptr++ = '.'; - *ptr++ = '.'; - } - else - if (n->volume >= 0x00 && n->volume <= 0x40) - { - *ptr++ = dmHexVal(n->volume >> 4); - *ptr++ = dmHexVal(n->volume); - } - else - { - char c; - switch (n->volume & 0xf0) - { - case 0x50: c = '-'; break; - case 0x60: c = '+'; break; - case 0x70: c = '/'; break; - case 0x80: c = '\\'; break; - case 0x90: c = 'S'; break; - case 0xa0: c = 'V'; break; - case 0xb0: c = 'P'; break; - case 0xc0: c = '<'; break; - case 0xd0: c = '>'; break; - case 0xe0: c = 'M'; break; - default: c = '?'; break; - } - *ptr++ = c; - *ptr++ = dmHexVal(n->volume); - } - *ptr++ = '_'; - - if (n->effect >= 0 && n->effect < jmpNMODEffectTable) - *ptr++ = jmpMODEffectTable[n->effect]; - else - *ptr++ = (n->effect == jsetNotSet ? '.' : '?'); - - if (n->param != jsetNotSet) - { - *ptr++ = dmHexVal(n->param >> 4); - *ptr++ = dmHexVal(n->param); - } - else - { - *ptr++ = '.'; - *ptr++ = '.'; - } - - *ptr = 0; - - dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, xc, yc, text); -} - - -void dmDisplayPattern(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSPattern *pat, int row) -{ - int cwidth = (font->width * 10 + 3 * 4 + 5), - lwidth = 6 + font->width * 3, - qy0 = y0 + font->height + 2, - qy1 = y1 - font->height - 2, - qwidth = ((x1 - x0 - lwidth) / cwidth), - qheight = ((qy1 - qy0 - 4) / (font->height + 1)), - nrow, nchannel, yc, choffs, - midrow = qheight / 2; - - if (engine.actChannel < qwidth / 2) - choffs = 0; - else - if (engine.actChannel >= pat->nchannels - qwidth/2) - choffs = pat->nchannels - qwidth; - else - choffs = engine.actChannel - qwidth/2; - - dmDrawBox3D(screen, x0 + lwidth, qy0, x1, qy1, col.box2, col.box1); - - for (nchannel = 0; nchannel < qwidth; nchannel++) - { - int bx0 = x0 + lwidth + 1 + nchannel * cwidth, - bx1 = bx0 + cwidth; - - if (engine.actChannel == nchannel + choffs) - { - dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.activeChannel); - } - else - { - dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.inboxBg); - } - } - - yc = qy0 + 2 + (font->height + 1) * midrow; - dmFillRect(screen, x0 + lwidth + 1, yc - 1, x1 - 1, yc + font->height, col.activeRow); - - for (nchannel = 0; nchannel < qwidth; nchannel++) - { - int bx0 = x0 + lwidth + 1 + nchannel * cwidth, - bx1 = bx0 + cwidth; - - dmDrawVLine(screen, qy0 + 1, qy1 - 1, bx1, col.viewDiv); - - if (jvmGetMute(engine.dev, nchannel + choffs)) - { - dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, - bx0 + (cwidth - font->width * 5) / 2, qy1 + 3, "MUTED"); - } - - dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, - bx0 + (cwidth - font->width * 3) / 2, y0 + 1, "%3d", - nchannel + choffs); - } - - for (nrow = 0; nrow < qheight; nrow++) - { - int crow = nrow - midrow + row; - yc = qy0 + 2 + (font->height + 1) * nrow; - - if (crow >= 0 && crow < pat->nrows) - { - dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, x0, yc, "%03d", crow); - - for (nchannel = 0; nchannel < qwidth; nchannel++) - { - if (choffs + nchannel >= pat->nchannels) - break; - - dmPrintNote(screen, x0 + lwidth + 4 + nchannel * cwidth, yc, - pat->data + (pat->nchannels * crow) + choffs + nchannel); - } - } - } -} - - -void audioCallback(void *userdata, Uint8 *stream, int len) -{ - JSSMixer *d = (JSSMixer *) userdata; - - if (d != NULL) - { - jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); - } -} - - -void dmMuteChannels(BOOL mute) -{ - int i; - for (i = 0; i < engine.mod->nchannels; i++) - jvmMute(engine.dev, i, mute); -} - -int main(int argc, char *argv[]) -{ - BOOL initSDL = FALSE, audioInit = FALSE; - DMResource *file = NULL; - int result = -1; - BOOL muteState = FALSE; - - memset(&engine, 0, sizeof(engine)); - - engine.optScrWidth = 640; - engine.optScrHeight = 480; - engine.optScrDepth = 32; - - dmInitProg("CBP", "Cyrbe Basci Player", "0.1", NULL, NULL); - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Open the files - if (optFilename == NULL) - { - dmError("No filename specified.\n"); - return 1; - } - - if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) - { - int err = dmGetErrno(); - dmError("Error opening file '%s', %d: (%s)\n", - optFilename, err, dmErrorStr(err)); - return 1; - } - - // Initialize miniJSS - jssInit(); - - // Read module file - dmMsg(1, "Reading file: %s\n", optFilename); -#ifdef JSS_SUP_XM - dmMsg(2, "* Trying XM...\n"); - result = jssLoadXM(file, &engine.mod); -#endif -#ifdef JSS_SUP_JSSMOD - if (result != 0) - { - size_t bufgot, bufsize = dmfsize(file); - Uint8 *buf = dmMalloc(bufsize); - dmfseek(file, 0L, SEEK_SET); - dmMsg(2, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); - if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) - { - dmf_close(file); - dmError("Error reading file (not enough data %d), #%d: %s\n", - bufgot, dmferror(file), dmErrorStr(dmferror(file))); - goto error_exit; - } - result = jssLoadJSSMOD(buf, bufsize, &engine.mod); - dmFree(buf); - } -#endif - dmf_close(file); - - if (result != DMERR_OK) - { - dmError("Error loading module file, %d: %s\n", - result, dmErrorStr(result)); - goto error_exit; - } - - // Try to convert it - if ((result = jssConvertModuleForPlaying(engine.mod)) != DMERR_OK) - { - dmError("Could not convert module for playing, %d: %s\n", - result, dmErrorStr(result)); - goto error_exit; - } - - // Get font -// file = dmf_create_stdio("fnsmall.fnt", "rb"); - file = dmf_create_memio(NULL, "pplfont.fnt", engineSetupFont, sizeof(engineSetupFont)); - if (file == NULL) - { - dmError("Error opening font file 'pplfont.fnt'.\n"); - goto error_exit; - } - result = dmLoadBitmapFont(file, &font); - dmf_close(file); - if (result != DMERR_OK) - { - dmError("Could not load font from file, %d: %s\n", - result, dmErrorStr(result)); - goto error_exit; - } - - // Initialize SDL components - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) - { - dmError("Could not initialize SDL: %s\n", SDL_GetError()); - goto error_exit; - } - initSDL = TRUE; - - - // Initialize mixing device - dmMsg(2, "Initializing miniJSS mixer with: %d, %d, %d\n", - optOutFormat, optOutChannels, optOutFreq); - - engine.dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); - if (engine.dev == NULL) - { - dmError("jvmInit() returned NULL\n"); - goto error_exit; - } - - switch (optOutFormat) - { - case JSS_AUDIO_S16: engine.afmt.format = AUDIO_S16SYS; break; - case JSS_AUDIO_U16: engine.afmt.format = AUDIO_U16SYS; break; - case JSS_AUDIO_S8: engine.afmt.format = AUDIO_S8; break; - case JSS_AUDIO_U8: engine.afmt.format = AUDIO_U8; break; - default: - dmError("Unsupported audio format %d (could not set matching SDL format)\n", - optOutFormat); - goto error_exit; - } - - engine.afmt.freq = optOutFreq; - engine.afmt.channels = optOutChannels; - engine.afmt.samples = optOutFreq / 16; - engine.afmt.callback = audioCallback; - engine.afmt.userdata = (void *) engine.dev; - - // Open the audio device - if (SDL_OpenAudio(&engine.afmt, NULL) < 0) - { - dmError("Couldn't open SDL audio: %s\n", - SDL_GetError()); - goto error_exit; - } - audioInit = TRUE; - - // Initialize player - if ((engine.plr = jmpInit(engine.dev)) == NULL) - { - dmError("jmpInit() returned NULL\n"); - goto error_exit; - } - - jvmSetCallback(engine.dev, jmpExec, engine.plr); - jmpSetModule(engine.plr, engine.mod); - jmpPlayOrder(engine.plr, optStartOrder); - jvmSetGlobalVol(engine.dev, 64); - - if (optMuteOChannels >= 0 && optMuteOChannels < engine.mod->nchannels) - { - dmMuteChannels(TRUE); - jvmMute(engine.dev, optMuteOChannels, FALSE); - engine.actChannel = optMuteOChannels; - muteState = TRUE; - } - - // Initialize video - if (!dmInitializeVideo()) - goto error_exit; - - SDL_WM_SetCaption(dmProgDesc, dmProgName); - - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - - // okay, main loop here ... "play" module and print out info - SDL_LockAudio(); - SDL_PauseAudio(0); - SDL_UnlockAudio(); - - int currTick, prevTick = 0, prevRow = -1; - - while (!engine.exitFlag) - { - currTick = SDL_GetTicks(); - BOOL force = (currTick - prevTick > 500), updated = FALSE; - - while (SDL_PollEvent(&engine.event)) - switch (engine.event.type) - { - case SDL_KEYDOWN: - switch (engine.event.key.keysym.sym) - { - case SDLK_ESCAPE: - engine.exitFlag = TRUE; - break; - - case SDLK_SPACE: - engine.pauseFlag = !engine.pauseFlag; - SDL_PauseAudio(engine.pauseFlag); - break; - - case SDLK_LEFT: - if (engine.actChannel > 0) - { - engine.actChannel--; - force = TRUE; - } - break; - - case SDLK_RIGHT: - if (engine.actChannel < engine.mod->nchannels) - { - engine.actChannel++; - force = TRUE; - } - break; - - case SDLK_m: - if (engine.event.key.keysym.mod & KMOD_SHIFT) - { - muteState = !muteState; - dmMuteChannels(muteState); - } - else - if (engine.event.key.keysym.mod & KMOD_CTRL) - { - dmMuteChannels(FALSE); - } - else - { - jvmMute(engine.dev, engine.actChannel, !jvmGetMute(engine.dev, engine.actChannel)); - } - force = TRUE; - break; - - case SDLK_PAGEUP: - JSS_LOCK(engine.dev); - JSS_LOCK(engine.plr); - jmpChangeOrder(engine.plr, dmClamp(engine.plr->order - 1, 0, engine.mod->norders)); - JSS_UNLOCK(engine.plr); - JSS_UNLOCK(engine.dev); - force = TRUE; - break; - - case SDLK_PAGEDOWN: - JSS_LOCK(engine.dev); - JSS_LOCK(engine.plr); - jmpChangeOrder(engine.plr, dmClamp(engine.plr->order + 1, 0, engine.mod->norders)); - JSS_UNLOCK(engine.plr); - JSS_UNLOCK(engine.dev); - force = TRUE; - break; - - case SDLK_f: - engine.optVFlags ^= SDL_FULLSCREEN; - if (!dmInitializeVideo()) - goto error_exit; - force = TRUE; - break; - - default: - break; - } - - break; - - case SDL_VIDEORESIZE: - engine.optScrWidth = engine.event.resize.w; - engine.optScrHeight = engine.event.resize.h; - - if (!dmInitializeVideo()) - goto error_exit; - - break; - - case SDL_VIDEOEXPOSE: - break; - - case SDL_QUIT: - engine.exitFlag = TRUE; - break; - } - - -#if 1 - JSS_LOCK(engine.plr); - JSSPattern *currPattern = engine.plr->pattern; - int currRow = engine.plr->row; - if (!engine.plr->isPlaying) - engine.exitFlag = TRUE; - JSS_UNLOCK(engine.plr); - - if (currRow != prevRow || force) - { - prevRow = currRow; - force = TRUE; - } - - // Draw frame - if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0) - { - dmError("Can't lock surface.\n"); - goto error_exit; - } - - if (force) - { - dmClearSurface(engine.screen, col.boxBg); - - dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5, "%s v%s by ccr/TNSP - (c) Copyright 2012 TNSP", dmProgDesc, dmProgVersion); - - dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12 + 11, - "Song: '%s'", - engine.mod->moduleName); - - dmDisplayPattern(engine.screen, 5, 40, - engine.screen->w - 6, engine.screen->h * 0.8, - currPattern, currRow); - - JSS_LOCK(engine.plr); - dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12, - "Tempo: %3d | Speed: %3d | Row: %3d/%-3d | Order: %3d/%-3d | Pattern: %3d/%-3d", - engine.plr->tempo, engine.plr->speed, - engine.plr->row, engine.plr->pattern->nrows, - engine.plr->order, engine.mod->norders, - engine.plr->npattern, engine.mod->npatterns); - JSS_UNLOCK(engine.plr); - updated = TRUE; - } - - if (force || currTick - prevTick >= (engine.pauseFlag ? 100 : 20)) - { - JSS_LOCK(engine.dev); - dmDisplayChannels(engine.screen, 5, engine.screen->h * 0.8 + 5, - engine.screen->w - 5, engine.screen->h - 5, engine.dev); - JSS_UNLOCK(engine.dev); - updated = TRUE; - } - - if (force) - prevTick = currTick; - -#endif - // Flip screen - if (SDL_MUSTLOCK(engine.screen) != 0) - SDL_UnlockSurface(engine.screen); - - if (updated) - SDL_Flip(engine.screen); - - SDL_Delay(engine.pauseFlag ? 100 : 30); - } - -error_exit: - if (engine.screen) - SDL_FreeSurface(engine.screen); - - dmMsg(0, "Audio shutdown.\n"); - if (audioInit) - { - SDL_LockAudio(); - SDL_PauseAudio(1); - SDL_UnlockAudio(); - SDL_CloseAudio(); - } - - jmpClose(engine.plr); - jvmClose(engine.dev); - jssFreeModule(engine.mod); - - dmFreeBitmapFont(font); - - if (initSDL) - SDL_Quit(); - - jssClose(); - - return 0; -}
--- a/utils/svg2qd.py Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -#!/usr/bin/python -import sys -import re -import xml.etree.ElementTree as ET - - -def bf(x) : - return int(round(float(x))) - - -def printVertex(v) : - if type(v) is list : - return "{:.2f},{:.2f},{:.2f}".format(v[0], v[1], v[2]) - else : - return v - - -def getTransform(elem) : - if "transform" in elem.attrib : - ntrans = elem.attrib["transform"] - tmatch = re.compile(r"translate\((.*?)\)", re.IGNORECASE) - for trns in tmatch.finditer(ntrans) : - coord = trns.group(1).split(",") - return [float(coord[0]), float(coord[1]), 0] - return None - - -def getStyle(elem) : - style = {} - if "style" in elem.attrib : - for elem in elem.attrib["style"].split(";") : - kv = elem.split(":") - style[kv[0]] = kv[1] - return style - - -def printVertices(type, vertices, width, level) : - if len(vertices) > 0 : - list = map(lambda v:printVertex(v), vertices) - str = "# "+ type - if type == "m" : - str = "R" - elif type == "M" : - str = "L" - elif type == "c" : - str = "R" - print "{}{}{} {} {}".format(" "*level, str, len(vertices)-1, " ".join(list), width) - - -def printPath(path, level) : - style = getStyle(path) - width = bf(style["stroke-width"]) - - trans = getTransform(path) - if trans : - print "{}G{}".format(" "*level, printVertex(trans)) - - vertices = [] - type = "" - for elem in path.attrib["d"].split(" ") : - if elem == "m" or elem == "M" : - printVertices(type, vertices, width, level) - vertices = [] - type = elem - elif elem == "z" : - vertices.append("Z") - elif elem == "c" or elem == "C" : - print "Curves not supported! Path ID '{}':\n{}".format(path.attrib["id"], path.attrib["d"]) - sys.exit(0) - else : - tmp = elem.split(",") - px = float(tmp[0]) - py = float(tmp[1]) - vertices.append([px, py, 0]) - - printVertices(type, vertices, width, level) - if trans : - print "{}E\n".format(" "*level) - - -def iterateDocument(elems, level) : - for elem in elems: - if elem.tag == "{http://www.w3.org/2000/svg}g" : - print "\n{}# GROUP".format(" "*level) - tmp = getTransform(elem) - if tmp : - print "{}G{}".format(" "*level, printVertex(getTransform(elem))) - iterateDocument(elem, level + 1) - print "{}E\n".format(" "*level) - else : - iterateDocument(elem, level) - elif elem.tag == "{http://www.w3.org/2000/svg}path" : - printPath(elem, level) - - -# Ns. paaohjelma -if len(sys.argv) != 2 : - print "Usage: "+sys.argv[0]+" <input.svg>" - sys.exit(1) - -tree = ET.parse(sys.argv[1]) -iterateDocument(tree.getroot(), 0)
--- a/utils/view64.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,321 +0,0 @@ -/* - * view64 - Display some C64 etc graphics formats via libSDL - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2012 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include "dmlib.h" -#include "dmargs.h" -#include "dmfile.h" -#include "lib64gfx.h" -#include <SDL.h> - - -char * optFilename = NULL; -int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; -int optScrWidth, optScrHeight; -int optForcedFormat = -1; - - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 2, 0, "fs", "Fullscreen", OPT_NONE }, - { 3, 'S', "scale", "Scale image by factor (1-10)", OPT_ARGREQ }, - { 4, 'f', "format", "Force input format (see list below)", OPT_ARGREQ }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void dmSetScaleFactor(float factor) -{ - optScrWidth = (int) ((float) C64_SCR_WIDTH * factor * C64_SCR_PAR_XY); - optScrHeight = (int) ((float) C64_SCR_HEIGHT * factor); -} - - -void argShowHelp() -{ - int i; - - dmPrintBanner(stdout, dmProgName, "[options] <input image file>"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf("\nAvailable bitmap formats:\n"); - for (i = 0; i < ndmC64ImageFormats; i++) - { - const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; - char buf[64]; - printf("%3d | %-5s | %-15s | %s\n", - i, fmt->fext, - dmC64GetImageTypeString(buf, sizeof(buf), fmt->type), - fmt->name); - } -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - dmVerbosity++; - break; - - case 2: - optVFlags |= SDL_FULLSCREEN; - break; - - case 3: - { - float factor; - if (sscanf(optArg, "%f", &factor) == 1) - { - if (factor < 1 || factor >= 10) - { - dmError("Invalid scale factor %1.0f, see help for valid values.\n", factor); - return FALSE; - } - - dmSetScaleFactor(factor); - } - else - { - dmError("Invalid scale factor '%s'.\n", optArg); - return FALSE; - } - } - break; - - case 4: - { - int i; - if (sscanf(optArg, "%d", &i) == 1) - { - if (i < 0 || i >= ndmC64ImageFormats) - { - dmError("Invalid image format index %d, see help for valid values.\n", i); - return FALSE; - } - optForcedFormat = i; - } - else - { - dmError("Invalid image format argument '%s'.\n", optArg); - return FALSE; - } - } - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *filename) -{ - if (optFilename == NULL) - { - optFilename = dm_strdup(filename); - return TRUE; - } - else - { - dmError("Too many filenames specified ('%s')\n", filename); - return FALSE; - } -} - - -BOOL dmInitializeVideo(SDL_Surface **screen) -{ - *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE); - if (*screen == NULL) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - return FALSE; - } - return TRUE; -} - - -int main(int argc, char *argv[]) -{ - SDL_Surface *screen = NULL, *surf = NULL; - DMImage bmap; - BOOL initSDL = FALSE, exitFlag, needRedraw; - const DMC64ImageFormat *fmt = NULL, *forced; - DMC64Image image; - char *windowTitle; - Uint8 *dataBuf = NULL; - size_t dataSize; - int ret; - - dmSetScaleFactor(2.0); - - dmInitProg("view64", "Display some C64 bitmap graphics formats", "0.2", NULL, NULL); - - /* Parse arguments */ - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, FALSE)) - exit(1); - - - if (optFilename == NULL) - { - dmError("No input file specified, perhaps you need some --help\n"); - goto error; - } - - if ((ret = dmReadDataFile(NULL, optFilename, &dataBuf, &dataSize)) != DMERR_OK) - goto error; - - dmMsg(1, "Read %d bytes of input.\n", dataSize); - - // Probe for format - if (optForcedFormat >= 0) - { - forced = &dmC64ImageFormats[optForcedFormat]; - dmMsg(0,"Forced %s format image, type %d, %s\n", - forced->name, forced->type, forced->fext); - } - else - forced = NULL; - - ret = dmC64DecodeBMP(&image, dataBuf, dataSize, 0, 2, &fmt, forced); - if (forced == NULL && fmt != NULL) - { - dmMsg(0,"Probed %s format image, type %d, %s\n", - fmt->name, fmt->type, fmt->fext); - } - - if (ret < 0) - { - dmError("Probing could not find any matching image format (%d). Perhaps try forcing a format via -f\n", ret); - return -1; - } - - - // Initialize libSDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) - { - dmError("Could not initialize SDL: %s\n", SDL_GetError()); - goto error; - } - initSDL = TRUE; - - - // Open window/set video mode - screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE); - if (screen == NULL) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - goto error; - } - - // Create surface (we are lazy and ugly) - surf = SDL_CreateRGBSurface(SDL_SWSURFACE, C64_SCR_WIDTH, C64_SCR_HEIGHT, 8, 0, 0, 0, 0); - SDL_SetColors(surf, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS); - SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS); - - // Convert bitmap (this is a bit ugly and lazy here) - bmap.data = surf->pixels; - bmap.pitch = surf->pitch; - bmap.width = surf->w; - bmap.height = surf->h; - bmap.constpal = TRUE; - - if (fmt->convertFrom != NULL) - ret = fmt->convertFrom(&bmap, &image, TRUE); - else - ret = dmC64ConvertGenericBMP2Image(&bmap, &image, TRUE); - - - // Set window title and caption - windowTitle = dm_strdup_printf("%s - %s", dmProgName, optFilename); - SDL_WM_SetCaption(windowTitle, dmProgName); - dmFree(windowTitle); - - - // Start main loop - needRedraw = TRUE; - exitFlag = FALSE; - while (!exitFlag) - { - SDL_Event event; - while (SDL_PollEvent(&event)) - switch (event.type) - { - case SDL_KEYDOWN: - switch (event.key.keysym.sym) - { - case SDLK_ESCAPE: exitFlag = TRUE; break; - - default: - break; - } - - needRedraw = TRUE; - break; - - case SDL_VIDEORESIZE: - optScrWidth = event.resize.w; - optScrHeight = event.resize.h; - - if (!dmInitializeVideo(&screen)) - goto error; - - needRedraw = TRUE; - break; - - case SDL_VIDEOEXPOSE: - needRedraw = TRUE; - break; - - case SDL_QUIT: - exit(0); - } - - if (needRedraw) - { - if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) - { - dmError("Can't lock surface.\n"); - goto error; - } - - dmScaledBlitSurface8to8(surf, 0, 0, screen->w, screen->h, screen); - SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS); - - if (SDL_MUSTLOCK(screen) != 0) - SDL_UnlockSurface(screen); - - SDL_Flip(screen); - needRedraw = FALSE; - } - - SDL_Delay(100); - } - - -error: - if (screen) - SDL_FreeSurface(screen); - - if (initSDL) - SDL_Quit(); - - return 0; -}
--- a/utils/viewmod.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,475 +0,0 @@ -/* - * viewmod - View information about given module file - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2006-2007 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include "jss.h" -#include "jssmod.h" -#include <errno.h> -#include <string.h> -#include "dmargs.h" -#include "dmmutex.h" - - -char *optFilename = NULL; -BOOL optViewPatterns = FALSE, - optViewInstruments = FALSE, - optViewExtInstruments = FALSE, - optViewGeneralInfo = FALSE; - - -DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help and exit", OPT_NONE }, - { 1, 'p', "patterns", "View patterns", OPT_NONE }, - { 2, 'i', "instruments", "View instruments", OPT_NONE }, - { 5, 'e', "extinstruments", "View extended instruments", OPT_NONE }, - { 3, 'g', "general", "General information", OPT_NONE }, - { 4, 'v', "verbose", "Be more verbose", OPT_NONE }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, "[options] [modfile]"); - dmArgsPrintHelp(stdout, optList, optListN); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - (void) optArg; - - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - optViewPatterns = TRUE; - break; - - case 2: - optViewInstruments = TRUE; - break; - - case 3: - optViewGeneralInfo = TRUE; - break; - - case 4: - dmVerbosity++; - break; - - case 5: - optViewExtInstruments = TRUE; - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - // Was not option argument - if (!optFilename) - optFilename = currArg; - else { - dmError("Gay error '%s'!\n", currArg); - return FALSE; - } - - return TRUE; -} - - -const char patNoteTable[12][3] = -{ - "C-", "C#", "D-", - "D#", "E-", "F-", - "F#", "G-", "G#", - "A-", "A#", "B-" -}; - -#define jmpNMODEffectTable (36) -static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - -/* Print a given pattern - */ -void printPattern(FILE *f, JSSPattern *p) -{ - int i, j; - char c; - JSSNote *n; - - if (!p) - return; - - n = p->data; - - for (i = 0; i < p->nrows; i++) - { - fprintf(f, "%.2x: ", i); - - for (j = 0; j < p->nchannels; j++) - { - switch (n->note) - { - case jsetNotSet: - fprintf(f, "... "); - break; - case jsetNoteOff: - fprintf(f, "=== "); - break; - default: - fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12); - break; - } - - if (n->instrument != jsetNotSet) - fprintf(f, "%.2x ", n->instrument + 1); // Because FT2 is 1-based and we use 0 internally - else - fprintf(f, ".. "); - - if (n->volume == jsetNotSet) - fprintf(f, ".. "); - else if (n->volume >= 0x00 && n->volume <= 0x40) - fprintf(f, "%.2x ", n->volume); - else - { - switch (n->volume & 0xf0) - { - case 0x50: c = '-'; break; - case 0x60: c = '+'; break; - case 0x70: c = '/'; break; - case 0x80: c = '\\'; break; - case 0x90: c = 'S'; break; - case 0xa0: c = 'V'; break; - case 0xb0: c = 'P'; break; - case 0xc0: c = '<'; break; - case 0xd0: c = '>'; break; - case 0xe0: c = 'M'; break; - default: c = '?'; break; - } - fprintf(f, "%c%x ", c, (n->volume & 0x0f)); - } - - if (n->effect >= 0 && n->effect < jmpNMODEffectTable) - fprintf(f, "%c", jmpMODEffectTable[n->effect]); - else if (n->effect == jsetNotSet) - fprintf(f, "."); - else - fprintf(f, "?"); - - if (n->param != jsetNotSet) - fprintf(f, "%.2x|", n->param); - else - fprintf(f, "..|"); - - n++; - } - - fprintf(f, "\n"); - } -} - - -/* - * Print given extended instrument - */ -void printEnvelope(FILE *f, JSSEnvelope *e, char *s) -{ - int i; - - fprintf(f, - "\t%s-envelope:\n" - "\t - flags.....: %.4x", s, e->flags); - - if (e->flags & jenvfUsed) - fprintf(f, " [used]"); - if (e->flags & jenvfSustain) - fprintf(f, " [sust]"); - if (e->flags & jenvfLooped) - fprintf(f, " [loop]"); - - fprintf(f, "\n" - "\t - npoints...: %i\n" - "\t - sustain...: %i\n" - "\t - loopS.....: %i\n" - "\t - loopE.....: %i\n", - e->npoints, e->sustain, e->loopS, e->loopE); - - if (dmVerbosity >= 2) - { - fprintf(f, "\t - Points....:"); - for (i = 0; i < e->npoints; i++) - { - fprintf(f, " [%i:%i]", - e->points[i].frame, e->points[i].value); - } - - fprintf(f, "\n"); - } -} - - -void printExtInstrument(FILE *f, JSSExtInstrument *i) -{ - if (!i) - { - fprintf(f, "\n"); - return; - } - -#ifndef JSS_LIGHT - if (i->desc) - fprintf(f, - "Description: '%s'\n", i->desc); -#endif - fprintf(f, - "nsamples.......: %i\n" - "vibratoType....: %i\n" - "vibratoSweep...: %i\n" - "vibratoDepth...: %i\n" - "vibratoRate....: %i\n" - "fadeOut........: %i\n", - i->nsamples, i->vibratoType, i->vibratoSweep, - i->vibratoDepth, i->vibratoRate, i->fadeOut); - - if (dmVerbosity >= 1) - { - printEnvelope(f, &i->volumeEnv, "Volume"); - printEnvelope(f, &i->panningEnv, "Panning"); - } - fprintf(f, "\n"); -} - - -void printInstrument(FILE *f, JSSInstrument *i) -{ - if (!i) - { - fprintf(f, "\n"); - return; - } - - if (dmVerbosity >= 1) - { -#ifndef JSS_LIGHT - if (i->desc) - fprintf(f, "Description: '%s'\n", i->desc); -#endif - fprintf(f, - "size...........: %ld (0x%lx)\n" - "loopStart......: %ld (0x%lx)\n" - "loopEnd........: %ld (0x%lx)\n" - "volume.........: %d (0x%x)\n" - "flags..........: 0x%x ", - (unsigned long) i->size, (unsigned long) i->size, - (unsigned long) i->loopS, (unsigned long) i->loopE, - (unsigned long) i->loopS, (unsigned long) i->loopE, - i->volume, i->volume, - i->flags); - - if (i->flags & jsfLooped) fprintf(f, "[loop] "); - if (i->flags & jsfBiDi) fprintf(f, "[bi-di] "); - if (i->flags & jsf16bit) fprintf(f, "[16bit] "); - - fprintf(f, - "\nC4BaseSpeed....: %d (0x%x)\n" - "ERelNote.......: %d (%s%d)\n" - "EFineTune......: %d\n" - "EPanning,,,....: %d (0x%x)\n\n", - i->C4BaseSpeed, i->C4BaseSpeed, - i->ERelNote, patNoteTable[(48 + i->ERelNote) % 12], (48 + i->ERelNote) / 12, - i->EFineTune, i->EPanning, i->EPanning); - } - else - { -#ifndef JSS_LIGHT - if (i->desc) - fprintf(f, "'%s', ", i->desc); -#endif - fprintf(f, - "s=%ld (%lx), l=%ld-%ld (%lx-%lx), v=%i (%x), f=0x%x, c4=%i (%x), rn=%i (%s%i), ft=%i, pn=%i (%x)\n", - (unsigned long) i->size, (unsigned long) i->size, - (unsigned long) i->loopS, (unsigned long) i->loopE, - (unsigned long) i->loopS, (unsigned long) i->loopE, - i->volume, i->volume, i->flags, i->C4BaseSpeed, - i->C4BaseSpeed, i->ERelNote, - patNoteTable[(48 + i->ERelNote) % 12], - (48 + i->ERelNote) / 12, i->EFineTune, - i->EPanning, i->EPanning); - } -} - - -void printGeneralInfo(FILE *f, JSSModule *m) -{ - int i; - - if (!m) - return; - - fprintf(f, "Module type.....: %i\n", m->moduleType); -#ifndef JSS_LIGHT - if (m->moduleName) - fprintf(f, "Module name.....: '%s'\n", m->moduleName); - if (m->trackerName) - fprintf(f, "Tracker name....: '%s'\n", m->trackerName); -#endif - fprintf(f, - "Speed...........: %d ticks\n" - "Tempo...........: %d bpm\n" - "Flags...........: %x ", - m->defSpeed, m->defTempo, m->defFlags); - - if (m->defFlags & jmdfAmigaPeriods) fprintf(f, "[Amiga periods] "); - if (m->defFlags & jmdfAmigaLimits) fprintf(f, "[Amiga limits] "); - if (m->defFlags & jmdfStereo) fprintf(f, "[stereo] "); - if (m->defFlags & jmdfFT2Replay) fprintf(f, "[FT2 replay] "); - if (m->defFlags & jmdfST300Slides) fprintf(f, "[ST300 slides] "); - if (m->defFlags & jmdfByteLStart) fprintf(f, "[ByteStart] "); - - fprintf(f, "\n" - "Restart pos.....: %d (order)\n" - "IntVersion......: %x\n" - "Channels........: %d\n" - "Instruments.....: %d\n" - "Ext.instruments.: %d\n" - "Patterns........: %d\n" - "Orders..........: %d\n", - m->defRestartPos, m->intVersion, m->nchannels, - m->ninstruments, m->nextInstruments, m->npatterns, - m->norders); - - if (dmVerbosity >= 1) - { - fprintf(f, "Orderlist: "); - for (i = 0; i < m->norders - 1; i++) - fprintf(f, "%d, ", m->orderList[i]); - if (i < m->norders) - fprintf(f, "%d", m->orderList[i]); - fprintf(f, "\n"); - } -} - - - -int main(int argc, char *argv[]) -{ - int result = -1, i; - DMResource *file; - JSSModule *mod; - - dmInitProg("viewmod", "miniJSS Module Viewer", "0.4", NULL, NULL); - dmVerbosity = 0; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Initialize miniJSS - jssInit(); - - // Open the file - dmMsg(1, "Reading module file '%s'\n", optFilename); - if (optFilename == NULL) - file = dmf_create_stdio_stream(stdin); - else if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) - { - dmError("Error opening input file '%s'. (%s)\n", - optFilename, strerror(errno)); - return 1; - } - - // Read module file - dmMsg(1, "Reading file: %s\n", optFilename); -#ifdef JSS_SUP_XM - dmMsg(1, "* Trying XM...\n"); - result = jssLoadXM(file, &mod); -#endif -#ifdef JSS_SUP_JSSMOD - if (result != 0) - { - size_t bufgot, bufsize = dmfsize(file); - Uint8 *buf = dmMalloc(bufsize); - dmfseek(file, 0L, SEEK_SET); - dmMsg(1, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); - if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) - { - dmError("Error reading file (not enough data %d), #%d: %s\n", - bufgot, dmferror(file), dmErrorStr(dmferror(file))); - return 2; - } - result = jssLoadJSSMOD(buf, bufsize, &mod); - dmFree(buf); - } -#endif - dmf_close(file); - if (result != DMERR_OK) - { - dmError("Error loading module file, %d: %s\n", - result, dmErrorStr(result)); - return 3; - } - - // Print out information - if (optViewGeneralInfo) - printGeneralInfo(stdout, mod); - - if (optViewPatterns) - { - for (i = 0; i < mod->npatterns; i++) - { - printf("\nPattern #%03i:\n", i); - printPattern(stdout, mod->patterns[i]); - } - } - - if (optViewExtInstruments) - { - printf("\n" - "ExtInstruments:\n" - "---------------\n" - ); - for (i = 0; i < mod->nextInstruments; i++) - { - printf("#%03i: ", i + 1); - printExtInstrument(stdout, mod->extInstruments[i]); - } - } - - if (optViewInstruments) - { - printf("\n" - "Instruments:\n" - "------------\n" - ); - for (i = 0; i < mod->ninstruments; i++) - { - printf("#%03i: ", i + 1); - printInstrument(stdout, mod->instruments[i]); - } - } - - // Free module data - jssFreeModule(mod); - jssClose(); - - exit(0); - return 0; -}
--- a/utils/xm2jss.c Tue Apr 16 06:01:42 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1040 +0,0 @@ -/* - * xm2jss - Convert XM module to JSSMOD - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2006-2009 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <stdio.h> -#include <errno.h> -#include "jss.h" -#include "jssmod.h" -#include "jssplr.h" -#include "dmlib.h" -#include "dmargs.h" -#include "dmres.h" -#include "dmmutex.h" - - -#define jmpNMODEffectTable (36) -static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - -char *optInFilename = NULL, *optOutFilename = NULL; -BOOL optIgnoreErrors = FALSE, - optStripExtInstr = FALSE, - optStripInstr = FALSE, - optStripSamples = FALSE, - optOptimize = FALSE; - -int optPatternMode = PATMODE_COMP_HORIZ, - optSampMode16 = jsampDelta, - optSampMode8 = jsampFlipSign | jsampDelta; - -#define SAMPMODE_MASK (jsampFlipSign | jsampSwapEndianess | jsampSplit | jsampDelta) - - -static const char* patModeTable[PATMODE_LAST] = -{ - "Raw horizontal", - "Compressed horizontal (similar to XM modules)", - "Raw vertical", - "Compressed vertical", - "Raw vertical for each element", -}; - - -DMOptArg optList[] = { - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 2, 'i', "ignore", "Ignore errors", OPT_NONE }, - { 3, 'p', "patterns", "Pattern storage mode", OPT_ARGREQ }, - { 4, 'E', "strip-ext-instr","Strip ext. instruments (implies -I -S)", OPT_NONE }, - { 5, 'I', "strip-instr", "Strip instruments (implies -S)", OPT_NONE }, - { 6, 'S', "strip-samples", "Strip instr. sampledata", OPT_NONE }, - { 7, '8', "smode8", "8-bit sample conversion flags", OPT_ARGREQ }, - { 8, '1', "smode16", "16-bit sample conversion flags", OPT_ARGREQ }, - { 9, 'O', "optimize", "Optimize module", OPT_NONE }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - int i; - - dmPrintBanner(stdout, dmProgName, "[options] <input.xm> <output.jmod>"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf("\n" - "Pattern storage modes:\n"); - - for (i = 1; i < PATMODE_LAST; i++) - printf(" %d = %s\n", i, patModeTable[i-1]); - - printf( - "\n" - "Sample data conversion flags (summative):\n" - " 1 = Delta encoding (DEF 8 & 16)\n" - " 2 = Flip signedness (DEF 8)\n" - " 4 = Swap endianess (affects 16-bit only)\n" - " 8 = Split and de-interleave hi/lo bytes (affects 16-bit only)\n" - "\n" - ); -} - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - (void) optArg; - - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - dmVerbosity++; - break; - - case 2: - optIgnoreErrors = TRUE; - break; - - case 3: - optPatternMode = atoi(optArg); - if (optPatternMode <= 0 || optPatternMode >= PATMODE_LAST) - { - dmError("Unknown pattern conversion mode %d\n", optPatternMode); - return FALSE; - } - break; - - case 4: optStripExtInstr = TRUE; break; - case 5: optStripInstr = TRUE; break; - case 6: optStripSamples = TRUE; break; - - case 7: optSampMode8 = atoi(optArg) & SAMPMODE_MASK; break; - case 8: optSampMode16 = atoi(optArg) & SAMPMODE_MASK; break; - - case 9: optOptimize = TRUE; break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - // Was not option argument - if (!optInFilename) - optInFilename = currArg; - else - if (!optOutFilename) - optOutFilename = currArg; - else - { - dmError("Too many filename arguments specified, '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -/* These functions and the macro mess are meant to make the - * conversion routines themselves clearer and simpler. - */ -BOOL jsPutByte(Uint8 *patBuf, size_t patBufSize, size_t *npatBuf, Uint8 val) -{ - if (*npatBuf >= patBufSize) - return FALSE; - else - { - patBuf[*npatBuf] = val; - (*npatBuf)++; - return TRUE; - } -} - -#define JSPUTBYTE(x) do { if (!jsPutByte(patBuf, patBufSize, patSize, x)) return DMERR_BOUNDS; } while (0) - -#define JSCOMP(x,z) do { if ((x) != jsetNotSet) { qflags |= (z); qcomp++; } } while (0) - -#define JSCOMPPUT(xf,xv,qv) do { \ - if (qflags & (xf)) { \ - if ((xv) < 0 || (xv) > 255) \ - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ - "%s value out of bounds %d.\n", qv, (xv)); \ - JSPUTBYTE(xv); \ - } \ -} while (0) - -#define JSCONVPUT(xv,qv) do { \ - if ((xv) != jsetNotSet) { \ - if ((xv) < 0 || (xv) > 254) \ - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ - "%s value out of bounds %d.\n", qv, (xv)); \ - JSPUTBYTE((xv) + 1); \ - } else { \ - JSPUTBYTE(0); \ - } \ -} while (0) - - -/* Convert a note - */ -static int jssConvertNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) -{ - Uint8 tmp; - if (note->note == jsetNotSet) - tmp = 0; - else if (note->note == jsetNoteOff) - tmp = 127; - else - tmp = note->note + 1; - - if (tmp > 0x7f) - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); - - JSPUTBYTE(tmp & 0x7f); - - JSCONVPUT(note->instrument, "Instrument"); - JSCONVPUT(note->volume, "Volume"); - JSCONVPUT(note->effect, "Effect"); - - tmp = (note->param != jsetNotSet) ? note->param : 0; - JSPUTBYTE(tmp); - - return DMERR_OK; -} - - -/* Compress a note - */ -static int jssCompressNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) -{ - Uint8 qflags = 0; - int qcomp = 0; - - JSCOMP(note->note, COMP_NOTE); - JSCOMP(note->instrument, COMP_INSTRUMENT); - JSCOMP(note->volume, COMP_VOLUME); - JSCOMP(note->effect, COMP_EFFECT); - if (note->param != jsetNotSet && note->param != 0) - { - qflags |= COMP_PARAM; - qcomp++; - } - - if (qcomp < 4) - { - JSPUTBYTE(qflags | 0x80); - - if (note->note != jsetNotSet) - { - Uint8 tmp = (note->note != jsetNoteOff) ? note->note : 127; - if (tmp > 0x7f) - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); - JSPUTBYTE(tmp); - } - - JSCOMPPUT(COMP_INSTRUMENT, note->instrument, "Instrument"); - JSCOMPPUT(COMP_VOLUME, note->volume, "Volume"); - JSCOMPPUT(COMP_EFFECT, note->effect, "Effect"); - JSCOMPPUT(COMP_PARAM, note->param, "Param"); - } else - return jssConvertNote(patBuf, patBufSize, patSize, note); - - return DMERR_OK; -} - - -/* Compress pattern - */ -static int jssConvertPatternCompHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - int row, channel; - *patSize = 0; - - for (row = 0; row < pattern->nrows; row++) - for (channel = 0; channel < pattern->nchannels; channel++) - { - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssCompressNote(patBuf, patBufSize, patSize, note); - if (res != DMERR_OK) - { - JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); - return res; - } - } - - return DMERR_OK; -} - - -static int jssConvertPatternCompVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - int row, channel; - *patSize = 0; - - for (channel = 0; channel < pattern->nchannels; channel++) - for (row = 0; row < pattern->nrows; row++) - { - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssCompressNote(patBuf, patBufSize, patSize, note); - if (res != DMERR_OK) - { - JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); - return res; - } - } - - return DMERR_OK; -} - - -/* Convert a pattern - */ -static int jssConvertPatternRawHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - int row, channel; - *patSize = 0; - - for (row = 0; row < pattern->nrows; row++) - for (channel = 0; channel < pattern->nchannels; channel++) - { - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssConvertNote(patBuf, patBufSize, patSize, note); - if (res != DMERR_OK) - { - JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); - return res; - } - } - - return DMERR_OK; -} - - -static int jssConvertPatternRawVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - int row, channel; - *patSize = 0; - - for (channel = 0; channel < pattern->nchannels; channel++) - for (row = 0; row < pattern->nrows; row++) - { - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssConvertNote(patBuf, patBufSize, patSize, note); - if (res != DMERR_OK) - { - JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); - return res; - } - } - - return DMERR_OK; -} - - -#define JSFOREACHNOTE1 \ - for (channel = 0; channel < pattern->nchannels; channel++) \ - for (row = 0; row < pattern->nrows; row++) { \ - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - -#define JSFOREACHNOTE2 } - -static int jssConvertPatternRawElem(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - Uint8 tmp; - int row, channel; - *patSize = 0; - - JSFOREACHNOTE1; - if (note->note == jsetNotSet) - tmp = 0; - else if (note->note == jsetNoteOff) - tmp = 127; - else - tmp = note->note + 1; - if (tmp > 0x7f) - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); - JSPUTBYTE(tmp); - JSFOREACHNOTE2; - - JSFOREACHNOTE1; - JSCONVPUT(note->instrument, "Instrument"); - JSFOREACHNOTE2; - - JSFOREACHNOTE1; - JSCONVPUT(note->volume, "Volume"); - JSFOREACHNOTE2; - - JSFOREACHNOTE1; - JSCONVPUT(note->effect, "Effect"); - JSFOREACHNOTE2; - - JSFOREACHNOTE1; - tmp = (note->param != jsetNotSet) ? note->param : 0; - JSPUTBYTE(tmp); - JSFOREACHNOTE2; - - return DMERR_OK; -} - -#undef JSFOREACHNOTE1 -#undef JSFOREACHNOTE2 - - -static void jssCopyEnvelope(JSSMODEnvelope *je, JSSEnvelope *e) -{ - int i; - - je->flags = e->flags; - je->npoints = e->npoints; - je->sustain = e->sustain; - je->loopS = e->loopS; - je->loopE = e->loopE; - - for (i = 0; i < e->npoints; i++) - { - je->points[i].frame = e->points[i].frame; - je->points[i].value = e->points[i].value; - } -} - - -/* Save a JSSMOD file - */ -int jssSaveJSSMOD(FILE *outFile, JSSModule *m, int patMode, int flags8, int flags16) -{ - JSSMODHeader jssH; - int i, pattern, order, instr, totalSize; - const size_t patBufSize = 64*1024; // 64kB pattern buffer - Uint8 *patBuf; - - // Check the module - if (m == NULL) - JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, "Module pointer was NULL\n"); - - if ((m->nchannels < 1) || (m->npatterns < 1) || (m->norders < 1)) - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, - "Module had invalid values (nchannels=%i, npatterns=%i, norders=%i)\n", - m->nchannels, m->npatterns, m->norders); - - // Create the JSSMOD header - jssH.idMagic[0] = 'J'; - jssH.idMagic[1] = 'M'; - jssH.idVersion = JSSMOD_VERSION; - jssH.norders = m->norders; - jssH.npatterns = m->npatterns; - jssH.nchannels = m->nchannels; - jssH.nextInstruments = m->nextInstruments; - jssH.ninstruments = m->ninstruments; - jssH.defFlags = m->defFlags; - jssH.intVersion = m->intVersion; - jssH.defRestartPos = m->defRestartPos; - jssH.defSpeed = m->defSpeed; - jssH.defTempo = m->defTempo; - jssH.patMode = patMode; - - // Write header - totalSize = sizeof(jssH); - if (fwrite(&jssH, sizeof(jssH), 1, outFile) != 1) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD header!\n"); - - dmMsg(1," * JSSMOD-header 0x%04x, %d bytes.\n", JSSMOD_VERSION, totalSize); - - // Write orders list - for (totalSize = order = 0; order < m->norders; order++) - { - Uint16 tmp = m->orderList[order]; - totalSize += sizeof(tmp); - if (fwrite(&tmp, sizeof(tmp), 1, outFile) != 1) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD orders list.\n"); - } - - dmMsg(1," * %d item orders list, %d bytes.\n", - m->norders, totalSize); - - // Allocate pattern compression buffer - if ((patBuf = dmMalloc(patBufSize)) == NULL) - JSSERROR(DMERR_MALLOC, DMERR_MALLOC, - "Error allocating memory for pattern compression buffer.\n"); - - - // Write patterns - for (totalSize = pattern = 0; pattern < m->npatterns; pattern++) - { - JSSMODPattern patHead; - size_t finalSize = 0; - - switch (patMode) - { - case PATMODE_RAW_HORIZ: - i = jssConvertPatternRawHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - case PATMODE_COMP_HORIZ: - i = jssConvertPatternCompHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - case PATMODE_RAW_VERT: - i = jssConvertPatternRawVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - case PATMODE_COMP_VERT: - i = jssConvertPatternCompVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - case PATMODE_RAW_ELEM: - i = jssConvertPatternRawElem(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - default: - i = DMERR_INVALID_DATA; - dmFree(patBuf); - JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Unsupported pattern conversion mode %d.\n", patMode); - break; - } - - if (i != DMERR_OK) - { - dmFree(patBuf); - JSSERROR(i, i, "Error converting pattern data #%i\n", pattern); - } - else - { - dmMsg(3, " - Pattern %d size %d bytes\n", pattern, finalSize); - patHead.nrows = m->patterns[pattern]->nrows; - patHead.size = finalSize; - totalSize += finalSize + sizeof(patHead); - - if (fwrite(&patHead, sizeof(patHead), 1, outFile) != 1) - { - dmFree(patBuf); - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Error writing pattern #%d header\n", pattern); - } - - if (fwrite(patBuf, sizeof(Uint8), finalSize, outFile) != finalSize) - { - dmFree(patBuf); - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Error writing pattern #%d data\n", pattern); - } - } - } - dmFree(patBuf); - dmMsg(1," * %d patterns, %d bytes.\n", m->npatterns, totalSize); - - // Write extended instruments - for (totalSize = instr = 0; instr < m->nextInstruments; instr++) - { - JSSMODExtInstrument jssE; - JSSExtInstrument *einst = m->extInstruments[instr]; - - memset(&jssE, 0, sizeof(jssE)); - - if (einst) - { - // Create header - jssE.nsamples = einst->nsamples; - for (i = 0; i < jsetNNotes; i++) - { - int snum = einst->sNumForNotes[i]; - jssE.sNumForNotes[i] = (snum != jsetNotSet) ? snum : 0; - } - - jssCopyEnvelope(&jssE.volumeEnv, &(einst->volumeEnv)); - jssCopyEnvelope(&jssE.panningEnv, &(einst->panningEnv)); - jssE.vibratoType = einst->vibratoType; - jssE.vibratoSweep = einst->vibratoSweep; - jssE.vibratoDepth = einst->vibratoDepth; - jssE.fadeOut = einst->fadeOut; - } else - JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Extended instrument #%i NULL!\n", instr); - - // Write to file - totalSize += sizeof(jssE); - if (fwrite(&jssE, sizeof(jssE), 1, outFile) != 1) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Could not write JSSMOD extended instrument #%i to file!\n", instr); - } - dmMsg(1," * %d Extended Instruments, %d bytes.\n", m->nextInstruments, totalSize); - - - // Write sample instrument headers - for (totalSize = instr = 0; instr < m->ninstruments; instr++) - { - JSSMODInstrument jssI; - JSSInstrument *pInst = m->instruments[instr]; - - memset(&jssI, 0, sizeof(jssI)); - - // Create header - if (pInst) - { - jssI.size = pInst->size; - jssI.loopS = pInst->loopS; - jssI.loopE = pInst->loopE; - jssI.volume = pInst->volume; - jssI.flags = pInst->flags; - jssI.C4BaseSpeed = pInst->C4BaseSpeed; - jssI.ERelNote = pInst->ERelNote; - jssI.EFineTune = pInst->EFineTune; - jssI.EPanning = pInst->EPanning; - jssI.hasData = (pInst->data != NULL) ? TRUE : FALSE; - jssI.convFlags = (pInst->flags & jsf16bit) ? flags16 : flags8; - } - else - JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Instrument #%i NULL!\n", instr); - - // Write to file - totalSize += sizeof(jssI); - if (fwrite(&jssI, sizeof(jssI), 1, outFile) != 1) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Could not write JSSMOD instrument #%i to file!\n", instr); - } - dmMsg(1," * %d Instrument headers, %d bytes.\n", m->ninstruments, totalSize); - - // Write sample data - for (totalSize = instr = 0; instr < m->ninstruments; instr++) - if (m->instruments[instr]) - { - JSSInstrument *inst = m->instruments[instr]; - if (inst->data != NULL) - { - size_t res; - if (inst->flags & jsf16bit) - { - jssEncodeSample16(inst->data, inst->size, flags16); - res = fwrite(inst->data, sizeof(Uint16), inst->size, outFile); - } - else - { - jssEncodeSample8(inst->data, inst->size, flags8); - res = fwrite(inst->data, sizeof(Uint8), inst->size, outFile); - } - - totalSize += inst->size; - if (res != (size_t) inst->size) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Could not write JSSMOD sample #%i to file!\n", instr); - } - } - dmMsg(1," * %d samples, %d bytes.\n", m->ninstruments, totalSize); - - return DMERR_OK; -} - - -/* Optimize a given module - */ -JSSModule *optimizeModule(JSSModule *m) -{ - BOOL usedPatterns[jsetMaxPatterns + 1], - usedInstruments[jsetMaxInstruments + 1], - usedExtInstruments[jsetMaxInstruments + 1]; - int mapExtInstruments[jsetMaxInstruments + 1], - mapInstruments[jsetMaxInstruments + 1], - mapPatterns[jsetMaxPatterns + 1]; - JSSModule *r = NULL; - int i, n8, n16; - - // Allocate a new module - if ((r = jssAllocateModule()) == NULL) - return NULL; - - // Allocate tables - - // Copy things - r->moduleType = m->moduleType; - r->moduleName = dm_strdup(m->moduleName); - r->trackerName = dm_strdup(m->trackerName); - r->defSpeed = m->defSpeed; - r->defTempo = m->defTempo; - r->defFlags = m->defFlags; - r->defRestartPos = m->defRestartPos; - r->intVersion = m->intVersion; - r->nchannels = m->nchannels; - r->norders = m->norders; - for (i = 0; i < jsetNChannels; i++) - r->defPanning[i] = m->defPanning[i]; - - // Initialize values - for (i = 0; i <= jsetMaxInstruments; i++) - { - usedExtInstruments[i] = FALSE; - usedInstruments[i] = FALSE; - mapExtInstruments[i] = jsetNotSet; - mapInstruments[i] = jsetNotSet; - } - - for (i = 0; i <= jsetMaxPatterns; i++) - { - usedPatterns[i] = FALSE; - mapPatterns[i] = jsetNotSet; - } - - // Find out all used patterns and ext.instruments - for (i = 0; i < m->norders; i++) - { - int pattern = m->orderList[i]; - if (pattern >= 0 && pattern < m->npatterns) - { - JSSPattern *p = m->patterns[pattern]; - if (p != NULL) - { - int row, channel; - JSSNote *n = p->data; - - // Mark pattern as used - usedPatterns[pattern] = TRUE; - - // Check all notes - for (row = 0; row < p->nrows; row++) - for (channel = 0; channel < p->nchannels; channel++, n++) - { - if (n->instrument != jsetNotSet) - { - if (optStripExtInstr || (n->instrument >= 0 && n->instrument < m->nextInstruments)) - usedExtInstruments[n->instrument] = TRUE; - else - dmMsg(2, "Pattern 0x%x, row=0x%x, chn=%d has invalid instrument 0x%x\n", - pattern, row, channel, n->instrument); - } - } - } - else - { - dmError("Pattern 0x%x is used on order 0x%x, but has no data!\n", - pattern, i); - } - } - else - if (pattern != jsetMaxPatterns) - { - dmError("Order 0x%x has invalid pattern number 0x%x!\n", - i, pattern); - } - } - - // Find out used instruments - for (i = 0; i <= jsetMaxInstruments; i++) - if (usedExtInstruments[i] && m->extInstruments[i] != NULL) - { - int note; - JSSExtInstrument *e = m->extInstruments[i]; - - for (note = 0; note < jsetNNotes; note++) - if (e->sNumForNotes[note] != jsetNotSet) - { - int q = e->sNumForNotes[note]; - if (q >= 0 && q < m->ninstruments) - { - usedInstruments[q] = TRUE; - } - else - { - dmError("Ext.instrument #%d sNumForNotes[%d] value out range (%d < %d).\n", - i, m->ninstruments, q); - } - } - } - - // Create pattern mappings - r->npatterns = 0; - dmMsg(1, "Unused patterns: "); - - for (i = 0; i <= jsetMaxPatterns; i++) - if (m->patterns[i] != NULL) - { - if (!usedPatterns[i]) - { - dmPrint(2, "0x%x, ", i); - } - else - { - if (i >= m->npatterns) - dmError("Pattern 0x%x >= 0x%x, but used!\n", i, m->npatterns); - - mapPatterns[i] = r->npatterns; - r->patterns[r->npatterns] = m->patterns[i]; - (r->npatterns)++; - } - } - dmPrint(2, "\n"); - - dmMsg(1, "%d used patterns, %d unused.\n", - r->npatterns, m->npatterns - r->npatterns); - - - // Re-map instruments - dmMsg(1, "Unused instruments: "); - for (n8 = n16 = i = 0; i <= jsetMaxInstruments; i++) - if (m->instruments[i] != NULL) - { - if (!usedInstruments[i] && !optStripInstr) - { - dmPrint(2, "0x%x, ", i); - } - else - { - JSSInstrument *ip = m->instruments[i]; - if (i >= m->ninstruments) - dmError("Instrument 0x%x >= 0x%x, but used!\n", i, m->ninstruments); - - mapInstruments[i] = r->ninstruments; - r->instruments[r->ninstruments] = ip; - (r->ninstruments)++; - - if (ip->flags & jsf16bit) - n16++; - else - n8++; - } - } - dmPrint(2, "\n"); - dmMsg(1, "Total of (%d) 16-bit, (%d) 8-bit samples, (%d) instruments.\n", - n16, n8, r->ninstruments); - - // Re-map ext.instruments - dmMsg(1, "Unused ext.instruments: "); - for (i = 0; i < jsetMaxInstruments; i++) - if (usedExtInstruments[i]) - { - if (i >= m->nextInstruments && !optStripExtInstr) - { - dmError("Ext.instrument 0x%x >= 0x%x, but used!\n", - i, m->nextInstruments); - } - else - if (m->extInstruments[i] != NULL) - { - JSSExtInstrument *e = m->extInstruments[i]; - int note; - - mapExtInstruments[i] = r->nextInstruments; - r->extInstruments[r->nextInstruments] = e; - (r->nextInstruments)++; - - // Re-map sNumForNotes - for (note = 0; note < jsetNNotes; note++) - { - int q = e->sNumForNotes[note]; - if (q != jsetNotSet) - { - int map; - if (q >= 0 && q <= jsetMaxInstruments) - { - map = mapInstruments[q]; - } - else - { - map = jsetNotSet; - dmError("e=%d, note=%d, q=%d/%d\n", i, note, q, r->ninstruments); - } - e->sNumForNotes[note] = map; - } - } - } - else - { - dmPrint(2, "[0x%x==NULL], ", i); - mapExtInstruments[i] = jsetNotSet; - } - } - else - { - if (i < m->nextInstruments && m->extInstruments[i] != NULL) - { - dmPrint(2, "0x%x, ", i); - } - } - dmPrint(2, "\n"); - dmMsg(1, "%d extended instruments.\n", r->nextInstruments); - - - // Remap pattern instrument data - for (i = 0; i < r->npatterns; i++) - { - int row, channel; - JSSPattern *p = r->patterns[i]; - JSSNote *n = p->data; - - for (row = 0; row < p->nrows; row++) - for (channel = 0; channel < p->nchannels; channel++, n++) - { - char effect; - - if (!optStripExtInstr) - { - if (n->instrument >= 0 && n->instrument <= jsetMaxInstruments) - n->instrument = mapExtInstruments[n->instrument]; - - if (n->instrument != jsetNotSet && r->extInstruments[n->instrument] == NULL) - dmError("Non-existing instrument used #%d.\n", n->instrument); - } - - JMPGETEFFECT(effect, n->effect); - - switch (effect) - { - case 'C': // Cxx = Set volume - if (n->volume == jsetNotSet) - { - n->volume = n->param; - n->effect = jsetNotSet; - n->param = jsetNotSet; - } - break; - } - } - } - - // Remap orders list - for (i = 0; i < m->norders; i++) - { - r->orderList[i] = mapPatterns[m->orderList[i]]; - } - - return r; -} - - -int main(int argc, char *argv[]) -{ - DMResource *sfile = NULL; - FILE *dfile = NULL; - JSSModule *sm, *dm; - int result; - - dmInitProg("xm2jss", "XM to JSSMOD converter", "0.6", NULL, NULL); - dmVerbosity = 0; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Check arguments - if (optInFilename == NULL || optOutFilename == NULL) - { - dmError("Input or output file not specified. Try --help.\n"); - return 1; - } - - // Read the source file - if ((sfile = dmf_create_stdio(optInFilename, "rb")) == NULL) - { - dmError("Error opening input file '%s', %d: %s\n", - optInFilename, errno, strerror(errno)); - return 1; - } - - // Initialize miniJSS - jssInit(); - - // Read file - dmMsg(1, "Reading XM-format file ...\n"); - result = jssLoadXM(sfile, &sm); - dmf_close(sfile); - if (result != 0) - { - dmError("Error while loading XM file (%i), ", result); - if (optIgnoreErrors) - fprintf(stderr, "ignoring. This may cause problems.\n"); - else - { - fprintf(stderr, "giving up. Use --ignore if you want to try to convert anyway.\n"); - return 2; - } - } - - // Check stripping settings - if (optStripExtInstr) optStripInstr = TRUE; - if (optStripInstr) optStripSamples = TRUE; - - // Remove samples - if (optStripSamples) - { - int i; - - dmMsg(1, "Stripping samples...\n"); - for (i = 0; i < sm->ninstruments; i++) - { - dmFree(sm->instruments[i]->data); - sm->instruments[i]->data = NULL; - } - } - - // Remove instruments - if (optStripInstr) - { - int i; - - dmMsg(1, "Stripping instruments...\n"); - for (i = 0; i < sm->ninstruments; i++) - { - dmFree(sm->instruments[i]); - sm->instruments[i] = NULL; - } - sm->ninstruments = 0; - } - - // Remove ext.instruments - if (optStripExtInstr) - { - int i; - - dmMsg(1, "Stripping ext.instruments...\n"); - for (i = 0; i < sm->nextInstruments; i++) - { - dmFree(sm->extInstruments[i]); - sm->extInstruments[i] = NULL; - } - sm->nextInstruments = 0; - } - // Run the optimization procedure - if (optOptimize) - { - dmMsg(1, "Optimizing module data...\n"); - dm = optimizeModule(sm); - } else - dm = sm; - - // Write output file - if ((dfile = fopen(optOutFilename, "wb")) == NULL) - { - dmError("Error creating output file '%s', %d: %s\n", - optOutFilename, errno, strerror(errno)); - return 1; - } - - dmMsg(1, "Writing JSSMOD-format file [patMode=0x%04x, samp8=0x%02x, samp16=0x%02x]\n", - optPatternMode, optSampMode8, optSampMode16); - - result = jssSaveJSSMOD(dfile, dm, optPatternMode, optSampMode8, optSampMode16); - - fclose(dfile); - - if (result != 0) - { - dmError("Error while saving JSSMOD file, %d: %s\n", - result, dmErrorStr(result)); - dmError("WARNING: The resulting file may be broken!\n"); - } - else - { - dmMsg(1, "Conversion complete.\n"); - } - return 0; -}