#define MAIN
#include <string.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <process.h>
#include <math.h>
#include <process.h>
#include <dos.h>
#include <share.h>
#include <direct.h>
#include <errno.h>
#include <stdarg.h>
#pragma pack(1)

#define EOS                     '\0'
#define MAX_INSTRUMENTS         31
#define DEFAULT_NUM_INSTRUMENTS 15
#define MAX_POSITIONS           128
#define MAX_CHANNELS            4
#define MAX_PATTERN_ROWS        64

typedef unsigned long DWORD;
typedef unsigned int WORD;
typedef unsigned char BYTE;
#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))

typedef struct tagMODHEADER
{
    char    name[20];
} MODHEADER;


typedef struct tagINSTRUMENT
{
    char    name[22];
    WORD    sampleLength;                    
    WORD    volume;
    WORD    repeatOffset;
    WORD    repeatLength;
} INSTRUMENT;


typedef struct tagPOSITIONTABLE
{
    BYTE    noOfPositions;
    BYTE    reserved;
    BYTE    position[ MAX_POSITIONS ];
} POSITIONTABLE;

typedef struct tagNOTE
{
    WORD    word1;
    WORD    word2;
} NOTE;


typedef struct tagCHANNEL
{
    NOTE    note;
} CHANNEL;

typedef struct tagPATTERNROW
{
    CHANNEL channel[MAX_CHANNELS];
} PATTERNROW;

typedef struct tagPATTERNTABLE
{
    PATTERNROW row[MAX_PATTERN_ROWS];
} PATTERNTABLE;


//**********************************************************************
//*                                           
//**********************************************************************

MODHEADER       modHeader;
INSTRUMENT      instrument;
POSITIONTABLE   positionTable;
PATTERNTABLE    patternTable;

//**********************************************************************
//*                                           
//**********************************************************************

//WORD WordSwap( WORD value )
//{
//    return((LOBYTE(value) << 8) | HIBYTE(value));
//}
#define WordSwap(a)  ((WORD) (LOBYTE(a) << 8) | (WORD) HIBYTE(a))

//**********************************************************************
//*                                           
//**********************************************************************

main( int argc, char *argv[])
{
    int handle, loop;
    BYTE noOfInstruments;
    BYTE noOfPatternTables;
    WORD noOfSampleBytes;
    char buffer[256];
    int  row, channel;
    DWORD period, sampleRate;
    WORD word1, word2;
    WORD  noteInstrument;
    WORD  notePeriod;
    WORD  noteEffect;
    WORD  noteParm;


    if (argc <= 1 || (handle = open(argv[1], O_RDWR | O_BINARY )) == -1)
        exit(1);

    //******************************************************************
    //* DETERMINE THE NUMBER OF INSTRUMENTS
    //******************************************************************

    lseek( handle, 1080L, SEEK_SET);

    if (read( handle, buffer, 4) == 4 &&
        (strncmp(buffer, "M.K.", 4) == 0 ||
         strncmp(buffer, "FLT4", 4) == 0 ||
         strncmp(buffer, "FLT8", 4) == 0))
        noOfInstruments = MAX_INSTRUMENTS;
    else
        noOfInstruments = DEFAULT_NUM_INSTRUMENTS;

    //******************************************************************
    //* READ FILE HEADER
    //******************************************************************

    lseek( handle, 0L, SEEK_SET);
    read( handle, (char *) &modHeader, sizeof(MODHEADER) );
    modHeader.name[ sizeof(modHeader.name)-1 ] = EOS;

    printf( "=======================================\n" );
    printf( "MODNAME = [%s]\n", modHeader.name );

    //******************************************************************
    //* READ INSTRUMENT TABLES
    //******************************************************************

    for (loop = 0; loop < noOfInstruments; loop++)
    {
        read( handle, (char *) &instrument, sizeof(INSTRUMENT) );

        instrument.sampleLength = WordSwap( instrument.sampleLength ) * sizeof(WORD);
		instrument.volume       = WordSwap( instrument.volume ) & 0x007F;
        instrument.repeatLength = WordSwap( instrument.repeatLength ) * sizeof(WORD);
		instrument.repeatOffset = WordSwap( instrument.repeatOffset ) * sizeof(WORD);
        noOfSampleBytes += instrument.sampleLength;

        if (instrument.sampleLength)
        {
            printf( "--------------------------------------\n" );
            printf( "INSTRUMENT = (%d) %s\n", loop+1, instrument.name );
            printf( "LENGTH     = %u\n", instrument.sampleLength );
            printf( "VOLUME     = %u\n", instrument.volume );
            printf( "REPEAT OFF = %u\n", instrument.repeatOffset );
            printf( "REPEAT LEN = %u\n", instrument.repeatLength );
        }
    }

    //******************************************************************
    //* READ SONG HEADER
    //******************************************************************

    read( handle, (char *) &positionTable, sizeof(POSITIONTABLE) );

    printf( "=======================================\n" );
    printf( "NO OF SONG POSITIONS = %d\n", positionTable.noOfPositions );

    printf("SONG POSITIONS ...\n");

    for ( loop = 0; loop < positionTable.noOfPositions; loop++ )
    {
        printf("%3d\n", positionTable.position[loop] );
    }

    if ( noOfInstruments > DEFAULT_NUM_INSTRUMENTS )
        lseek( handle, 4L, SEEK_CUR);       /* skip past signature */

    //******************************************************************
    //* READ PATTERN TABLES
    //******************************************************************

    noOfPatternTables = 0;

    for ( loop = 0; loop < positionTable.noOfPositions; loop++ )
    {
        if (positionTable.position[loop] >= noOfPatternTables)
            noOfPatternTables = positionTable.position[loop] + 1;
    }

    for ( loop = 0; loop < noOfPatternTables; loop++)
    {
        printf( "---------------------------------------------------------------------------------------------------------------------------\n");

        printf( "PATTERN #%d\n", loop );
        read( handle, (char *) &patternTable, sizeof(PATTERNTABLE) );

        for ( row = 0; row < MAX_PATTERN_ROWS; row++ )
        {
            for ( channel = 0; channel < MAX_CHANNELS; channel++ )
            {
                word1 = WordSwap( patternTable.row[row].channel[channel].note.word1 );
                word2 = WordSwap( patternTable.row[row].channel[channel].note.word2 );

                noteInstrument = ((word1 >> 8) & 0xF0) + ((word2 >> 12) & 0x0F);
                notePeriod     = (word1 & 0xFFF);
                noteEffect     = (word2 >> 8) & 0x0F;
                noteParm       = (word2 & 0xFF);

                printf("Ins=");

                if (noteInstrument)
                    printf("[%2d]", noteInstrument);
                else
                    printf("[  ]");

                printf(" Per=");

                if (notePeriod)
                    printf("[%3d]", notePeriod);
                else
                    printf("[   ]");

                if (noteEffect)
                    printf(" Eff=[%2.2X,%2.2X]", noteEffect, noteParm);
                else
                    printf(" Eff=[     ]");

                if (channel < (MAX_CHANNELS-1))
                    printf("³");
            }
            printf("\n");
        }
    }

    close(handle);
}




