//Структуры

struct ModSample
{
        byte msName[22];
        word msLength;
        byte msFinetune;
        byte msVolume;
        word msRepeat;
        word msRepLen;
};

struct ModHeader
{
        byte mhName[20];
        struct ModSample mhSamples[31];
        byte mhOrderLen;
        byte mhReStart;
        byte mhOrder[128];
        word mhSign[2];
}Header;


struct ModInfoRec
{
        byte OrderLen;
        byte ReStart;
        byte Order[128];
        dword Patterns;
        word SampOfs[31];
        word SampSeg[31];
        word SampLen[31];
        word SampRep[31];
        word SampRepLen[31];
        word SampVol[31];
}ModInfo;

//Resources and Data.
word FileHandle;
byte ErrorInfo;
byte EndModule;

//Объявления процедур
word FOPEN(DX,AL);
word FREAD(BX,DX,CX);
word FSEEK(BX,CX,DX,AL);

void LoadModule(word FileName)
{
        ErrorInfo=1;
        ClearModInfo();
        FileHandle=FOPEN(FileName,0);
        IF(AX==0)goto FAILED;
//        FSEEK(FileHandle,0,11550,0);
        FREAD(AX,#Header,sizeof(ModHeader));



//        IF(AX!=sizeof(ModHeader))goto CLOSEFILE;

//        IF(Header.mhSign=='.M')&&(Header.mhSign[2]=='.K')GOTO ISMODFILE;
//        IF(Header.mhSign=='LF')&&(Header.mhSign[2]=='4T')GOTO ISMODFILE;
//GOTO ISMODFILE;
//        SI=#Header.mhSamples[15].msName;
//        DI=#Header.mhOrderLen;
//        ES=DS;
//        $cld
//        CX=130;
//        $rep $movsb
//        DI=#Header.mhSamples[15].msName;
//        AX=0;
//        CX=16*sizeof(ModSample);
//        $rep $stosb
//        FSEEK(FileHandle,0,600,0);
//ISMODFILE:
        ModInfo.OrderLen=Header.mhOrderLen;
        AL=Header.mhReStart;
        IF(AL>=Header.mhOrderLen)AL=0x7F;
        ModInfo.ReStart=AL;
        CX=128;
        AX=0;
        BX=0;
        loop(CX){
                AH=Header.mhOrder[BX];
                ModInfo.Order[BX]=AH;
                IF(AH>AL)AL=AH;
                BX++;
        }
        AH=0;
        AX++;
        $push AX
        GETMEM(AX*64);
        $pop CX
        IF(AX==0)goto CLOSEFILE;
        DSWORD[#ModInfo.Patterns]=0;
        DSWORD[#ModInfo.Patterns+2]=AX;
        READFAR(,FileHandle,CX<<10,AX);

        IF(CARRYFLAG)GOTO CLOSEFILE;
        FOR(DI=0,SI=0;DI<31*2;DI++,DI++,SI+=sizeof(ModSample)){
                AX=DSWORD[#Header.mhSamples[0].msLength+SI];
                AL><AH;
                AX<<=1;
                ModInfo.SampLen[DI]=AX;
                ModInfo.SampVol[DI]=DSBYTE[#Header.mhSamples[0].msVolume+SI];
                AX=DSWORD[#Header.mhSamples[0].msRepeat+SI];
                AL><AH;
                AX<<=1;
                ModInfo.SampRep[DI]=AX;
                AX=DSWORD[#Header.mhSamples[0].msRepLen+SI];
                AL><AH;
                AX<<=1;
                ModInfo.SampRepLen[DI]=AX;
        }
        FOR(DI=0;DI<31*2;DI++,DI++){
                AX=ModInfo.SampLen[DI]>>4;
                IF(NOTZEROFLAG){
                        GETMEM(AX+1);
                        IF(AX==0)GOTO CLOSEFILE;
                        ModInfo.SampOfs[DI]=0;
                        ModInfo.SampSeg[DI]=AX;
                        READFAR(,FileHandle,ModInfo.SampLen[DI],AX);
                        IF(CARRYFLAG)GOTO CLOSEFILE;
                }
        }
        ErrorInfo=0;
        EndModule=FALSE;
CLOSEFILE:
        FCLOSE(,FileHandle);
FAILED:
}

void FreeModule()
{
        $pusha
        AX=DSWORD[#ModInfo.Patterns+2];
        IF(AX!=0)FREEMEM();
        FOR(SI=0;SI<31*2;SI++,SI++){
                AX=ModInfo.SampSeg[SI];
                IF(ModInfo.SampLen[SI]!=0)&&(AX!=0)FREEMEM(AX);
        }
        ClearModInfo();
        $popa
}


void ClearModInfo()
{
        $pusha
        $push ES
        ModInfo=0;
        $pop ES
        $popa
}
