/*      MOD2GM.C
 *
 * MOD2GM v1.01 .GM converter
 *
 * Copyright 1996 Petteri Kangaslampi and Jarno Paananen
 *
 * This file is part of the MIDAS Sound System, and may only be
 * used, modified and distributed under the terms of the MIDAS
 * Sound System license, LICENSE.TXT. By continuing to use,
 * modify or distribute this file you indicate that you have
 * read the license and understand and accept it fully.
*/

#include <stdio.h>
#include <stdlib.h>
#ifdef __BORLANDC__
#include <alloc.h>
#endif
#include "midas.h"

char            *title =
"MOD2GM v1.01 .GM converter for MIDAS Sound System v" MVERSTR "\n"
"Copyright 1996 Petteri Kangaslampi and Jarno Paananen\n";

char            *usage =
"Usage:\tMOD2GM\t<Sourcefile> <GMfile> [options]\n"
"    <Sourcefile>    Name of source module file\n"
"    <GMfile>        Name of destination .GM file\n"
"Options:\n"
"    -q              Be quiet - no messages\n";

fileHandle      outf;                   /* output file handle */
int             ofOpen = 0;             /* 1 if output file is open */
ulong           smpTotal = 0;           /* total sample size */
ulong           total = 0;              /* total size */


/****************************************************************************\
*
* Function:     void Error(char *msg)
*
* Description:  Prints an error message to stderr and exits to DOS
*
* Input:        char *msg               error message
*
\****************************************************************************/

void Error(char *msg)
{
    fprintf(stderr, "Error: %s\n", msg);
    if ( ofOpen == 1 )
        fileClose(outf);
    exit(EXIT_FAILURE);
}




/****************************************************************************\
*
* Function:     void SaveGM(char *fileName, gmpModule *module)
*
* Description:  Saves a module into a .GM file
*
* Input:        char *fileName          module file name
*               gmpModule *module       module to be saved
*
\****************************************************************************/

void SaveGM(char *fileName, gmpModule *module)
{
    int         error;
    int         i, s;
    int         numChans = module->numChannels;
    unsigned    a;
    uchar       b, d;
    gmpInstrument *inst;
    gmpSample   *smp;


    /* A small macro to ensure I won't get Cobol fingers: */
#define FILEWRITE(data,len) \
    { \
        total += len; \
        if ( (error = fileWrite(outf, data, len)) != OK ) \
            Error(errorMsg[error]); \
    }

    /* open output file: */
    if ( (error = fileOpen(fileName, fileOpenWrite, &outf)) != OK )
        Error(errorMsg[error]);
    ofOpen = 1;

    /* Write module structure: */
    FILEWRITE(module, sizeof(gmpModule));

    /* Write initial panning positions: */
    FILEWRITE(module->panning, sizeof(int) * numChans);

    /* Write song data: */
    FILEWRITE(module->songData, sizeof(ushort) * module->songLength);

    /* Write instrument data for all instruments: */
    for ( i = 0; i < module->numInsts; i++ )
    {
        inst = module->instruments[i];

        /* Write instrument structure: */
        FILEWRITE(inst, sizeof(gmpInstrument));

        /* Write sample structures for any samples: */
        if ( inst->numSamples != 0 )
            FILEWRITE(inst->samples, inst->numSamples * sizeof(gmpSample));

        /* Write note sample numbers if used: */
        if ( inst->noteSamples != NULL )
            FILEWRITE(inst->noteSamples, 96);

        /* Write volume envelope information if used: */
        if ( inst->volEnvelope != NULL )
            FILEWRITE(inst->volEnvelope, sizeof(gmpEnvelope));

        /* Write panning envelope information if used: */
        if ( inst->panEnvelope != NULL )
            FILEWRITE(inst->panEnvelope, sizeof(gmpEnvelope));
    }

    /* Write all patterns: */
    for ( i = 0; i < module->numPatts; i++ )
    {
        FILEWRITE(module->patterns[i], module->patterns[i]->length);
    }

    /* Finally convert all samples into delta format and write the sample
       data: */
    for ( i = 0; i < module->numInsts; i++ )
    {
        inst = module->instruments[i];

        /* Do all sample for this instrument: */
        for ( s = 0; s < inst->numSamples; s++ )
        {
            smp = &inst->samples[s];

            /* Check that there really is a sample: */
            if ( (smp->sampleLength > 0) && (smp->sampleType == smp8bit) )
            {
                /* FIXME - 16-bit samples (?) */
                /* convert sample data to delta format: */
                b = 0;
                for ( a = 0; a < smp->sampleLength; a++ )
                {
                    d = smp->sample[a] - b;
                    b = b + d;
                    smp->sample[a] = d;
                }

                /* Write sample data: */
                FILEWRITE(smp->sample, smp->sampleLength);

                smpTotal += smp->sampleLength;
            }
        }
    }

    /* close output file: */
    if ( (error = fileClose(outf)) != OK )
        Error(errorMsg[error]);
    ofOpen = 0;
}



int main(int argc, char *argv[])
{
    int         error;
    static gmpModule   *module;
#ifdef __BORLANDC__
    ulong       free1;
#endif
    int         quiet = 0;
    static fileHandle  f;
    static char        buf[48];

    /* EMS MUST be disabled when using .GM files: */
    mUseEMS = 0;

#ifdef __BORLANDC__
    /* Save the size of largest available free block to detect memory leaks:*/
    free1 = coreleft();
#endif

    /* Check if quiet mode should be used: */
    if ( (argc == 4) )
    {
        if ( ((argv[3][0] == '-') || (argv[3][0] == '/')) &&
             ((argv[3][1] == 'q') || (argv[3][1] == 'Q')) )
            quiet = 1;
    }

    if ( !quiet )
        puts(title);

    if ( (argc < 3) || (argc > 4) )
    {
        puts(usage);
        exit(EXIT_SUCCESS);
    }

    /* Read first 48 bytes of module: */
    if ( (error = fileOpen(argv[1], fileOpenRead, &f)) != OK )
        midasError(error);
    if ( (error = fileRead(f, buf, 48)) != OK )
        midasError(error);
    if ( (error = fileClose(f)) != OK )
        midasError(error);

    if ( mMemEqual(buf, "Extended Module:", 16) )
    {
        if ( !quiet )
            puts("Loading Fasttracker 2 module");
        if ( (error = gmpLoadXM(argv[1], 0, NULL, &module)) != OK )
            midasError(error);
    }
    else
    {
        if ( mMemEqual(buf+44, "SCRM", 4) )
        {
            if ( !quiet )
                puts("Loading Screamtracker 3 module");
            if ( (error = gmpLoadS3M(argv[1], 0, NULL, &module)) != OK )
                midasError(error);
        }
        else
        {
            if ( !quiet )
                puts("Loading Protracker module");
            if ( (error = gmpLoadMOD(argv[1], 0, NULL, &module)) != OK )
                midasError(error);
        }
    }

    if ( !quiet )
        printf("Saving .GM file %s\n", argv[2]);

    /* save .GM file: */
    SaveGM(argv[2], module);

    if ( !quiet )
        printf("Done. Total size %lu bytes, with %lu bytes of sample data.\n",
            total, smpTotal);

    /* deallocate module: */
    if ( (error = gmpFreeModule(module)) != OK )
        Error(errorMsg[error]);

#ifdef __BORLANDC__
    if ( !quiet )
        printf("Done. Memory lost: %lu bytes\n", free1 - coreleft());
#endif

    return 0;
}