home *** CD-ROM | disk | FTP | other *** search
/ PC Interdit / pc-interdit.iso / sound / sbmod / mod_sb.pas < prev    next >
Pascal/Delphi Source File  |  1994-10-30  |  50KB  |  2,023 lines

  1.  
  2.  
  3. {
  4.  
  5.  *****************************************************************************
  6.  ***                   MICRO APPLICATION PC INTERDIT                       ***
  7.  ***                  ================================                     ***
  8.  ***                                                                       ***
  9.  ***                           Unit MOD_SB                                 ***
  10.  ***                                                                       ***
  11.  ***  Cette unité est facilement intégrable dans les programmes. Elle      ***
  12.  ***  peut être mise en oeuvre par l'intermédiaire de l'interruption du    ***
  13.  ***  timer. Elle contient de plus une routine permettant d'exécuter       ***
  14.  ***  les fichiers VOC.                                                    ***
  15.  ***  Pour une qualité d'émission de 22KHz lors de la sortie d'un fichier  ***
  16.  ***  MOD à 8 voix sur un 486 DX 33,  elle exige moins de 15% du temps de  ***
  17.  ***  calcul.                                                              ***
  18.  ***                                                                       ***
  19.  *** Auteur          : Boris Bertelsons  (InspirE)                         ***
  20.  *** Nom du fichier  : MOD_SB.PAS                                          ***
  21.  *** Date            : 04.04.1994                                          ***
  22.  *** Version         : 2.0                                                 ***
  23.  *** Compilateur     : Turbo Pascal 6.0 et supérieur                       ***
  24.  *****************************************************************************
  25.  
  26. }
  27.  
  28. {$F+}
  29. unit mod_sb;
  30.  
  31. interface uses crt,dos,variab;
  32.  
  33.  var andycount : word;
  34.  
  35. procedure wr_dsp_sb16(v : byte);
  36. {
  37. Par l'intermédiaire de cette procédure, vous pouvez sortir un
  38. octet sur le port de commandes de la carte Sound Blaster.
  39. }
  40.  
  41. Function SbReadByte : Byte;
  42. {
  43. Cette fonction permet de lire un octet de données sur la 
  44. carte Sound Blaster.
  45. }
  46.  
  47. Function Reset_Sb16 : boolean;
  48. {
  49. Par l'intermédiaire de cette fonction, vous pouvez réaliser 
  50. un reset de la carte Sound Blaster. Quand le reset a été effectué, 
  51. la carte renvoie la valeur TRUE, sinon la valeur FALSE. La
  52. fonction permet d'obtenir l'adresse de base de la carte.
  53. }
  54.  
  55. Function Detect_reg_Sb16 : boolean;
  56. {
  57. L'obtention de l'adresse de base dont il a été question ci-dessus
  58. est menée à bien par cette fonction. Elle donne à la variable 
  59. dsp_adr l'adresse de base de la carte Sound Blaster. Elle renvoie
  60. TRUE quand une adresse de base a été trouvée, sinon FALSE.
  61. }
  62.  
  63. Procedure Write_Mixer(Reg,Val : Byte);
  64. {
  65. Cette procédure écrit la valeur transmise à "Val" dans le
  66. registre de mixage "Reg". La procédure ne fonctionne qu'à
  67. partir de SB Pro.
  68. }
  69.  
  70. Function Read_Mixer(Reg : Byte) : byte;
  71. {
  72. Au moyen de cette fonction, vous pouvez lire une valeur
  73. dans le registre de mixage indiqué dans "Reg".
  74. }
  75.  
  76. Procedure Filtre_on;
  77. {
  78. Cette procédure désactive la mise en valeur des basses à
  79. partir de la carte SB Pro.
  80. }
  81.  
  82. Procedure Filtre_Mid;
  83. {
  84. Pour obtenir une sonorité normale sur les cartes à partir
  85. de SB Pro, vous pouvez utiliser cette procédure.
  86. }
  87.  
  88. Procedure Filtre_out;
  89. {
  90. En appelant cette procédure, vous faites mieux entendre 
  91. les sons aigus.
  92. }
  93.  
  94. Procedure Set_Balance(Valeur : byte);
  95. {
  96. Au moyen de cette procédure, vous pouvez régler la balance
  97. du son sur les cartes stéréo. "Valeur" peut prendre des
  98. valeurs comprises entre 0 (tout à gauche) et 15 (tout à droite). 
  99. }
  100.  
  101. Procedure Set_Volume(Valeur : byte);
  102. {
  103. Vous réglez au moyen de cette procédure le volume avec lequel 
  104. le fichier MOD sera exécuté. A partir de la carte SB Pro, le 
  105. volume est réglé matériellement au moyen du mixer. Sur la 
  106. carte SB habituelle, la régulation se fait par des moyens
  107. logiciels, à l'aide de la variable "outvolume"
  108. }
  109.  
  110. Procedure Reset_Mixer;
  111. {
  112. Exactement comme pour le DSP, il faut restaurer les valeurs 
  113. par défaut dans le mixer de la carte SB au moyen d'un reset.
  114. Le registre 0 de reset du mixer doit recevoir pour cela la
  115. valeur 0. La procédure s'en charge à votre place.
  116. }
  117.  
  118. Function Detect_Mixer_Sb16 : boolean;
  119. {
  120. Cette fonction sert à reconnaître la puce mixer. Elle renvoie 
  121. la valeur TRUE quand une puce mixer a été trouvée et FALSE
  122. dans le cas contraire. Elle est très importante car elle
  123. intervient pour distinguer les cartes SB. Lorsque la fonction 
  124. renvoie la valeur TRUE, cela veut dire que votre appareil est
  125. équipé d'une carte SB Pro.
  126. }
  127.  
  128. Procedure SbGetDSPVersion;
  129. {
  130. Pour distinguer entre SB Pro et SB16, vous avez besoin de 
  131. connaître le numéro de version de la carte. S'il est inférieur
  132. à 4, vous avez une SB Pro. Sinon, c'est une SB 16.
  133. }
  134.  
  135. Procedure Set_Timeconst_sb16(tc : byte);
  136. {
  137. Pour définir la constante timer de la Sound Blaster, vous
  138. avez besoin de cette fonction. La constante se calcule à 
  139. l'aide de la formule
  140.  
  141. tc:=256-(1.000.000/Fréquence du sample).
  142.  
  143. La constante que l'on obtient ainsi doit être transmise au
  144. moyen de la commande $40. Vous transmettrez à la procédure
  145. la constante calculée.
  146. }
  147.  
  148. Procedure Exit_Sb16;
  149. {
  150. Pour mettre fin au programme, il faut faire appel à cette
  151. procédure. Elle ramène l'interruption cachée SB à sa valeur
  152. précédente et elle restaure le masque initial de l'interruption.
  153. }
  154.  
  155. Procedure dsp_block_sb16(gr,dgr : word; bk : pointer; b1,b2 : boolean);
  156. {
  157. Cette fonction est destinée à vous faciliter la tâche quand
  158. il s'agit de sortir un bloc via DMA. Elle sort un bloc de la
  159. taille "gr" adressé par le pointeur "bk" via le DMA. Il se
  160. peut que vous vouliez sortir un sample ou que vous ayez au
  161. contraire besoin
  162. }
  163.  
  164. procedure mod_SetSpeed(msp : word);
  165.  
  166. procedure mod_Samplefreq(Rate : integer);
  167.  
  168. Procedure Calculate_music;
  169.  
  170. procedure mod_SetLoop(msl : word);
  171.  
  172. procedure voc_pause;
  173.  
  174. function charge_fichiermod(modnom : string;ispeed,iloop : integer;freq : byte) : integer;
  175.  
  176. function init_The_Mod : boolean;
  177.  
  178. procedure voc_done;
  179.  
  180. procedure write_sbConfig;
  181.  
  182. procedure Init_Voc(filename : string);
  183.  
  184. Procedure periodic_off;
  185.  
  186. Procedure Fin_mod;
  187.  
  188. Procedure periodic_on;
  189.  
  190. procedure voc_continue;
  191.  
  192. function Init_Sb : boolean;
  193.  
  194. const bpm : byte = 125;
  195.  
  196. var SaveExitProc : Pointer;
  197.  mycli : byte;
  198.  
  199.  music_played : boolean;
  200.  
  201. implementation
  202.  
  203. const
  204.  Speed3 : word = 58;
  205.  Loop3  : word = 42;
  206.  
  207. Var
  208.  Tonhauteur_voix : array[1..8] of word;
  209.  ton_haut : word;                       { Valeur qui se trouve dans  }
  210.                     { dans le fichier MOD        }
  211.  cible : pt;                             
  212.  Modp  : pointer;                       { Pointeur sur Rm_Song        }
  213.  note : array[1..8] of byte;
  214.  altx,alty : integer;
  215.  voix_actuelle : word;
  216.  
  217.  Mixed_data   : pointer;
  218.  Mixed_data_st : pointer;
  219.  
  220. {$L c:\edition\prog\fr\asm\modmix}
  221. procedure Voix_vide; external;
  222. {procedure voix_normale(voix_actuelle : word); external;}
  223. procedure voix_normale; external;
  224. procedure voix_normale_st; external;
  225.  
  226. var Portamento_Up_voix : array[1..8] of longint;
  227.     Portamento_Do_voix : array[1..8] of longint;
  228.  
  229. var Mixingproc_voix     :  array[1..8] of pointer;
  230.     voixvide            : pointer;
  231.  
  232.     effet_voix        : array[1..8] of byte;
  233.  
  234.     longueur_voix       : array[1..8] of longint;
  235.     loop_longueur_voix  : array[1..8] of longint;
  236.     Position_voix       : array[1..8] of longint;
  237.     loop_start_voix     : array[1..8] of longint;
  238.     Segment_voix        : array[1..8] of longint;
  239.     Notvol_voix         : array[1..8] of longint;
  240.     Incval_voix         : array[1..8] of longint;
  241.  
  242. var perfcount : word;
  243.  
  244.     var bsw : boolean;
  245.       vocb1,
  246.       vocb2,
  247.       buffer1,
  248.       buffer2 : pointer;
  249.     shiftfacteur,
  250.     shiftfacteur_stereo : word;
  251.  
  252. {
  253.  
  254.  **************************************************************************
  255.  ***                                                                    ***
  256.  ***                Routine du Timer - Handling                         ***
  257.  ***                                                                    ***
  258.  **************************************************************************
  259.  
  260. }
  261. procedure RegleTimer(Proc : pointer; Freq : word);
  262. var icompteur : word;
  263.     oldv : pointer;
  264. begin;
  265.  asm cli end;
  266.  icompteur := 1193180 DIV Freq;
  267.  Port[$43] := $36;
  268.  Port[$40] := Lo(Icompteur);
  269.  Port[$40] := Hi(Icompteur);
  270.  
  271.  Getintvec(8,OldV);
  272.  setintvec(OldTimerInt,OldV);
  273.  SetIntVec(8,Proc);
  274.  old_tCompteur := 1;
  275.  seccompteur  := 0;
  276.  Oldintcompteur := 0;
  277.  asm sti end;
  278. end;
  279.  
  280. procedure RestaureTimer;
  281. var oldv : pointer;
  282. begin;
  283.   asm cli end;
  284.   port[$43] := $36;
  285.   Port[$40] := 0;
  286.   Port[$40] := 0;
  287.   GetIntVec(OldTimerInt,OldV);
  288.   SetIntVec(8,OldV);
  289.   asm sti end;
  290. end;
  291.  
  292. procedure NouveauTimer; interrupt;
  293. var dr : registers;
  294. begin;
  295.  inc(perfcount);
  296.  inc(Seccompteur);
  297.  inc(oldintcompteur);
  298.  if oldintcompteur = 58 then begin;
  299.    oldintcompteur := 0;
  300.    intr(Oldtimerint,dr);
  301.  end;
  302.  if Seccompteur = timer_per_second then begin;
  303.    Seccompteur := 0;
  304.    inc(andycount);
  305.    inc(secpass);
  306.    if secpass = 60 then begin;
  307.      inc(minpass);
  308.      secpass := 0;
  309.    end;
  310.  end;
  311.  if not in_retrace then calculate_Music;
  312.  Port[$20] := $20;
  313. end;
  314.  
  315.  
  316. {
  317.  
  318.  **************************************************************************
  319.  ***                                                                    ***
  320.  ***            Routine de programmation des cartes Soundblasters       ***
  321.  ***                                                                    ***
  322.  **************************************************************************
  323.  
  324. }
  325.  
  326.  
  327. procedure wr_dsp_sb16(v : byte);
  328. begin;
  329.   while port[dsp_adr+$c] >= 128 do ;
  330.   port[dsp_adr+$c] := v;
  331. end;
  332.  
  333. FUNCTION SbReadByte : BYTE;
  334. {
  335.  La fonction attend, jusqu'à ce que la DSP puisse être lue et 
  336.  retourne alors la valeur lue.
  337. }
  338. begin;
  339.   while port[dsp_adr+$a] = $AA do ;     { attend que DSP soit prête }
  340.   SbReadByte := port[dsp_adr+$a];       { lit une valeur }
  341. end;
  342.  
  343. procedure SBreset;
  344. VAR bt,ct, stat : BYTE;
  345. begin;
  346.   PORT[dsp_adr+$6] := 1;
  347.   FOR ct := 1 TO 100 DO;
  348.   PORT[dsp_adr+$6] := 0;
  349.   bt := 0;
  350.   repeat
  351.     ct := 0;
  352.     repeat
  353.       stat := port[dsp_adr + $E];
  354.     until (ct > 8000) or (stat >= 128);
  355.     inc(bt);
  356.   until (bt > 100) or (port[dsp_adr + $A] = $AA);
  357. end;
  358.  
  359. FUNCTION Reset_SB16 : BOOLEAN;
  360. {
  361.  La fonction effectue un reset du DSP. Si le reset réussit,
  362.  elle retourne TRUE, sinon FALSE
  363. }
  364. CONST  ready = $AA;
  365. VAR ct, stat : BYTE;
  366. BEGIN
  367.   PORT[dsp_adr+$6] := 1;                { dsp_adr+$6 = fonction de reset }
  368.   FOR ct := 1 TO 100 DO;
  369.   PORT[dsp_adr+$6] := 0;
  370.   stat := 0;
  371.   ct   := 0;                            { Comparaison  ct < 100, car }
  372.   WHILE (stat <> ready)                 { l'initialisation dure    }
  373.   AND   (ct < 100)      DO BEGIN        { environ 100ms             }
  374.     stat := PORT[dsp_adr+$E];
  375.     stat := PORT[dsp_adr+$a];
  376.     INC(ct);
  377.   END;
  378.   Reset_SB16 := (stat = ready);
  379. END;
  380.  
  381.  
  382. FUNCTION Detect_reg_SB16 : BOOLEAN;
  383. {
  384.  La fonction retourne TRUE, quand une carte Soundblaster a pu  être
  385.  initialisée, sinon FALSE. La variable dsp_adr reçoit
  386.  l'adresse de base de la SB.
  387. }
  388. VAR
  389.   Port, Lst : WORD;
  390. BEGIN
  391.  Detect_Reg_SB16 := SbRegDetected;
  392.  IF SbRegDetected THEN EXIT;            { Exit, lorsque l'initialisation est faite }
  393.  Port := Startport;                     { Adresse SB possibles }
  394.  Lst  := Endport;                       { entre $210 et $280 !      }
  395.  WHILE (NOT SbRegDetected)
  396.  AND   (Port <= Lst)  DO BEGIN
  397.    dsp_adr := Port;
  398.    SbRegDetected := Reset_SB16;
  399.    IF NOT SbRegDetected THEN
  400.      INC(Port, $10);
  401.  END;
  402.  Detect_reg_SB16 := SbRegDetected;
  403. END;
  404.  
  405.  
  406. PROCEDURE Write_Mixer(Reg, Val: BYTE);
  407. begin;
  408.  Port[dsp_adr+$4] := Reg;
  409.  Port[dsp_adr+$5] := Val;
  410. END;
  411.  
  412.  
  413. FUNCTION Read_Mixer(Reg: BYTE) : BYTE;
  414. begin;
  415.   Port[dsp_adr+$4] := Reg;
  416.   Read_Mixer := Port[dsp_adr+$5];
  417. end;
  418.  
  419. procedure Filtre_on;
  420. {
  421. Cette procédure désactive la mise en valeur des basses à
  422. partir de la carte SB Pro.
  423. }
  424. var Aide : byte;
  425. begin;
  426.  if sb16detected then begin;
  427.    write_Mixer(68,64);
  428.    write_Mixer(69,64);
  429.    write_Mixer(70,255);
  430.    write_Mixer(71,255);
  431.  end else begin;
  432.    Aide := read_Mixer($0c);
  433.    Aide := Aide or 8;
  434.    Write_Mixer($0c,Aide);
  435.    Aide := read_Mixer($0e);
  436.    Aide := Aide AND 2;
  437.    write_Mixer($0e,Aide);
  438.  end;
  439. end;
  440.  
  441. procedure Filtre_MID;
  442. {
  443. Pour obtenir une sonorité normale sur les cartes à partir
  444. de SB Pro, vous pouvez utiliser cette procédure.
  445. }
  446. var Aide : byte;
  447. begin;
  448.  if sb16detected then begin;
  449.    write_Mixer(68,160);
  450.    write_Mixer(69,160);
  451.    write_Mixer(70,192);
  452.    write_Mixer(71,192);
  453.  end else begin;
  454.    Aide := read_Mixer($0e);
  455.    Aide := Aide OR 32;
  456.    write_Mixer($0e,Aide);
  457.  end;
  458. end;
  459.  
  460. procedure Filtre_out;
  461. {
  462. En appelant cette procédure, vous faites mieux entendre
  463. les sons aigus.
  464. }
  465.  
  466. var Aide : byte;
  467. begin;
  468.  if sb16detected then begin;
  469.    write_Mixer(68,192);
  470.    write_Mixer(69,192);
  471.    write_Mixer(70,160);
  472.    write_Mixer(71,160);
  473.  end else begin;
  474.    Aide := read_Mixer($0c);
  475.    Aide := Aide OR 247;
  476.    Write_Mixer($0c,Aide);
  477.    Aide := read_Mixer($0e);
  478.    Aide := Aide AND 2;
  479.    write_Mixer($0e,Aide);
  480.  end;
  481. end;
  482.  
  483. procedure Set_Balance(Valeur : byte);
  484.  
  485. Var left,right : byte;
  486. begin;
  487.  if Sb16Detected then begin;
  488.    left  := 12;
  489.    right := 12;
  490.    if Valeur < 12 then right := Valeur;
  491.    if Valeur > 12 then left  := 24-Valeur;
  492.    write_Mixer(50,(left  shl 4));
  493.    write_Mixer(51,(right shl 4));
  494.  end else begin;
  495.   Valeur := Valeur SHR 1;
  496.   case Valeur of
  497.      0..6 : begin;
  498.            write_Mixer(02,(7 shl 5)+(Valeur shl 1));
  499.          end;
  500.        07 : begin;
  501.            write_Mixer(02,(7 shl 5)+(7 shl 1));
  502.          end;
  503.       08..13 : begin;
  504.            write_Mixer(02,((13-Valeur) shl 5)+(7 shl 1));
  505.            end;
  506.      end;
  507.  end;
  508. end;
  509.  
  510. procedure Set_Volume(Valeur : byte);
  511.  
  512. begin;
  513.   if sb16detected then begin;
  514.     write_Mixer(48,(Valeur shl 3));
  515.     write_Mixer(49,(Valeur shl 3));
  516.   end else begin;
  517.     if MixerDetected then begin;
  518.       Valeur := Valeur Shr 2;
  519.       write_Mixer($22,(Valeur shl 5) + (Valeur shl 1));
  520.     end else begin;
  521.       outvolume := Valeur shl 1;
  522.     end;
  523.   end;
  524. end;
  525.  
  526. procedure reset_Mixer; assembler;
  527. asm
  528.   mov dx,dsp_adr+$4
  529.   mov al,0
  530.   out dx,al
  531.   mov cx,50
  532. @loop:
  533.   loop @loop
  534.   inc dx
  535.   out dx,al
  536. end;
  537.  
  538. FUNCTION Detect_Mixer_sb16 : BOOLEAN;
  539. VAR SaveReg : WORD;
  540.     NewReg  : WORD;
  541. BEGIN
  542.   Detect_Mixer_sb16 := MixerDetected;
  543.   IF (NOT SbRegDetected)
  544.   OR MixerDetected THEN EXIT;
  545.  
  546.  
  547.   Reset_Mixer;
  548.   SaveReg := Read_Mixer($22);
  549.   Write_Mixer($22, 243);
  550.   NewReg  := Read_Mixer($22);
  551.  
  552.  
  553.  
  554.   IF NewReg = 243 THEN begin;
  555.     MixerDetected := TRUE;
  556.     STEREO := True;
  557.   end;
  558.   Write_Mixer($22, SaveReg);
  559.   Detect_Mixer_sb16 := MixerDetected;
  560. END;
  561.  
  562. PROCEDURE SbGetDSPVersion;
  563. {
  564.  Fournit le numéro de version de la DSP et le dépose dans les variables
  565.  globales SBVERSMAJ et SBVERSMIN, ainsi que SBVERSSTR.
  566. }
  567. VAR i : WORD;
  568.     t : WORD;
  569.     s : STRING[2];
  570. BEGIN
  571.   Wr_dsp_sb16($E1);                  { $E1 = interroge le numéro de version }
  572.   SbVersMaj := SbReadByte;
  573.   SbVersMin := SbReadByte;
  574.   str(SbVersMaj, SbVersStr);
  575.   SbVersStr := SbVersStr + '.';
  576.   str(SbVersMin, s);
  577.   if SbVersMin > 9 then
  578.     SbVersStr := SbVersStr +       s
  579.   else
  580.     SbVersStr := SbVersStr + '0' + s;
  581. END;
  582.  
  583.  
  584. function wrt_dsp_adr_sb16 : string;
  585. begin;
  586.   case dsp_adr of
  587.     $210 : wrt_dsp_adr_sb16 := '210';
  588.     $220 : wrt_dsp_adr_sb16 := '220';
  589.     $230 : wrt_dsp_adr_sb16 := '230';
  590.     $240 : wrt_dsp_adr_sb16 := '240';
  591.     $250 : wrt_dsp_adr_sb16 := '250';
  592.     $260 : wrt_dsp_adr_sb16 := '260';
  593.     $270 : wrt_dsp_adr_sb16 := '270';
  594.     $270 : wrt_dsp_adr_sb16 := '280';
  595.    END;
  596. end;
  597.  
  598. function wrt_dsp_irq : string;
  599. begin;
  600.   case dsp_irq of
  601.      $2 : wrt_dsp_irq := '2 h';
  602.      $3 : wrt_dsp_irq := '3 h';
  603.      $5 : wrt_dsp_irq := '5 h';
  604.      $7 : wrt_dsp_irq := '7 h';
  605.     $10 : wrt_dsp_irq := '10 h';
  606.    END;
  607. end;
  608.  
  609. procedure Set_Timeconst_sb16(tc : byte);
  610. begin;
  611.   wr_dsp_sb16($40);
  612.   wr_dsp_sb16(tc);
  613. end;
  614.  
  615. procedure test_transmission;
  616. begin;
  617.    fillchar(buffer1^,3000,127);
  618.    Taillebloc := 2000;
  619.    dern_sortie := true;
  620.    Sampling_Rate := 211;
  621.    dsp_block_sb16(Taillebloc,Taillebloc,buffer1,true,false);
  622.    delay(100);
  623. end;
  624.  
  625. procedure write_sbConfig;
  626. begin;
  627.   clrscr;
  628.   if SbRegDetected then begin;
  629.     writeln('Carte son à l''adresse ',wrt_dsp_adr_sb16,'h avec une IRQ ',
  630.     wrt_dsp_irq);
  631.   end else begin;
  632.     writeln('Aucune carte son compatible Sound Blaster trouvé !');
  633.   end;
  634.   if MixerDetected then begin;
  635.     writeln('Mixer - Chip trouvé');
  636.     if SbVersMaj < 4 then
  637.       writeln('La carte détectée est',
  638.             ' une Sound Blaster Pro ou compatible')
  639.     else
  640.       writeln('La carte détéctée est',
  641.       ' une Sound Blaster 16 ASP ou compatible');
  642.   end else begin;
  643.     writeln('La carte détectée est',
  644.     ' une Sound Blaster ou compatible');
  645.   end;
  646.   writeln('Numéro de version : ',SbVersStr);
  647. end;
  648.  
  649. procedure Exit_Sb16;
  650. begin;
  651.   setintvec($8+dsp_irq,oldint);
  652.   port[$21] := Port[$21] or irqmsq;
  653.   port[dsp_adr+$c] := $d3;
  654.   Port[$20] := $20;
  655.   wr_dsp_sb16($D0);
  656. end;
  657.  
  658. procedure Jouer_Sb16(Segm,Offs,dgr,dsize : word);
  659. var li : word;
  660. begin;
  661.   port[$0A] := dma_ch+4;
  662.   Port[$0c] := 0;
  663.   Port[$0B] := $48+dma_ch;
  664.   Port[dma_adr[dma_ch]] := Lo(offs);
  665.   Port[dma_adr[dma_ch]] := Hi(offs);
  666.   Port[dma_wc[dma_ch]] := Lo(dgr-1);
  667.   Port[dma_wc[dma_ch]] := Hi(dgr-1);
  668.   Port[dma_page[dma_ch]] := Segm;
  669.   if sb16_outputlong <> dsize then begin;
  670.     wr_dsp_sb16($C6);
  671.     if stereo then begin;
  672.       wr_dsp_sb16($20);
  673.     end else
  674.       wr_dsp_sb16($00);
  675.     wr_dsp_sb16(Lo(dsize-1));
  676.     wr_dsp_sb16(Hi(dsize-1));
  677.     sb16_outputlong := dsize;
  678.   end else begin;
  679.     wr_dsp_sb16($45);
  680.   end;
  681.   Port[$0A] := dma_ch;
  682. end;
  683.  
  684. procedure Jouer_Sb(Segm,Offs,dgr,dsize : word);
  685. {
  686.  Cette procédure exécute le bloc adressé par Segm:Offs
  687.  de taille dsize. Il faut noter que le contrôleur DMA ne peut PAS
  688.  travailler en accédant aux pages...
  689. }
  690. var li : word;
  691. begin;
  692.   port[$0A] := dma_ch+4;                { Bloque le canal DMA }
  693.   Port[$0c] := 0;                       { Adresse du tampon (blk)  }
  694.   Port[$0B] := $48+dma_ch;              { Pour la sortie du son }
  695.   Port[dma_adr[dma_ch]] := Lo(offs);    { au DMA-Controller }
  696.   Port[dma_adr[dma_ch]] := Hi(offs);
  697.   Port[dma_wc[dma_ch]] := Lo(dgr-1);  { Taille du bloc }
  698.   Port[dma_wc[dma_ch]] := Hi(dgr-1);  { au DMA-Controller }
  699.   Port[dma_page[dma_ch]] := Segm;
  700.   Wr_dsp_sb16($14);
  701.   Wr_dsp_sb16(Lo(dsize-1));                  { Taille du bloc }
  702.   Wr_dsp_sb16(Hi(dsize-1));                  { à la DSP }
  703.   Port[$0A] := dma_ch;                  { Libère le canal DMA }
  704. end;
  705.  
  706.  
  707. procedure Jouer_SbPro(Segm,Offs,dgr,dsize : word);
  708. var li : word;
  709. begin;
  710.   port[$0A] := dma_ch+4;
  711.   Port[$0c] := 0;
  712.   Port[$0B] := $48+dma_ch;
  713.   Port[dma_adr[dma_ch]] := Lo(offs);
  714.   Port[dma_adr[dma_ch]] := Hi(offs);
  715.   Port[dma_wc[dma_ch]] := Lo(dgr-1);
  716.   Port[dma_wc[dma_ch]] := Hi(dgr-1);
  717.   Port[dma_page[dma_ch]] := Segm;
  718.  
  719.   wr_dsp_sb16($48);
  720.   wr_dsp_sb16(Lo(dsize-1));
  721.   wr_dsp_sb16(Hi(dsize-1));
  722.   wr_dsp_sb16($91);
  723.   Port[$0A] := dma_ch;
  724. end;
  725.  
  726. procedure dsp_block_sb16(gr,dgr : word;bk : pointer;b1,b2 : boolean);
  727. var l : longint;
  728.     pn,offs : word;
  729.     hbyte : byte;
  730.     a : word;
  731.     OldV,NewV,Aide : byte;
  732.     stereoreg : byte;
  733.     sr : word;
  734.     samps : byte;
  735. begin;
  736.   PLAYING_MOD := b1;
  737.   PLAYING_VOC := b2;
  738.  
  739.   dsp_rdy_sb16 := false;
  740.   l := 16*longint(pt(bk).sgm)+pt(bk).ofs;
  741.   pn := pt(l).sgm;
  742.   offs := pt(l).ofs;
  743.  
  744.   if PLAYING_MOD then begin;
  745.     set_timeconst_sb16(Sampling_Rate);
  746.     if sb16Detected then begin;
  747.       if stereo then  begin;
  748.     Jouer_Sb16(pn,offs,dgr*2,gr*2);
  749.       end else
  750.     Jouer_Sb16(pn,offs,dgr,gr);
  751.     end else begin;
  752.       if stereo then begin;
  753.     SR := word(-1000000 DIV (Sampling_Rate-256));
  754.     SR := SR * 2;
  755.     Samps := 256 - (1000000 DIV SR);
  756.     set_timeconst_sb16(Samps);
  757.     Jouer_SbPro(pn,offs,dgr*2,gr*2);
  758.       end else
  759.     Jouer_Sb(pn,offs,dgr,gr);
  760.     end;
  761.   end;
  762.  
  763.   if PLAYING_VOC then begin;
  764.     sb16_outputlong := 0;
  765.     set_timeconst_sb16(vblock.SR);
  766.     if sb16Detected then begin;
  767.       if stereo then begin;
  768.     Jouer_Sb16(pn,offs,dgr,gr);
  769.       end else begin;
  770.     Jouer_Sb16(pn,offs,dgr,gr);
  771.       end;
  772.     end else begin;
  773.       if stereo then begin;
  774.     Jouer_SbPro(pn,offs,dgr,gr);
  775.       end else begin;
  776.     Jouer_Sb(pn,offs,dgr,gr);
  777.       end;
  778.     end;
  779.   end;
  780. end;
  781.  
  782.  
  783.  
  784. {
  785. ***********************************************************************
  786. ***                                                                 ***
  787. ***                   Routines pour fichiers MOD                    ***
  788. ***                                                                 ***
  789. ***********************************************************************
  790. }                                                                             
  791.  
  792. procedure get_pctunel(hauteur : word;Var vk : longint);
  793. {
  794.  La procédure fournit à partir de la hauteur de son transmise (telle qu'elle
  795.  figure dans le fichier MOD) la valeur entière et les décimales nécessaires
  796.  pour la manipulation de la fréquence.
  797. }
  798. var nct : byte;
  799.     trouve : boolean;
  800. begin;
  801.  nct := 1;
  802.  trouve := false;
  803.  while (nct <= 70) and not trouve do   { jusqu'à aboutissement }
  804.  begin;                                 { ou une valeur dans le tableau }
  805.    if hauteur > Modoctave[nct] then
  806.      trouve := true;
  807.    inc(nct);
  808.  end;
  809.  if trouve then begin;
  810.    vk  := Incfacts[nct-tpw+12];
  811.  end else begin;
  812.    vk  := 0;              { Va chercher des valeurs dans le tableau. }
  813.  end;
  814. end;
  815.  
  816. function Notes_Nr(hauteur : word) : integer;
  817. var nct : byte;
  818.     trouve : boolean;
  819. begin;
  820.  nct := 1;
  821.  trouve := false;
  822.  while (nct <= 70) and not trouve do   { Jusqu'à aboutissement }
  823.  begin;                                 { ou dernière valeur dans le tableau }
  824.    if hauteur > Modoctave[nct] then
  825.      trouve := true;
  826.    inc(nct);
  827.  end;
  828.  if trouve then begin;
  829.    Notes_nr := nct-1;
  830.  end else begin;
  831.    Notes_nr := -1;
  832.  end;
  833. end;
  834.  
  835. function Volume_notes(Stm : byte) : byte;
  836. begin;
  837.  Volume_notes := Rm_Song[mli,Stm,4];
  838. end;
  839.  
  840. var mixed_posi : word;
  841.     calc_size : word;
  842.  
  843.  
  844. procedure intra_boucle_4;
  845. {
  846.  On réalise ici le mixage des données. Le tampon
  847.  est rempli avec les données calculées. C'est la
  848.  version MONO de la routine.
  849. }
  850. begin;
  851.   calc_size := taillebloc;
  852.   if bsw then
  853.     cible := pt(buffer1)
  854.   else
  855.     cible := pt(buffer2);
  856.     fillchar(mixed_data^,8000,128);
  857. asm
  858.     mov cx,1
  859. @voix_loop:
  860.     mov mixed_posi,0
  861.     mov voix_actuelle,cx
  862.     mov si,cx
  863.     dec si
  864.     shl si,2
  865.     call dword ptr Mixingproc_voix[si]
  866.  
  867.     inc cx
  868.     cmp cx,voix
  869.     jbe @voix_loop
  870.  
  871.     mov mixed_posi,0
  872.     mov cx,calc_size
  873. @Mixed_2_blk:
  874.     les di,mixed_data
  875.     add di,mixed_posi
  876.     mov ax,es:[di]
  877.     push cx
  878.     mov cx,shiftfacteur
  879.     shr ax,cl
  880.     pop cx
  881.     add mixed_posi,2
  882.  
  883.     mov bx,cible.sgm                                                        { Ecrit les octets dans la cible }
  884.     mov es,bx
  885.     mov bx,cible.ofs
  886.     mul outvolume
  887.     shr ax,6
  888.     mov es:[bx],al
  889.     inc cible.ofs
  890.  
  891.     loop @mixed_2_blk
  892. end;
  893. end;
  894.  
  895.  
  896. procedure intra_boucle_4_stereo;
  897. {
  898.  On réalise ici le mixage des données. Le tampon
  899.  est rempli par les données calculées. C'est la
  900.  version stéréo de la routine.
  901. }
  902. begin;
  903.   calc_size := taillebloc;
  904.   if bsw then
  905.     cible := pt(buffer1)
  906.   else
  907.     cible := pt(buffer2);
  908.     fillchar(mixed_data^,8000,128);
  909.     fillchar(mixed_data_st^,8000,128);
  910. asm
  911.     mov cx,1
  912. @voix_loop:
  913.     mov mixed_posi,0
  914.     mov voix_actuelle,cx
  915.     mov si,cx
  916.     dec si
  917.     shl si,2
  918.     call dword ptr Mixingproc_voix[si]
  919.  
  920.     inc cx
  921.     cmp cx,voix
  922.     jbe @voix_loop
  923.  
  924.     mov mixed_posi,0
  925.     mov cx,calc_size
  926. @Mixed_2_blk:
  927.     les di,mixed_data
  928.     add di,mixed_posi
  929.     mov ax,es:[di]
  930.     push cx
  931.     mov cx,shiftfacteur_stereo
  932.     shr ax,cl
  933.     pop cx
  934.  
  935.     mov bx,cible.sgm     { Ecrit les octets dans la cible }
  936.     mov es,bx
  937.     mov bx,cible.ofs
  938.     mul outvolume
  939.     shr ax,6
  940.     mov es:[bx],al
  941.     inc cible.ofs
  942.  
  943.     les di,mixed_data_st
  944.     add di,mixed_posi
  945.     mov ax,es:[di]
  946.     push cx
  947.     mov cx,shiftfacteur_stereo
  948.     shr ax,cl
  949.     pop cx
  950.     add mixed_posi,2
  951.  
  952.     mov bx,cible.sgm       { Ecrit l'octet dans la cible}
  953.     mov es,bx
  954.     mov bx,cible.ofs
  955.     mul outvolume
  956.     shr ax,6
  957.     mov es:[bx],al
  958.     inc cible.ofs
  959.  
  960.     loop @mixed_2_blk
  961. end;
  962. end;
  963.  
  964.  
  965. procedure mixe_start_4;
  966. var rdiff : real;
  967.     dummy : byte;
  968.     var li : integer;
  969. begin;
  970.  for li := 1 to Voix do begin;
  971.    if note[li] <> 0 then begin;
  972.      tonhauteur_Voix[li] := (Rm_Song[mli,li,1] and $0F)*256+Rm_Song[mli,li,2];
  973.      get_pctunel(tonhauteur_Voix[li],Incval_Voix[li]);
  974.    end;
  975.  
  976.    ls[li] := loop_s[In_st[li]];
  977.    ll[li] := loop_l[In_st[li]];
  978.    if ll[li] > 30 then inl[li] := ll[li]+ls[li];
  979.    Loop_Longueur_Voix[li] := ll[li];
  980.    Loop_Start_Voix[li]  := ls[li];
  981.  
  982.    case effet_Voix[li] of
  983.      1 : begin;
  984.         inc(Incval_Voix[li],Portamento_up_Voix[li]);
  985.      end;
  986.      2 : begin;
  987.         inc(Incval_Voix[li],Portamento_do_Voix[li]);
  988.      end;
  989.    end;
  990.  end;
  991. end;
  992.  
  993. procedure effect_handling(li : integer);
  994. var idx : word;
  995.     Portamento_Speed : word;
  996.     Startnote,
  997.     endnote : word;
  998.     startinc,
  999.     endinc : longint;
  1000.  
  1001. begin;
  1002.  if Rm_Song[mli,li,3] and $0F <= 15 then begin;
  1003.    Eff[li] := 0;
  1004.    case (Rm_Song[mli,li,3] and $0F) of
  1005.       01 : begin;
  1006.          effet_Voix[li] := 1;
  1007.          Portamento_Speed := Rm_Song[mli,li,4];
  1008.          Startnote := Notes_nr(tonhauteur_Voix[li]);
  1009.          Endnote   := Startnote+Portamento_Speed;
  1010.          get_pctunel(Modoctave[Startnote],Startinc);
  1011.          get_pctunel(Modoctave[Endnote],Endinc);
  1012.          Portamento_up_Voix[li] := round((Endinc - Startinc) / playspeed);
  1013.        end;
  1014.       02 : begin;
  1015.          effet_Voix[li] := 2;
  1016.          Portamento_Speed := Rm_Song[mli,li,4];
  1017.          Startnote := Notes_nr(tonhauteur_Voix[li]);
  1018.          Endnote   := Startnote-Portamento_Speed;
  1019.          get_pctunel(Modoctave[Startnote],Startinc);
  1020.          get_pctunel(Modoctave[Endnote],Endinc);
  1021.          Portamento_do_Voix[li] := round((Endinc - Startinc) / playspeed);
  1022.        end;
  1023.        9 : begin;  { Sample offset }
  1024.          Position_Voix[li] := longint(Rm_Song[mli,li,4]) shl 24;
  1025.        end;
  1026.       13 : begin;
  1027.                    mli := 64;
  1028.                  end;
  1029.       11 : begin;
  1030.                    mli := 64;
  1031.                          mlj := Rm_Song[mli,li,4];
  1032.                  end;
  1033.       12 : begin;
  1034.          Notvol_Voix[li]  := Volume_notes(li);
  1035.        end;
  1036.       14 : begin;
  1037.          case (Rm_Song[mli,li,4] shr 4) of
  1038.         12 : begin;
  1039.                inl[li]    := 0;
  1040.                Notvol_Voix[li]   := 0;
  1041.                inp[li]    := 0;
  1042.                NotVol[li]    := 0;
  1043.              end;
  1044.          end;
  1045.        end;
  1046.       15 : begin;
  1047.          idx := Rm_Song[mli,li,4];
  1048.          if idx <= $f then begin;
  1049.            Playspeed    := idx;
  1050.            Speed := Playspeed*105 div 10;
  1051.            taillebloc := Speed * Sound_Boucle;
  1052.          end else begin;
  1053.            bpm := idx;
  1054.            mod_SetLoop(Sampling_Frequence div (BPM * 4));
  1055.            Speed := Playspeed*105 div 10;
  1056.            taillebloc := Speed * Sound_Boucle;
  1057.          end;
  1058.          if taillebloc < 40 then taillebloc := 40;
  1059.          if taillebloc > 4000 then taillebloc := 4000;
  1060.                  end;
  1061.     end;
  1062.   end;
  1063. end;
  1064.  
  1065.  
  1066. procedure nmw_all_4;
  1067. const stereoprocs : array[1..8] of pointer =
  1068.   (@Voix_normale,@Voix_normale,@Voix_normale_st,@Voix_normale_st,
  1069.    @Voix_normale,@Voix_normale,@Voix_normale_st,@Voix_normale_st);
  1070. var idx : byte;
  1071.     li : integer;
  1072. begin;
  1073.    inc(mli);
  1074.    if mli > 64 then mli := 1;
  1075.    if mli = 1 then begin;
  1076.      inc(mlj);
  1077.      if mlj > Chansonlongueur then begin;
  1078.        if mloop then begin;
  1079.      mlj := 1;
  1080.      move(rm[Chanson[mlj]]^,Rm_song,2048);
  1081.        end else begin;
  1082.      asm
  1083.        call [periodic_arret]
  1084.      end;
  1085.      music_off := true;
  1086.      Mod_Fin := true;
  1087.        end;
  1088.      end else begin;
  1089.      move(rm[Chanson[mlj]]^,Rm_song,2048);
  1090.      end;
  1091.    end;
  1092.  
  1093.   for li := 1 to Voix do begin;
  1094.     effet_Voix[li] := 0;
  1095.     note[li] := (Rm_Song[mli,li,1] AND $F0)+((Rm_Song[mli,li,3] AND $F0) shr 4);
  1096.     if note[li] <> 0 then begin;
  1097.       if stereo then begin;
  1098.     Mixingproc_voix[li] := stereoprocs[li];
  1099.       end else begin;
  1100.     Mixingproc_voix[li] := @Voix_normale;
  1101.       end;
  1102.       Frappe_notes[li] := 500;
  1103.       In_St[li]  := note[li];
  1104.       inst[li]  := Ptr(pt(Samp[In_St[li]]).sgm,pt(Samp[In_St[li]]).ofs);
  1105.       Longueur_Voix[li]      := sam_l[In_St[li]];
  1106.       Position_Voix[li]    := 0;
  1107.       Notvol_Voix[li]      := vol_inst[in_St[li]];
  1108.       Segment_Voix[li]     := seg(inst[li]^);
  1109.     end;
  1110.     effect_handling(li);
  1111.   end;
  1112. end;
  1113.  
  1114.  
  1115. procedure initialiser_mixage;
  1116. begin;
  1117.   asm
  1118.     call [mixer_proc]
  1119.   end;
  1120. end;
  1121.  
  1122. FUNCTION ConvertString(Source : Pointer; Size : BYTE):String;
  1123. VAR
  1124.    WorkStr : String;
  1125. BEGIN
  1126.    Move(Source^,WorkStr[1],Size);
  1127.    WorkStr[0] := CHR(Size);
  1128.    ConvertString := WorkStr;
  1129. END;
  1130.  
  1131. function init_Song : boolean;
  1132. const idt1 : string = 'FLT4';
  1133.       idt2 : string = 'M.K.';
  1134.       idt3 : string = '8CHN';
  1135. var rmod : file;
  1136.     sgr : word;                         { taille d'un sample }
  1137.     inststart : longint; { Position où démarrent les données sample dans le fichier }
  1138.     t_fichier : longint;                    { La taille du fichier MOD }
  1139.     Mkg : array[1..4] of char;          { pour reconnaître le type de mode m }
  1140.     helpsp : ^byte;
  1141.     strptr : pointer;
  1142.     idtch : array[1..4] of char;
  1143.     idtstr : string;
  1144.     instance : byte;
  1145.     idx : integer;
  1146. begin;
  1147.  In_St[1] := 0;
  1148.  In_St[2] := 0;
  1149.  In_St[3] := 0;
  1150.  In_St[4] := 0;
  1151.  In_St[5] := 0;
  1152.  In_St[6] := 0;
  1153.  In_St[7] := 0;
  1154.  In_St[8] := 0;
  1155.  for mlj := 0 to 128 do
  1156.    Chanson[mlj] := 0;
  1157.  {$I-}
  1158.  assign(rmod,Mod_Nom);
  1159.  reset(rmod,1);
  1160.  {$I+}
  1161.  if IOresult <> 0 then begin;
  1162.    init_song := false;
  1163.    exit;
  1164.  end;
  1165.  if taillefimod <> 0 then t_fichier := taillefimod else
  1166.  t_fichier := filesize(rmod);
  1167.  inststart := t_fichier;
  1168.  seek(rmod,1080);
  1169.  blockread(rmod,idtch,4);
  1170.  idtstr := idtch;
  1171.  if (idtstr <> idt1) and (idtstr <> idt2)
  1172.  and (idtstr <> idt3) then begin;
  1173.    instance := 15;
  1174.  end else begin;
  1175.    instance := 31;
  1176.  end;
  1177.  
  1178.  if instance = 31 then begin;  { 31 voix obtenus par leurs numéros d'identité}
  1179.  for mlj := 1 to 31 do begin;
  1180.   idx := mlj;
  1181.   seek(rmod,msp+42+(idx-1)*30);
  1182.   blockread(rmod,sgr,2);
  1183.   sgr := swap(sgr) * 2;
  1184.   if sgr <> 0 then inststart := inststart - sgr;
  1185.   Sam_l[idx] := sgr;
  1186.   seek(rmod,msp+45+(idx-1)*30);
  1187.   blockread(rmod,vol_inst[idx],1);
  1188.   blockread(rmod,loop_s[idx],2);
  1189.   blockread(rmod,loop_l[idx],2);
  1190.   loop_s[idx] := swap(loop_s[idx])*2;
  1191.   loop_l[idx] := swap(loop_l[idx])*2;
  1192.  end;
  1193.  
  1194.  seek(rmod,msp+1080);
  1195.  blockread(rmod,Mkg,4);
  1196.  if pos('8CHN',Mkg) <> 0 then begin;
  1197.    Taille_patt    := 2048;
  1198.    Voix        := 8;
  1199.    shiftfacteur        := 3;
  1200.    shiftfacteur_stereo := 3;
  1201.  end else begin;
  1202.  { Fichier MOD - 4 voix }
  1203.    Taille_patt    := 1024;
  1204.    Voix        := 4;
  1205.    shiftfacteur        := 2;
  1206.    shiftfacteur_stereo := 2;
  1207.  end;
  1208.  Mixer_Proc     := @mixe_start_4;
  1209.  nmw_Proc       := @nmw_all_4;
  1210.  if stereo then
  1211.    proc_intra     := @intra_boucle_4_stereo
  1212.  else
  1213.    proc_intra     := @intra_boucle_4;
  1214.  
  1215.  
  1216.  seek(rmod,msp+inststart);
  1217.  for mlj := 1 to 31 do begin;
  1218.   idx := mlj;
  1219.   getmem(Samp[idx],Sam_l[idx]);
  1220.   blockread(rmod,Samp[idx]^,sam_l[idx]);
  1221.  end;
  1222.  
  1223.  t_fichier := inststart - 1083;
  1224.  nb_patt := t_fichier div Taille_patt;
  1225.  for mlj := 0 to nb_patt-1 do begin;
  1226.    getmem(rm[mlj],2048);
  1227.    fillchar(rm[mlj]^,2048,0);
  1228.    seek(rmod,msp+1084+mlj*Taille_patt);
  1229.    helpsp := ptr(seg(rm[mlj]^),ofs(rm[mlj]^));
  1230.    for mli := 0 to 63 do begin;
  1231.      helpsp := ptr(seg(rm[mlj]^),ofs(rm[mlj]^)+mli*32);
  1232.      blockread(rmod,helpsp^,Taille_patt div 64);
  1233.    end;
  1234.  end;
  1235.  seek(rmod,msp+952);
  1236.  blockread(rmod,Chanson,128);
  1237.  
  1238.  getmem(strptr,25);
  1239.  for i := 0 to 30 do begin;
  1240.    seek(rmod,msp+20+i*30);
  1241.    blockread(rmod,strptr^,22);
  1242.    noms_inst[i+1] := convertstring(strptr,22);
  1243.  end;
  1244.  seek(rmod,msp);
  1245.  blockread(rmod,strptr^,20);
  1246.  Nom_chanson := convertstring(strptr,20);
  1247.  freemem(strptr,25);
  1248.  
  1249.  seek(rmod,msp+950); { à partir de 470}
  1250.  blockread(rmod,Chansonlongueur,1);
  1251.  end else begin;
  1252.  for mlj := 1 to 15 do begin;
  1253.   seek(rmod,msp+42+(mlj-1)*30);
  1254.   blockread(rmod,sgr,2);
  1255.   sgr := swap(sgr) * 2;
  1256.   if sgr <> 0 then inststart := inststart - sgr;
  1257.   Sam_l[mlj] := sgr;
  1258.   seek(rmod,msp+45+(mlj-1)*30);
  1259.   blockread(rmod,vol_inst[mlj],1);
  1260.   blockread(rmod,loop_s[mlj],2);
  1261.   blockread(rmod,loop_l[mlj],2);
  1262.   loop_s[mlj] := swap(loop_s[mlj])*2;
  1263.   loop_l[mlj] := swap(loop_l[mlj])*2;
  1264.  end;
  1265.  
  1266.  for mlj := 16 to 31 do begin;
  1267.   Sam_l[mlj] := 0;
  1268.   loop_s[mlj] := 0;
  1269.   loop_l[mlj] := 0;
  1270.  end;
  1271.  
  1272.  if pos('8CHN',Mkg) <> 0 then begin;
  1273.    Taille_patt    := 2048;
  1274.    Voix        := 8;
  1275.    shiftfacteur        := 3;
  1276.    shiftfacteur_stereo := 3;
  1277.  end else begin;
  1278.  { Fichier MOD à quatre voix }
  1279.    Taille_patt    := 1024;
  1280.    Voix        := 4;
  1281.    shiftfacteur        := 2;
  1282.    shiftfacteur_stereo := 2;
  1283.  end;
  1284.  Mixer_Proc := @mixe_start_4;
  1285.  nmw_Proc       := @nmw_all_4;
  1286.  if stereo then
  1287.    proc_intra     := @intra_boucle_4_stereo
  1288.  else
  1289.    proc_intra     := @intra_boucle_4;
  1290.  
  1291.  seek(rmod,msp+inststart);
  1292.  for mlj := 1 to 15 do begin;
  1293.    getmem(Samp[mlj],Sam_l[mlj]);
  1294.    blockread(rmod,Samp[mlj]^,sam_l[mlj]);
  1295.  end;
  1296.  
  1297.  t_fichier := inststart - 603;
  1298.  nb_patt := t_fichier div Taille_patt;
  1299.  for mlj := 0 to nb_patt-1 do begin;
  1300.    getmem(rm[mlj],2048);
  1301.    fillchar(rm[mlj]^,2048,0);
  1302.    seek(rmod,msp+1084+mlj*Taille_patt);
  1303.    helpsp := ptr(seg(rm[mlj]^),ofs(rm[mlj]^));
  1304.    for mli := 0 to 63 do begin;
  1305.      helpsp := ptr(seg(rm[mlj]^),ofs(rm[mlj]^)+mli*32);
  1306.      blockread(rmod,helpsp^,Taille_patt div 64);
  1307.    end;
  1308.  end;
  1309.  seek(rmod,msp+472);
  1310.  blockread(rmod,Chanson,128);
  1311.  
  1312.  getmem(strptr,25);
  1313.  for i := 0 to 14 do begin;
  1314.    seek(rmod,msp+20+i*30);
  1315.    blockread(rmod,strptr^,22);
  1316.    noms_inst[i+1] := convertstring(strptr,22);
  1317.  end;
  1318.  
  1319.  for i := 15 to 30 do begin;
  1320.    noms_inst[i+1] := '';
  1321.  end;
  1322.  seek(rmod,msp);
  1323.  blockread(rmod,strptr^,20);
  1324.  Nom_chanson := convertstring(strptr,20);
  1325.  freemem(strptr,25);
  1326.  
  1327.  seek(rmod,msp+470);
  1328.  blockread(rmod,Chansonlongueur,1);
  1329.  end;
  1330.  
  1331.  
  1332.  mlj := 0;
  1333.  mli := 0;
  1334.  close(rmod);
  1335.  init_song := true;
  1336. end;
  1337.  
  1338.  
  1339. procedure exit_song;
  1340. begin;
  1341.  Port[dsp_adr+$C] := $D3;
  1342.  halt(0);
  1343. end;
  1344.  
  1345. procedure Free_Soundmem;
  1346. begin;
  1347.  if music_played then begin;
  1348.  for mlj := 0 to Nb_patt-1 do begin;
  1349.    freemem(rm[mlj],2048);
  1350.  end;
  1351.  end;
  1352. end;
  1353.  
  1354. procedure init_sbperiod(p : pointer);
  1355. begin;
  1356.   periodic_arret := p;
  1357. end;
  1358.  
  1359. procedure mod_SetLoopflag(loopen : boolean);
  1360. begin;
  1361.  mloop := loopen;
  1362. end;
  1363.  
  1364. procedure mod_SetMultiply(msm : word);
  1365. begin;
  1366.  modmultiply := msm;
  1367. end;
  1368.  
  1369. procedure mod_SetLoop(msl : word);
  1370. begin;
  1371.  Sound_Boucle := msl;
  1372.  loop3 := msl;
  1373. end;
  1374.  
  1375. procedure mod_SetSpeed(msp : word);
  1376. begin;
  1377.  speed := msp;
  1378.  Speed3 := msp;
  1379. end;
  1380.  
  1381. procedure mod_autodetect(what : boolean);
  1382. begin;
  1383.  if what then mautodet := true else mautodet := false;
  1384. end;
  1385.  
  1386. procedure mod_transpose(transposerwert : integer);
  1387. begin;
  1388.   tpw := transposerwert;
  1389. end;
  1390.  
  1391. procedure init_data;
  1392. Var i,j : integer;
  1393. begin;
  1394.  m_played := false;
  1395.  In_St[1] := 0;
  1396.  In_St[2] := 0;
  1397.  In_St[3] := 0;
  1398.  In_St[4] := 0;
  1399.  In_St[5] := 0;
  1400.  In_St[6] := 0;
  1401.  In_St[7] := 0;
  1402.  In_St[8] := 0;
  1403.  Note1 := 0;
  1404.  Note2 := 0;
  1405.  Note3 := 0;
  1406.  Note4 := 0;
  1407.  Note5 := 0;
  1408.  Note6 := 0;
  1409.  Note7 := 0;
  1410.  Note8 := 0;
  1411.  Frappe_Notes[1] := 0;
  1412.  Frappe_Notes [2] := 0;
  1413.  Frappe_Notes [3] := 0;
  1414.  Frappe_Notes [4] := 0;
  1415.  Frappe_Notes [5] := 0;
  1416.  Frappe_Notes [6] := 0;
  1417.  Frappe_Notes [7] := 0;
  1418.  Frappe_Notes [8] := 0;
  1419.  fillchar(inl,sizeof(inl),0);
  1420.  notvol1 := 0; notvol2 := 0; notvol3 := 0; notvol4 := 0;
  1421.  notvol5 := 0; notvol6 := 0; notvol7 := 0; notvol8 := 0;
  1422.  fillchar(Rm_Song,2048,0);
  1423. end;
  1424.  
  1425. procedure init_Paramtable;
  1426. var ls : byte;
  1427.     h : real;
  1428. begin;
  1429. {  playspeed := 6;
  1430.   for ls := 1 to 31 do begin;
  1431.     if ls <= 3 then
  1432.       ModPara[ls].mult := 100
  1433.     else
  1434.       ModPara[ls].mult := 105;
  1435.     ModPara[ls].Speed := ls*ModPara[ls].mult div 10;
  1436.     ModPara[ls].bgr := ModPara[ls].Speed*Sound_Schleifen;
  1437.    end;}
  1438. end;
  1439.  
  1440. procedure mod_Samplefreq(Rate : integer);
  1441. var h : real;
  1442. begin;
  1443.   case Rate of
  1444.      08 : begin;
  1445.         Sampling_Rate := 131;
  1446.         set_timeconst_sb16(131);
  1447.         mod_transpose(1);
  1448.         mod_SetLoop(15);
  1449.         TailleBloc := Speed * Sound_Boucle;
  1450.         Sampling_Frequence := 8000;
  1451.         init_Paramtable;
  1452.       end;
  1453.      10 : begin;
  1454.         Sampling_Rate := 156;
  1455.         set_timeconst_sb16(156);
  1456.         mod_transpose(5);
  1457.         mod_SetLoop(19);
  1458.         TailleBloc := Speed * Sound_Boucle;
  1459.         Sampling_Frequence := 10000;
  1460.         init_Paramtable;
  1461.       end;
  1462.      13 : begin;
  1463.         Sampling_Rate := 181;
  1464.         set_timeconst_sb16(181);
  1465.         mod_transpose(10);
  1466.         mod_SetLoop(25);
  1467.         TailleBloc := Speed * Sound_Boucle;
  1468.         Sampling_Frequence := 13333;
  1469.         init_Paramtable;
  1470.       end;
  1471.      16 : begin;
  1472.         Sampling_Rate := 196;
  1473.         set_timeconst_sb16(196);
  1474.         mod_transpose(14);
  1475.         mod_SetLoop(32);
  1476.         Taillebloc := Speed * Sound_Boucle;
  1477.         Sampling_Frequence := 16666;
  1478.         init_Paramtable;
  1479.       end;
  1480.      22 : begin;
  1481.         Sampling_Rate := 211;
  1482.         set_timeconst_sb16(211);
  1483.         mod_transpose(19);
  1484.         mod_SetLoop(44);
  1485.         Taillebloc := Speed * Sound_Boucle;
  1486.         Sampling_Frequence := 22222;
  1487.         init_Paramtable;
  1488.       end;
  1489.    end;
  1490. end;
  1491.  
  1492. procedure Sound_handler;
  1493. var li : integer;
  1494. begin;
  1495.  if mycli <> 0 then exit;
  1496.  mycli := 1;
  1497.  if (Loop_pos > Speed) then begin;
  1498.    if phase_2 then begin;
  1499.      Perfcount := 0;
  1500.      asm
  1501.        call [nmw_proc]
  1502.      end;
  1503.      Initialiser_mixage;
  1504.      Loop_pos:=0;
  1505.      phase_2 := false;
  1506.      phase_1 := true;
  1507.      if outfading then
  1508.        if outvolume >= 2 then dec(outvolume,2);
  1509.      for li := 1 to 8 do
  1510.        if Frappe_notes[li] > 50 then dec(Frappe_notes[li],50);
  1511.    end;
  1512.  end else begin;
  1513.      asm call [proc_intra] end;
  1514.    Loop_pos := Speed+2;
  1515.  end;
  1516.  mycli := 0;
  1517. end;
  1518.  
  1519. procedure calculate_music; assembler;
  1520. asm
  1521.  cmp mycli,0
  1522.  jne  @fin_stop
  1523.  cmp  music_off,0
  1524.  jne   @fin_stop
  1525.  pusha
  1526.  call Sound_handler
  1527.  popa
  1528.  @fin_stop:
  1529. end;
  1530.  
  1531.  
  1532. procedure mod_waitretrace(num : byte);
  1533. var dl : integer;
  1534. begin;
  1535.  in_retrace := true;
  1536.  for dl := 1 to num do
  1537.     calculate_music;
  1538. asm
  1539.   push dx
  1540. @l1:
  1541.   mov dx,3dah
  1542.   in al,dx
  1543.   and al,8h
  1544.   jnz @l1
  1545. @l2:
  1546.   mov dx,3dah
  1547.   in al,dx
  1548.   and al,8h
  1549.   jz @l2
  1550.   pop dx
  1551. End;
  1552.  in_retrace := false;
  1553. end;
  1554.  
  1555. function charge_fichiermod(modnom : string;ispeed,iloop : integer;freq : byte) : integer;
  1556. var df : file;
  1557.     sterreg : byte;
  1558.     t_f : longint;
  1559. begin;
  1560.  PLAYING_MOD := true;
  1561.  PLAYING_VOC := false;
  1562.  outfading := false;
  1563.  outvolume := 63;
  1564.  Mod_Nom := modnom;
  1565.  {$I-}
  1566.  assign(df,Mod_nom);
  1567.  reset(df,1);
  1568.  {$I+}
  1569.  if IOResult <> 0 then begin;
  1570.    {$I-}
  1571.    close(df);
  1572.    charge_fichiermod := -1;                 { Fichier non trouvé !     }
  1573.    exit;
  1574.  end;
  1575.  {$I-}
  1576.  t_f := filesize(df);
  1577.  close(df);
  1578.  music_played := true;
  1579.  music_off := false;
  1580.  Mod_fin := false;
  1581.  
  1582.  if ispeed <> AUTO then Speed3 := ispeed;
  1583.  if iloop <> AUTO then Loop3  := iloop;
  1584.  if force_mono then stereo := false;
  1585.  if force_sb then begin;
  1586.    if Sb16Detected then stereo := false;
  1587.    Sb16Detected := false;
  1588.  end;
  1589.  
  1590.  if SBProdetected then begin;
  1591.    if stereo then begin;
  1592.      sterreg := Read_Mixer($0e);
  1593.      write_Mixer($0e,sterreg OR 2);
  1594.    end else begin;
  1595.      sterreg := Read_Mixer($0e);
  1596.      write_Mixer($0e,sterreg AND $FD);
  1597.    end;
  1598.  end;
  1599.  init_data;
  1600.  if init_song then begin;
  1601.    phase_1 := false;
  1602.    phase_2 := true;
  1603.    mycli := 0;
  1604.    mod_Samplefreq(freq);
  1605.    Playspeed    := 6;
  1606.    Speed := Playspeed*105 div 10;
  1607.    bpm := 125;
  1608.    mod_SetLoop(Sampling_Frequence div (BPM * 4));
  1609.    taillebloc := Speed * Sound_Boucle;
  1610.    if taillebloc < 100 then taillebloc := 100;
  1611.    if taillebloc > 4000 then taillebloc := 4000;
  1612.  
  1613.    asm call [nmw_proc] end;
  1614.    set_timeconst_sb16(Sampling_Rate);
  1615.    Initialiser_mixage;
  1616.    Secpass := 0;
  1617.    Minpass := 0;
  1618.    wr_dsp_sb16($D1);
  1619.    if sb16detected or sbprodetected then begin;
  1620.        Filtre_Mid;
  1621.      Set_Balance(Balance);
  1622.      Set_Volume(Mastervolume);
  1623.    end;
  1624.    Charge_fichiermod := 0;
  1625.  end else begin;
  1626.    Charge_fichiermod := -3;  { Erreur au chargement de la chanson }
  1627.  end;
  1628. end;
  1629.  
  1630.  
  1631.  
  1632. procedure fin_mod;
  1633. var mlj : integer;
  1634. begin;
  1635.  Free_Soundmem;
  1636.  for mlj := 1 to 31 do begin;
  1637.    freemem(Samp[mlj],Sam_l[mlj]);
  1638.  end;
  1639.  mod_terminated := true;
  1640. end;
  1641.  
  1642.  
  1643. Procedure periodic_on;
  1644. Begin
  1645.  Outvolume:=64;
  1646.  dern_sortie := false;
  1647. { for Loop_pos := 1 to Speed do begin;}
  1648.    asm call [proc_intra] end;
  1649. { end;}
  1650.  dsp_block_sb16(taillebloc,taillebloc,buffer1,true,false);
  1651.  bsw := not bsw;
  1652.  Loop_pos := 0;
  1653.  asm
  1654.    call [nmw_proc]
  1655.  end;
  1656.  Initialiser_mixage;
  1657.  
  1658.  init_sbperiod(@periodic_off);
  1659.  music_played := true;
  1660.  RegleTimer(@NouveauTimer,timer_per_second);
  1661. End;
  1662.  
  1663.  
  1664. Procedure periodic_off;
  1665. Begin
  1666.   dern_sortie := true;
  1667.   RestaureTimer;
  1668. End;
  1669.  
  1670. procedure Fade_Musix_out;
  1671. begin;
  1672.   outfading := true;
  1673. end;
  1674.  
  1675. procedure MODExitProc;
  1676. var mlj : byte;
  1677.  begin
  1678.  ExitProc := SaveExitProc;
  1679. { if music_played then periodisch_off;}
  1680.  if not mod_terminated and music_played then fin_mod;
  1681.  Exit_Sb16;
  1682. end;
  1683.  
  1684.  
  1685.  
  1686. {
  1687.  
  1688.  **************************************************************************
  1689.  ***                                                                    ***
  1690.  ***                 Routine pour sortir du fichier VOV                 ***
  1691.  ***                                                                    ***
  1692.  **************************************************************************
  1693.  
  1694. }
  1695.  
  1696. var pause_voc : boolean;
  1697.  
  1698.  
  1699. procedure Init_Voc(filename : string);
  1700. const VOCidt : string = 'Creative Voice File'+#$1A;
  1701. var ch : char;
  1702.     idtstr : string;
  1703.     ct : byte;
  1704.     h : byte;
  1705.     error : integer;
  1706.     srlo,srhi : byte;
  1707.     SR : word;
  1708.     Samplingr : word;
  1709.     stereoreg : byte;
  1710. begin;
  1711.   PLAYING_MOD := false;
  1712.   PLAYING_VOC := true;
  1713.   VOC_READY   := false;
  1714.   vocsstereo := stereo;
  1715.   stereo := false;
  1716.  
  1717.   assign(vocf,filename);
  1718.   reset(vocf,1);
  1719.   if filesize(vocf) < 5000 then begin;
  1720.     VOC_READY   := true;
  1721.     exit;
  1722.   end;
  1723.   blockread(vocf,voch,$19);
  1724.   idtstr := voch.Ident;
  1725.   if idtstr <> VOCidt then begin;
  1726.     VOC_READY   := true;
  1727.     exit;
  1728.   end;
  1729.  
  1730.   Blockread(vocf,inread,20);
  1731.   vblock.Ident_code := inread[2];
  1732.  
  1733.   if vblock.Ident_code = 1 then begin;
  1734.     vblock.SR := inread[6];
  1735.   end;
  1736.  
  1737.   if vblock.Ident_code = 8 then begin;
  1738.     SR := inread[6]+(inread[7]*256);
  1739.     Samplingr := 256000000 div (65536 - SR);
  1740.     if inread[9] = 1 then begin; {stereo}
  1741.       if sb16detected then samplingr := samplingr shr 1;
  1742.       stereo := true;
  1743.     end;
  1744.     vblock.SR := 256 - longint(1000000 DIV samplingr);
  1745.   end;
  1746.  
  1747.   if vblock.Ident_code = 9 then begin;
  1748.     Samplingr := inread[6]+(inread[7]*256);
  1749.     if inread[11] = 2 then begin; {stereo}
  1750.       stereo := true;
  1751.       if sbprodetected then samplingr := samplingr * 2;
  1752.       vblock.SR := 256 - longint(1000000 DIV (samplingr));
  1753.     end else begin;
  1754.       vblock.SR := 256 - longint(1000000 DIV samplingr);
  1755.     end;
  1756.   end;
  1757.  
  1758.  
  1759.   if vblock.SR < 130 then vblock.SR := 166;
  1760.  
  1761.   set_timeconst_sb16(vblock.SR);
  1762.  
  1763.   t_bloc := filesize(vocf) - 31;
  1764.   if t_bloc > 2500 then t_bloc := 2500;
  1765.   blockread(vocf,buffer1^,t_bloc);
  1766.  
  1767.   ch := #0;
  1768.   t_f := filesize(vocf) - 32;
  1769.   t_f := t_f - t_bloc;
  1770.   Bloc_actif := 1;
  1771.  
  1772.   if t_f > 1 then begin;
  1773.     blockread(vocf,buffer2^,t_bloc);
  1774.     t_f := t_f - t_bloc;
  1775.   end;
  1776.  
  1777.   wr_dsp_sb16($D1);
  1778.   lastone := false;
  1779.  
  1780.  if not sb16Detected then begin;
  1781.    if Stereo then begin;
  1782.      stereoreg := Read_Mixer($0E);
  1783.      stereoreg := stereoreg OR 2;
  1784.      Write_Mixer($0E,stereoreg);
  1785.    end else begin;
  1786.      stereoreg := Read_Mixer($0E);
  1787.      stereoreg := stereoreg AND $FD;
  1788.      Write_Mixer($0E,stereoreg);
  1789.    end;
  1790.  end;
  1791.  pause_voc:=false;
  1792.  dsp_block_sb16(t_bloc,t_bloc,vocb1,false,true);
  1793. end;
  1794.  
  1795. procedure voc_done;
  1796. var h : byte;
  1797. begin;
  1798.  lastone := true;
  1799. { repeat until dsp_rdy_sb16;}
  1800.  close(vocf);
  1801.  Reset_Sb16;
  1802.  stereo := vocsstereo;
  1803. end;
  1804.  
  1805.  
  1806. procedure voc_pause;
  1807. begin;
  1808.   pause_voc := true;
  1809. end;
  1810.  
  1811. procedure voc_continue;
  1812. begin;
  1813.   pause_voc := false;
  1814.   if bloc_actif = 1 then begin
  1815.     dsp_block_sb16(T_bloc,T_bloc,vocb2,false,true);
  1816.     bloc_actif := 2;
  1817.   end else begin;
  1818.     dsp_block_sb16(T_bloc,T_bloc,vocb1,false,true);
  1819.     bloc_actif := 1;
  1820.   end;
  1821. end;
  1822.  
  1823.  
  1824. procedure dsp_int_sb16; interrupt;
  1825. {
  1826.  On passe à cette procédure avec l'interruption générée à la fin
  1827.  d'un transfert de bloc. Si le flag dern_sortie n'a pas été posé,
  1828.  une nouvelle sortie démarre.
  1829. }
  1830. var h : byte;
  1831. begin;
  1832.   if interrupt_check then begin;
  1833.     IRQDetected := true;
  1834.   end else begin;
  1835.     if Playing_Mod then begin;
  1836.       h := port[dsp_adr+$E];
  1837.       dsp_rdy_sb16 := true;
  1838.  
  1839.       if not dern_sortie then begin;
  1840.        if bsw then
  1841.     dsp_Block_sb16(taillebloc,Taillebloc,Buffer1,true,false)
  1842.        else
  1843.     dsp_Block_sb16(taillebloc,Taillebloc,Buffer2,true,false);
  1844.     bsw := not bsw;
  1845.     phase_1 := false;
  1846.     phase_2 := true;
  1847.       end;
  1848.     end;
  1849.  
  1850.     IF PLAYING_VOC then begin;
  1851.       h := port[dsp_adr+$E];
  1852.       if (T_f > T_bloc) and not lastone then begin
  1853.     lastone := false;
  1854.     if bloc_actif = 1 then begin
  1855.       if not pause_voc then
  1856.         dsp_block_sb16(T_bloc,T_bloc,vocb2,false,true);
  1857.       blockread(vocf,vocb1^,T_bloc);
  1858.       T_f := T_f - T_bloc;
  1859.       bloc_actif := 2;
  1860.     end else begin;
  1861.       if not pause_voc then
  1862.         dsp_block_sb16(T_bloc,T_bloc,vocb1,false,true);
  1863.       blockread(vocf,vocb2^,T_bloc);
  1864.       T_f := T_f - T_bloc;
  1865.       bloc_actif := 1;
  1866.     end;
  1867.       end else begin;
  1868.     if not lastone then begin;
  1869.       if bloc_actif = 1 then begin
  1870.         if not pause_voc then
  1871.           dsp_block_sb16(T_bloc,T_bloc,vocb2,false,true);
  1872.         lastone := true;
  1873.       end else begin;
  1874.         if not pause_voc then
  1875.           dsp_block_sb16(T_bloc,T_bloc,vocb1,false,true);
  1876.         lastone := true;
  1877.       end;
  1878.     end else begin;
  1879.       dsp_rdy_sb16 := true;
  1880.       wr_dsp_sb16($D0);
  1881.       VOC_READY := true;
  1882.     end;
  1883.       end;
  1884.     end;
  1885.   end;
  1886.   Port[$20] := $20;
  1887. end;
  1888.  
  1889.  
  1890. procedure detect_sbIRQ;
  1891. {
  1892.  Cette routine reconnaît l'interruption de la carte Sound Blaster. Pour cela
  1893.  on teste toutes les interruptions possibles. On envoie des blocs courts
  1894.  via DMA. Si la sortie se conclut par le saut à l'interruption indiquée,
  1895.  celle-ci a été trouvée.
  1896. }
  1897. const irqs_possibles : array[1..5] of byte = ($2,$3,$5,$7,$10);
  1898. var i : integer;
  1899.     h : byte;
  1900. begin;
  1901.  getintvec($8+dsp_irq,intback);         { Sauvegarde les valeurs ! }
  1902.  port21 := port[$21];
  1903.  fillchar(buffer1^,1200,128);
  1904.  set_Timeconst_sb16(211);
  1905.  Wr_dsp_sb16($D3);                           { Eteint le haut-parleur }
  1906.  i := 1;
  1907.  interrupt_check := true;
  1908.  while (i <= 5) and (not IRQDetected) do
  1909.    begin;
  1910.      dsp_irq := irqs_possibles[i];      { IRQ à tester }
  1911.      getintvec($8+dsp_irq,oldint);      { Interruption détournée }
  1912.      setintvec($8+dsp_irq,@Dsp_Int_sb16);
  1913.      irqmsq := 1 shl dsp_irq;
  1914.      port[$21] := port[$21] and not irqmsq;
  1915.      Sampling_Rate := 211;
  1916.      taillebloc := 1200;              { Sortie pour test }
  1917.      dsp_Block_sb16(taillebloc,Taillebloc,buffer1,true,false);
  1918.      delay(150);
  1919.      setintvec($8+dsp_irq,oldint);      { Rétablit l'interrupt }
  1920.      port[$21] := Port[$21] or irqmsq;
  1921.      h := port[dsp_adr+$E];
  1922.      Port[$20] := $20;
  1923.      inc(i);
  1924.    end;
  1925.  interrupt_check := false;
  1926.  Wr_dsp_sb16($D1);                           { Rétablit le haut-parleur }
  1927.  setintvec($8+dsp_irq,intback);         { Rétablit les valeurs !!!      }
  1928.  port[$21] := port21;
  1929.  dsp_rdy_sb16 := true;
  1930. end;
  1931.  
  1932.  
  1933. function Init_Sb : boolean;
  1934. begin;
  1935.   if not detect_Reg_sb16 then begin;
  1936.     Init_Sb := false;
  1937.     exit;
  1938.   end;
  1939. { Soundblaster trouvé      }
  1940.  if not force_irq then detect_sbIRQ;    { IRQ auto-detection         }
  1941.    test_Transmission;
  1942.  if not force_irq then detect_sbIRQ;
  1943.  if Detect_Mixer_sb16 then begin;
  1944.    SbProDetected := TRUE;
  1945.  end;
  1946.  SbGetDspVersion;
  1947.  if SbVersMaj >= 4 then begin;                { SB 16 ASP détectée         }
  1948.    Sb16Detected := true;
  1949.    SBProDetected := false;
  1950.  end;
  1951.  wr_dsp_sb16($D1);
  1952.  getintvec($8+dsp_irq,oldint);
  1953.  setintvec($8+dsp_irq,@dsp_int_sb16);
  1954.  irqmsq := 1 shl dsp_irq;
  1955.  port[$21] := port[$21] and not irqmsq;
  1956. end;
  1957.  
  1958. function init_The_Mod : boolean;
  1959. begin;
  1960.  mod_autodetect(on);
  1961.  mod_SetSpeed(66);
  1962.  mod_SetMultiply(11);
  1963.  mod_Setloopflag(ON);
  1964.  
  1965.  if not init_sb then
  1966.    init_the_mod := false
  1967.  else begin;
  1968.    init_the_mod := true;
  1969.    mod_Samplefreq(Samfreq);
  1970.  end;
  1971. end;
  1972.  
  1973.  
  1974. begin;
  1975.  SaveExitProc := ExitProc;
  1976.  ExitProc := @MODExitProc;
  1977.  dsp_rdy_sb16 := true;
  1978.  mod_terminated := false;
  1979.  music_played := false;
  1980.  mloop := true;
  1981.  mli := 0;
  1982.  mlj := 0;
  1983.  tpw := 5;
  1984.  In_St[1] := 0;
  1985.  In_St[2] := 0;
  1986.  In_St[3] := 0;
  1987.  In_St[4] := 0;
  1988.  In_St[5] := 0;
  1989.  In_St[6] := 0;
  1990.  In_St[7] := 0;
  1991.  In_St[8] := 0;
  1992.  loop_pos := 0;
  1993.  mautodet := true;
  1994.  modmultiply  := 20;
  1995.  Sound_boucle := 10;
  1996.  Frappe_notes[1] := 0;
  1997.  Frappe_notes[2] := 0;
  1998.  Frappe_notes[3] := 0;
  1999.  Frappe_notes[4] := 0;
  2000.  Frappe_notes[5] := 0;
  2001.  Frappe_notes[6] := 0;
  2002.  Frappe_notes[7] := 0;
  2003.  Frappe_notes[8] := 0;
  2004.  Voixvide := @Voix_vide;
  2005.  Mixingproc_voix[1] := Voixvide;
  2006.  Mixingproc_voix[2] := Voixvide;
  2007.  Mixingproc_voix[3] := Voixvide;
  2008.  Mixingproc_voix[4] := Voixvide;
  2009.  Mixingproc_voix[5] := Voixvide;
  2010.  Mixingproc_voix[6] := Voixvide;
  2011.  Mixingproc_voix[7] := Voixvide;
  2012.  Mixingproc_voix[8] := Voixvide;
  2013.  getmem(mixed_data,8000);
  2014.  getmem(mixed_data_st,8000);
  2015.  
  2016.  getmem(buffer1,8000);
  2017.  getmem(buffer2,8000);
  2018.  getmem(vocb1,8000);
  2019.  getmem(vocb2,8000);
  2020.  bsw := true;
  2021. end.
  2022.  
  2023.