view gentab.c @ 510:43ea59887c69

Start work on making C64 formats encoding possible by changing DMDecodeOps to DMEncDecOps and adding fields and op enums for custom encode functions, renaming, etc. Split generic op sanity checking into a separate function in preparation for its use in generic encoding function.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 19 Nov 2012 15:06:01 +0200
parents 966617f0f6cd
children
line wrap: on
line source

#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;
}