/*      MM.C
 *
 * Routines for .MM module playing using the simplified MIDAS API
 *
 * Copyright 1995 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 "midas.h"


/* Macro to normalize a 16-bit segment:offset far pointer: */
#ifdef __REALMODE__
#define NORMALIZE(x) ((void*) ((((ulong) x) & 0x000FL) + \
    ((((ulong) x) & 0xFFF0L) << 12) + (((ulong) x) & 0xFFFF0000L)))
#else
#define NORMALIZE(x) (x)
#endif



/****************************************************************************\
*
* Function:     mpModule midasPrepareMM(uchar *mm, ModulePlayer *MP);
*
* Description:  Prepares a .MM module for playing using Module Player *MP.
*
* Input:        uchar *mm               Pointer to the .MM module
*               ModulePlayer *MP        Pointer to the Module Player which
*                                       will be used for playing the module
*
* Returns:      Pointer to the prepared module structure, which can be
*               played with midasPlayModule().
*
* Note:         This function should be used with the simple MIDAS
*               programming interface, MIDAS.C.
*               This function modifies the start of the .MM module in
*               memory, and may thus be called ONLY ONCE for each module.
*
\****************************************************************************/

mpModule * CALLING midasPrepareMM(uchar *mm, ModulePlayer *MP)
{
    mpModule    *module;
    int         error;
    int         i;
    uchar       *mmptr;
    unsigned    a;
    uchar       b;
    mpInstrument *inst;
    uchar       *sample;

    /* Point module to module header: */
    module = (mpModule*) mm;
    mmptr = mm + sizeof(mpModule);

    /* Point module->MP to correct Module Player: */
    module->MP = MP;

    /* Point module->orders to song data: */
    module->orders = (uchar*) mmptr;
    mmptr += module->songLength;

    /* Point module->insts to instrument headers: */
    module->insts = (mpInstrument*) mmptr;
    mmptr += module->numInsts * sizeof(mpInstrument);

    /* Allocate memory for pattern pointers: */
    if ( (error = memAlloc(module->numPatts * sizeof(mpPattern*),
        (void**) &module->patterns)) != OK )
        midasError(error);

    /* Point all patterns to correct pattern data: */
    for ( i = 0; i < module->numPatts; i++ )
    {
        module->patterns[i] = (mpPattern*) mmptr;
        mmptr += module->patterns[i]->length + sizeof(mpPattern);
        mmptr = NORMALIZE(mmptr);
    }

    /* Point module->instsUsed to instrument used data: */
    module->instsUsed = (uchar*) mmptr;
    mmptr += module->numInsts;

    /* Point all samples to correct sample data, convert samples to raw
       format and add instruments to Sound Device: */
    for ( i = 0; i < module->numInsts; i++ )
    {
        mmptr = NORMALIZE(mmptr);

        inst = &module->insts[i];
        if ( (module->instsUsed[i] == 1) && (inst->length != 0) )
        {
            sample = inst->sample = (uchar*) mmptr;
            mmptr += inst->length;

            b = 0;
            for ( a = 0; a < inst->length; a++ )
            {
                b = b + sample[a];
                sample[a] = b;
            }

            error = midasSD->AddInstrument(sample, smp8bit, inst->length,
                inst->loopStart, inst->loopEnd, inst->volume, inst->looping,
                0, &inst->sdInstHandle);
            if ( error != OK )
                midasError(error);
        }
        else
            inst->sdInstHandle = 0;
    }
    return module;
}




/****************************************************************************\
*
* Function:     void midasFreeMM(mpModule *module);
*
* Description:  Deallocates a module that has been prepared for playing with
*               midasPrepareMM(). Deallocates allocated structures and
*               removes the instruments from the Sound Device. Note that
*               the .MM module in memory will NOT be deallocated.
*
* Input:        mpModule *module        module to be deallocated.
*
\****************************************************************************/

void CALLING midasFreeMM(mpModule *module)
{
    int         error, i;

    /* Deallocate pattern pointers: */
    if ( (error = memFree(module->patterns)) != OK )
        midasError(error);

    /* Remove instruments from Sound Device: */
    for ( i = 0; i < module->numInsts; i++ )
    {
        if ( module->insts[i].sdInstHandle != 0 )
        {
            if ( (error = midasSD->RemInstrument(
                module->insts[i].sdInstHandle)) != OK )
                midasError(error);
        }
    }
}
