view viewmod.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 245b15cd1919
children
line wrap: on
line source

/*
 * 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;
}