// Подключаем файл с дефайнами
#include "soundsys\modload.inc"



// Объявление процедур
word fastcall SwapAndDouble(AX);
void fastcall LoadModFile(DX);



#ifdef __MSDOS__

// Меняет местами старшую и младшую части и удваивает результат
:word fastcall SwapAndDouble(AX)
{
 AL><AH;
 AX<<=1;
}



// Подгрузка мод-файла
:void fastcall LoadModFile(DX)
{
 $push ES,BP

  // Открываем файл с модулем
  BX=OPEN(DX,0);

   // Считываем заголовок мод-файла
   FREAD(BX,#ModModule,1084);
   // Узнаем количество семплов в модуле
   IF (ModModule.Signature[0]<32){
      // 15 семплов
      ModModule.NumSamples=15;
      // 4 канала
      ModModule.NumVoices=4;
      // Сдвигаем считанный заголовок
      ES=DS; DI=#ModModule.OrderLength;
      SI=#ModModule.ModSample[15].Name;
      CX=130>>1;
      $rep $movsw
      // Устанавливаем положение в файле на первый паттерн
      LLSEEK(BX,600,0);
   }ELSE{
      // 31 семпл
      ModModule.NumSamples=31;
      // Распознаем количество каналов по сигнатуре
      // "xCHN" или "FLTx" - x каналов
      // "CHxx" - xx каналов
      // "M.K." или "M!K!" - 4 канала
      // "OKTA" - 8 каналов
      EAX=DSDWORD[#ModModule.Signature];
      IF (EAX=='.K.M')||(EAX=='!K!M') ModModule.NumVoices=4;
      ELSE IF (EAX=='ATKO') ModModule.NumVoices=8;
      ELSE IF (AX=='HC'){
         // Узнаем количество каналов (AAD <=> AX=10*AH+AL)
         EAX>>=16; $ror AX,8 $aad
         ModModule.NumVoices=AL;
      }ELSE{
         // Сохраняем хендлер файла с модулем
         $push BX
          EBX=EAX>>8;
          IF (EBX=='NHC') ModModule.NumVoices=AL-'0';
          ELSE{
             EBX=EAX&0FFFFFFh; // 4TLF
             IF (EBX=='TLF') ModModule.NumVoices=dword EAX>>24-'0';
          }
         // Восстанавливаем хендлер файла с модулем
         $pop BX
      }
   }

   // Узнаем количество паттернов
   FOR (SI=0,AL=0; SI<128; SI++){
       AH=ModModule.Order[SI];
       IF (AL<AH) AL=AH;
   }
   ModModule.NumPatterns=AL+1;

   // Считываем паттерны
   FOR (BP=0; BP<ModModule.NumPatterns; BP++){
       $push BX
        // Смещение в таблице сегментов паттернов
        SI=BP<<1;
        // Выделяем память под паттерн                // !!!!!
        ModModule.PatternSeg[SI]=GETMEM(sizeof(PATTERNELEMENT)*4*ModModule.NumVoices);
       $pop BX
       // Считываем паттерн
        $push DS
         // Устанавливаем DS на сегмент паттерна
         DS=AX;
         // Считываем поэлементно весь паттерн
         FOR (DI=sizeof(PATTERNELEMENT)*64*CSBYTE[#ModModule.NumVoices],DX=0; DX<DI; DX+=sizeof(PATTERNELEMENT)){
             // Считываем элемент паттерна
             FREAD(BX,DX,4);
             // Преобразуем в собственный формат
             SI=DX;
             // Параметр эффекта
             SI.PATTERNELEMENT.EffectParametr=DSBYTE[SI+3];
             // Номер эффекта
             AL=DSBYTE[SI+2]&0Fh;
             SI.PATTERNELEMENT.EffectNumber=AL;
             // Период
             CH=DSWORD[SI]&0Fh; CL=DSWORD[SI+1];
             // Номер семпла
             AH=DSBYTE[SI]>>4; AL=DSBYTE[SI+2]; AX>>=4;
             // Период
             SI.PATTERNELEMENT.NotePeriod=CX;
             // Номер семпла
             SI.PATTERNELEMENT.SampleNumber=AL;
         }
        $pop DS
   }

   // Считываем семплы
   for (DI=0,BP=#ModModule.ModSample; DI<ModModule.NumSamples; DI++,BP+=sizeof(MODSAMPLE)){

       // Преобразуем
       BP.MODSAMPLE.Length=SwapAndDouble(BP.MODSAMPLE.Length);
       BP.MODSAMPLE.RepeatOffs=SwapAndDouble(BP.MODSAMPLE.RepeatOffs);
       BP.MODSAMPLE.RepeatLength=SwapAndDouble(BP.MODSAMPLE.RepeatLength);

       // Смещение зацикливания > длины семпла ?
       IF (BP.MODSAMPLE.RepeatOffs>BP.MODSAMPLE.Length){
          // Сбрасываем информацию о зацикливании семпла
          BP.MODSAMPLE.RepeatOffs=0;
          BP.MODSAMPLE.RepeatLength=0;
       }

       // Длина зацикливание+смещение зацикливания > длины семпла ?
       IF (BP.MODSAMPLE.RepeatOffs+BP.MODSAMPLE.RepeatLength>BP.MODSAMPLE.Length){
          // Перерассчитываем длину зацикливания
          BP.MODSAMPLE.RepeatLength=BP.MODSAMPLE.Length-BP.MODSAMPLE.RepeatOffs;
       }

       IF (BP.MODSAMPLE.Length==2){
          // Если размер семпла == 2, то семпла нету
          BP.MODSAMPLE.Length=0;
          CONTINUE;
       }

       $push BX
        // Выделяем память под семпл
        IF (!GETMEM(BP.MODSAMPLE.Length>>4+1)) WRITESTR("\nНе могу выделить память");
        // SI - смещение в таблице сегментов семплов
        SI=DI<<1;
        ModModule.SampleSeg[SI]=AX;
       $pop BX
       // Сохраняем сегмент данных
       $push DS
        // Устанавливаем DS на выделенный сегмент под семпл
        DS=AX;
        // Считываем семпл в формате AMIGA (-128...+127)
        @FREAD(BX,0,CS:BP.MODSAMPLE.Length);
       // Восстанавливаем сегмент данных
       $pop DS
   }

   // Позиция перезапуска песни больше длины списка паттернов ?
   IF (ModModule.ReStart>=ModModule.OrderLength) ModModule.ReStart=0;

  // Закрываем файл с модулем
  CLOSE(BX);

 $pop BP,ES
}

#endif