home *** CD-ROM | disk | FTP | other *** search
/ PC Interdit / pc-interdit.iso / sound / gusmod / gus_mod.pas < prev    next >
Pascal/Delphi Source File  |  1994-10-27  |  43KB  |  1,315 lines

  1. {$A+,B-,D+,E+,F-,G+,I-,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y+}
  2. unit gus_mod;
  3. {
  4.  ****************************************************************************
  5.  ***                   DATA BECKERs  "PC UNDERGROUND"                     ***
  6.  ***                  ================================                    ***
  7.  ***                                                                      ***
  8.  ***                       Modplayer-Unit GUS_MOD                         ***
  9.  ***                                                                      ***
  10.  *** L'unité GUS_MOD est destinée à faire jouer des MODs avec Gravis      ***
  11.  *** Ultrasound, la carte son habituelle de la Demo-Scene.                ***
  12.  ***                                                                      ***
  13.  *** Cette unité a été utilisé pour programmer le (FREEWARE-)             ***
  14.  *** Mod-Player TCP V1.0.                                                 ***
  15.  ***                                                                      ***
  16.  *** Auteur                : Boris Bertelsons  (InspirE)                  ***
  17.  *** Nom du fichier        : GUS_MOD.PAS                                  ***
  18.  *** Dernière modification : 28.06.1994                                   ***
  19.  *** Version               : 2.0                                          ***
  20.  *** Compilateur           : Turbo Pascal 6.0 und höher                   ***
  21.  ****************************************************************************
  22. }
  23.  
  24. interface
  25. function  _gus_modload(nom : string) : boolean;
  26. {
  27.  Charge le fichier contenu dans la variable nom dans la mémoire et dans
  28.  la GUS-RAM. La fonction renvoie la valeur TRUE, si le chargement du
  29.  fichier MOD s'est effectuée comme il le faut. Sinon elle renvoie la
  30.  valeur FALSE.
  31. }
  32.  
  33. procedure _gus_modstart;
  34. {
  35.  Lance l'exécution d'un MOD chargé par le biais d'un Timer-Interrupt
  36. }
  37.  
  38. procedure _gus_mod_quitter;
  39. {
  40.  Termine l'exécution d'un fichier MOD
  41. }
  42.  
  43. procedure _gus_initialiser;
  44. {
  45.  Initialisation de la GUS
  46. }
  47.  
  48. function _gus_init_env : boolean;
  49. {
  50.  Initialise la GUS. Il n'y a pas une vérification de la configuration
  51.  matérielle mais une vérification de la variable d'environnement ULTRASND
  52. }
  53.  
  54. procedure _gus_set_chanelpos;
  55. {
  56.  Occupe les positions de tous les canaux de la GUS
  57. }
  58.  
  59. {
  60.  *************************************************************************
  61.  ***                  Déclarations des TYPES                           ***
  62.  *************************************************************************
  63. }
  64. type Song_header = record         { Les variables globales}
  65.        kennung : string[25];      { du fichier MOD}
  66.        SongName : string[30];
  67.        LongChanson : byte;
  68.        Arrang : array[0..255] of byte;
  69.        Num_Patts : byte;
  70.        Num_Inst : byte;
  71.      end;
  72.  
  73. type Modinfo = record
  74.        Voix : word;
  75.        Titre  : string[20];
  76.        Nb_Patt : word;
  77.      end;
  78.  
  79. Type Runinfo = record
  80.         Frappe : array[1..8] of byte;
  81.         Ligne,
  82.         Pattnr   : integer;
  83.         Volumes  : array[1..8] of byte;
  84.         speed    : byte;
  85.         bpm      : byte;
  86.      end;
  87.  
  88. type
  89.  PCanalInfo = ^TCanalInfo;
  90.  TCanalInfo = record
  91.    InstNr     : byte;             { Variables de la configuration }
  92.    Mempos     : longint;          { matérielle }
  93.    Fin       : longint;
  94.    Loop_Start : longint;
  95.    Loop_Fin  : longint;
  96.  
  97.    Volume     : integer;          { Variables relatives au fichier MOD }
  98.    Freq   : word;
  99.    Looping    : byte;
  100.    Son        : integer;
  101.    Son_Init  : integer;
  102.    Son_Final   : integer;
  103.    Effet     : byte;
  104.    Operand   : byte;
  105.  
  106.    Effetx,                       { Variables relatives aux effets }
  107.    Effety      : integer;
  108.    Appegpos     : integer;
  109.    slidespeed   : integer;
  110.    vslide       : integer;
  111.    retrig_count : byte;
  112.    vibpos       : byte;
  113.    vibx         : byte;
  114.    viby         : byte;
  115.  end;
  116.  
  117.  PInstrumentnrInfo = ^TInstrumentInfo;
  118.  TInstrumentInfo = record
  119.    Nom       : string[22];
  120.    Mempos     : longint;
  121.    Fin       : longint;
  122.    l_Start    : longint;
  123.    l_Fin     : longint;
  124.    Taille    : word;
  125.    Loop_Start : word;
  126.    Loop_Fin  : word;
  127.    Volume     : word;
  128.    Looping    : byte;
  129.  end;
  130.  
  131.  
  132. {
  133.  *************************************************************************
  134.  ***             Variables et constantes globales                       ***
  135.  *************************************************************************
  136. }
  137. Const
  138.   Play_Chanel : array[1..14]      { permet de réaliser un "muting" du canal }
  139.     of byte = (1,1,1,1,1,1,1,     { 1 = Active le canal GUS correspondant }
  140.                1,1,1,1,1,1,1);    { 0 = Désactive le canal GUS correspondant }
  141.  
  142. var canaux        : array[0..31] of PCanalInfo;
  143.     Instruments   : array[0..31] of PInstrumentnrInfo;
  144.   MOD_Voix     : word;         { Dépend du nombre de voix (4/8)          }
  145.   MOD_Patternsize : word;         { Taille des Patterns en octets }
  146.   stop_Thevoice   : array[1..8] of boolean;
  147.   vh              : Song_Header;
  148.   Modinfptr       : pointer;
  149.   Modinf          : Modinfo;
  150.   Runinf          : Runinfo;
  151.   chpos           : array[1..8] of integer; { Position des voix }
  152.  
  153.  
  154. implementation
  155. uses dos,crt,design,fselect;
  156.  
  157. const VibratoTable : array[0..63] of integer =(
  158.     0,24,49,74,97,120,141,161,
  159.     180,197,212,224,235,244,250,253,
  160.     255,253,250,244,235,224,212,197,
  161.     180,161,141,120,97,74,49,24,
  162.     0,-24,-49,-74,-97,-120,-141,-161,
  163.     -180,-197,-212,-224,-235,-244,-250,-253,
  164.     -255,-253,-250,-244,-235,-224,-212,-197,
  165.     -180,-161,-141,-120,-97,-74,-49,-24);
  166.  
  167. const Voice_Divisor : array[14..32] of byte =
  168.        (43,40,37,35,33,31,30,28,27,26,25,24,23,22,21,20,20,19,18);
  169.       Voice_Base : array[14..14] of longint =
  170.        (88195);
  171.  
  172. const GUS_Environment : boolean = true;
  173.   Modinstance : byte = 31;        { Le nombre des instruments        }
  174.                                   { d'un fichier MOD (15 oder 31)    }
  175.   ModId : array[1..3] of          { Identification des MOD à 4 voix  }
  176.         String = ('M.K.','FLT4','4CHN');
  177.   Chn6 : string = '6CHN';         { Identification des MOD à 6 voix  }
  178.   chn8 : string = '8CHN';         { Identification des MOD à 8 voix  }
  179.   Modidentit : string             { Identification de tous les MOD   }
  180.     = 'M.K.FLT44CHN6CHN8CHN';     { relatif à la détection}
  181.   Interrupt_speed : word = 50;    { Nombre d'appels à une interruption}
  182.   Num_Voices = 14;                { Nous utilisons les 14 canaux GUS  }
  183.   U_Ram_Freepos : longint = 2;    { pour la gestion de la GUS - RAM   }
  184.  
  185.   Play_Voice = 0; Stop_Voice = 3; { Les constantes destinés à la}
  186.   Bit8       = 0; Bit16      = 4; { sélection du type de la voix}
  187.   No_Loop    = 0; Avec_Loop   = 8;{ qu'on va écouter}
  188.   Unidirect  = 0; Bidirect   = 16;
  189.   Go_forw    = 0; Go_Back    = 64;
  190.  
  191. var GUS_envstr : string;
  192.     GUS_BASE : word;
  193.   oldv : array[0..15] of integer;
  194.   tickcounter,                    { Destiné au contrôle de la vitesse }
  195.   ticklimit    : word;
  196.   ancientimer   : pointer;        { Pointeur sur la vieille timer,     }
  197.   i            : Integer ;        { la variable la plus choyée         }
  198.   gusmf        : file;            { Destiné au Handling du fichier MOD }
  199.   Pattern      : array[0..127]    { Pointeur sur le Pattern dans le Ram}
  200.                  of pointer;
  201.  
  202.  
  203. {$L c:\edition\prog\fr\asm\Gusasm}
  204. procedure U_StartVoice(Nr,Modus : byte); external;
  205. {
  206.  Démarre le canal contenu dans la variable Nr de la Gus dans
  207.  le modus activé par modus
  208. }
  209.  
  210. procedure u_Voicefreq(Nr : byte;Freq : word); external;
  211. {
  212.  Positionne la fréquence Freq pour le canal sélectionné par Nr }
  213.  
  214. procedure u_VoiceBalance(Nr,balance : byte); external;
  215. {
  216.  Destiné à la configuration de la 'balance' du canal indiqué par Nr.
  217.  Les valeurs pour 'balance' peuvent se situer entre 0 et 15.
  218.  C'est à dire :  0 représente la position toute à la gauche, 7 le milieu
  219.  et 15  la position toute à la droite.
  220. }
  221.  
  222. procedure u_VoiceVolume(Nr : byte; Vol : word); external;
  223. {
  224.  En faisant cela vous réglez le volume sonore Vol de Nr contenant le canal
  225. }
  226.  
  227. procedure u_delay; external;
  228. {
  229.  Pour régler le temps d'attente lors de l'accès à des registres à modification automatique de GF1,
  230.  destiné à l'usage interne)
  231. }
  232.  
  233. function  detect_gus : word; external;
  234. {
  235.  Destiné à l'identification de la GUS. La fonction renvoie une 0, si
  236.  le canal a été trouvé et le nombre 1 si aucune GUS n'a pu être
  237.  identifiée.  La fonction règle le bon Base-Port pour la GUS.
  238. }
  239.  
  240. procedure u_Initialize; external;
  241. {
  242.  Initialise Gravis Ultrasound.
  243. }
  244.  
  245. procedure Ultra_Mem2Gus(samp : pointer;start : longint;laenge : word); external;
  246. {
  247.  Avec cette procédure vous allez copier un Sampel de la Ram dans la RAM de la GUS
  248.  En faisant cela, le Sampel adressé par samp  se fait transmettre avec la
  249.  méthode Poke. Dans laenge vous indiquez la longueur du Sampel à transmettre.
  250. }
  251.  
  252. procedure gus_speaker_on; external;
  253. {
  254.  Active le haut-parleur de la GUS.
  255. }
  256.  
  257. procedure u_Voicedata(start,lsta,sende : longint;Nr : word); external;
  258. {
  259.  Règle les paramètres pour le canal. start désigne la position initiale de la
  260.  voix dans la GUS-Ram, lsta le début du boucle et renvoie
  261.  la position finale du canal. Vous sélectionnez le nombre du canal moyennant variable Nr.
  262. }
  263.  
  264. function  Ffacteur(t:word) : word; external;
  265. {
  266.  La fonction Ffaktor renvoie la fréquence qui correspond au numéro des notes t
  267.  pour la GUS à partir du tableau des fréquences Mod.
  268. }
  269.  
  270. function  Note(hauteur : word) : byte; external;
  271. {
  272.  Hiermit ermitteln Sie aus dem in hoehe übergebenen Tonhöhen-Wert aus der
  273.  MOD-Datei die Nummer der Note.
  274. }
  275.  
  276. procedure voice_rampin(Stimme:byte;vol : word); external;
  277. {
  278.  La fonction est à utiliser, si on ne veut pas entendre des crépitements.
  279.  La voix sélectionné dans 'voix' ne se fait pas répercuter toute de suite
  280.  sur le volume sonore indiqué par vol, mais se fait slider avec la Gus-Ramp
  281.  le plus rapidement possible de 0 au volume sonore souhaité.
  282.  Cette procédure remplace u_VoiceVolume.
  283. }
  284.  
  285. procedure voice_slide(nr,speed : byte;vol : word); external;
  286. {
  287.  Avec cette procédure vous pouvez intégrer un canal dans la GUS. Nr renvoie
  288.  au numéro du canal à intégrer, vous avez dans vol le volume sonore cible.
  289.  En ce qui concerne la vitesse, les deux bits supérieurs indique le
  290.  Ramp-Speed et les six 6 Bits inférieurs le facteur d'incrémentation.
  291.  Vous calculez le Ramp le plus vite avec une valeur de 63, le plus lent
  292.  avec une valeur de 192.
  293. }
  294.  
  295. procedure dos_getmem(var indicateur:pointer;quantite:word); external;
  296. {
  297.  Cett procédure remplace la Getmem-Procedure de PASCAL. Du fait qu'elle
  298.  utilise la mémoire du DOS elle est d'une nécessité vitale pour les
  299.  programmes résidents parce qu'il faut qu'ils n'occupent pas toujours
  300.  la même emplacement en mémoire et permettent de s'adapter à la MOD.
  301.  }
  302.  
  303. procedure dos_freemem(indicateur:pointer); external;
  304. {
  305.  Dos_Freemem ist das Equivalent zur Pascal Freemem Procedure. Eine Größe
  306.  des freizugebenden Speichers ist nicht anzugeben.
  307. }
  308.  
  309. procedure init_gus_base(base : word); external;
  310. {
  311.  Initialise Gravis Ultrasound avec l'adresse transmise dans Base.
  312. }
  313.  
  314.  
  315. {$L c:\edition\prog\fr\asm\loadin}
  316. procedure loadin; external;    { Ansi - Pic }
  317.  
  318.  
  319. procedure init_the_gus(base : word);
  320. begin;
  321.   init_gus_base(base);
  322. end;
  323.  
  324. procedure u_init;
  325. var li : integer;
  326. begin;
  327.    u_Initialize;
  328. end;
  329.  
  330. FUNCTION ConvertString(Source : Pointer; Size : BYTE):String;
  331. {
  332. Transforme une chaine ASCIIZ en un String Pascal
  333. }
  334. VAR
  335.    WorkStr : String;
  336. BEGIN
  337.    Move(Source^,WorkStr[1],Size);
  338.    WorkStr[0] := CHR(Size);
  339.    if pos(#0,Workstr) <> 0 then WorkStr[0] := chr(pos(#0,Workstr)-1);
  340.    ConvertString := WorkStr;
  341. END;
  342.  
  343. procedure Charge_Instrument(Nr : byte);
  344. {
  345.  Charge l'instrument de numéro nr dans la RAM de la carte GUS
  346. }
  347. var gr : longint;
  348.     samp : pointer;
  349. begin;
  350.    gr := Instruments[nr]^.Taille;
  351.    if gr > 10 then begin;      { ne charge que si > 10! }
  352.      dos_getmem(samp,gr);
  353.      Blockread(gusmf,samp^,gr);
  354.      U_Ram_freepos := U_Ram_freepos + (16-(U_Ram_freepos MOD 16));
  355.      Instruments[nr]^.Mempos := U_Ram_freepos;
  356.      Ultra_Mem2Gus(samp,Instruments[nr]^.Mempos,gr);
  357.      dos_freemem(samp);           { Initialise les variables des voix }
  358.      Instruments[nr]^.l_start :=
  359.         Instruments[nr]^.Mempos + Instruments[nr]^.Loop_Start;
  360.      if Instruments[nr]^.Looping = Avec_loop then begin;
  361.        Instruments[nr]^.fin :=
  362.          Instruments[nr]^.Mempos + Instruments[nr]^.Loop_Fin;
  363.      end else begin;
  364.        Instruments[nr]^.fin := Instruments[nr]^.Mempos + gr - 25;
  365.      end;
  366.      Inc(U_Ram_Freepos,gr);       { repousser le pointeur de gestion }
  367.    end;
  368. end;
  369.  
  370.  
  371. procedure Nouv_Interrupt_Speed(speed : word);
  372. {
  373.  Règle la vitesse d'Interrupt correspondant au BpM.
  374. }
  375. var zaehler : word;
  376.     loz,hiz : byte;
  377. begin;
  378.  interrupt_speed := round(speed / 2.5);
  379.  zaehler := 1193180 DIV interrupt_speed;
  380.  loz := lo(zaehler);
  381.  hiz := hi(zaehler);
  382.  asm
  383.   cli
  384.   mov dx,43h
  385.   mov al,36h
  386.   out dx,al
  387.   mov dx,40h
  388.   mov al,loz
  389.   out dx,al
  390.   mov al,hiz
  391.   out dx,al
  392.   sti
  393.  end;
  394. end;
  395.  
  396. procedure _gus_set_chanelpos;
  397. {
  398.  Positionne les différents canaux de la GUS
  399. }
  400. begin;
  401.   u_VoiceBalance(1,chpos[1]);
  402.   u_VoiceBalance(2,chpos[2]);
  403.   u_VoiceBalance(3,chpos[3]);
  404.   u_VoiceBalance(4,chpos[4]);
  405.   u_VoiceBalance(5,chpos[5]);
  406.   u_VoiceBalance(6,chpos[6]);
  407.   u_VoiceBalance(7,chpos[7]);
  408.   u_VoiceBalance(8,chpos[8]);
  409. end;
  410.  
  411. procedure display_loading(s : string);
  412. {
  413.  Indique la progression dans le chargment du Sample.
  414. }
  415. var li,slen : integer;
  416. var z : integer;
  417. begin;
  418.   for z := 0 to 12 do begin;
  419.     move(ptr(seg(loadin),ofs(loadin)+z*34*2)^,ptr($B800,z*160+8*160+44)^,34*2);
  420.   end;
  421.   while pos('\',s) <> 0 do begin;
  422.     delete(s,1,pos('\',s));
  423.   end;
  424.   slen := length(s);
  425.   slen := (15 - slen) div 2;
  426.   for li := 1 to slen do s := ' '+s;
  427.   gotoxy(33,13);
  428.   write(s);
  429. end;
  430.  
  431. function _gus_modload(nom : string) : boolean;
  432. {
  433.  Charge le fichier MOD transmis par "nom". Suppose que le fichier indiqué
  434.  dans le chemin d'accès existe et n'est pas protégé contre l'écriture.
  435. }
  436. var dummya : array[0..30] of byte;{ Pour le traitement de la chaîne }
  437.     daptr : pointer;              { pointeur sur dummya }
  438.     dumw : word;                  { Variable dummy pour lire}
  439.     dumb : byte;
  440.     Longreste : longint;         { pour connaître le nombre de patterns }
  441.     li : integer;
  442.     Identit : array[1..4] of char;{ Identité du fichier MOD }
  443.     ias : integer;                { Position de départ fonction de l'instrument }
  444. begin;
  445.   U_Ram_freepos := 32;
  446.   for li := 0 to 15 do begin;
  447.     new(Canaux[li]);
  448.     canaux[li]^.vibpos := 0;
  449.   end;
  450.   for li := 0 to 31 do begin;
  451.      new(Instruments[li]);
  452.      Instruments[li]^.Nom := '';
  453.   end;
  454.  
  455.   runinf.Ligne := 0;
  456.   runinf.Pattnr := -1;
  457.   tickcounter := 0;
  458.   ticklimit := 6;
  459.   runinf.speed := 6;
  460.   runinf.bpm := 125;
  461.   ias := 0;
  462.   daptr := @dummya;
  463.   assign(gusmf,nom);             { Ouvrir fichier + initialiser la longueur }
  464.   reset(gusmf,1);
  465.  
  466.   save_screen;
  467.   display_loading(nom);
  468.  
  469.   Longreste := filesize(gusmf);
  470.   Longreste := Longreste  - 1084;
  471.  
  472.   seek(gusmf,1080);               { Vérifier si c'est un MOD à 15 ou à 31 voix }
  473.   Blockread(gusmf,Identit,4);
  474.   if pos(Identit,Modidentit) = 0 then begin;
  475.     { 15 Voix? }
  476.     seek(gusmf,600);
  477.     Blockread(gusmf,Identit,4);
  478.     if pos(Identit,Modidentit) = 0 then begin;
  479.       { Pas de fichier MOD valide }
  480.       writeln('Pas de fichier MOD valide !!!');
  481.       halt(0);
  482.     end else begin;
  483.       Modinstance := 15;
  484.       ias := -16*30;
  485.     end;
  486.   end;
  487.  
  488.   if (Identit = MODId[1]) or      { Nombre de voix du fichier MOD ?       }
  489.      (Identit = MODId[2]) or
  490.      (Identit = MODId[3])
  491.   then begin;
  492.     MOD_Voix := 4;
  493.     MOD_Patternsize := 4*256;
  494.   end else
  495.     if (Identit = CHn6) then begin;
  496.       _gus_modload := false;
  497.       exit;
  498.     end else
  499.       if (Identit = CHn8) then begin;
  500.         MOD_Voix := 8;
  501.         MOD_Patternsize := 8*256;
  502.       end;
  503.  
  504.   seek(gusmf,0);
  505.   Blockread(gusmf,dummya,20);     { Connaître le nom du fichier }
  506.   vh.SongName := ConvertString(daptr,20);
  507.   seek(gusmf,950+ias);            { Longueur en patterns }
  508.   Blockread(gusmf,vh.longchanson,1);
  509.   seek(gusmf,952+ias);            { lit l'arrangement }
  510.   Blockread(gusmf,vh.Arrang,128);
  511.  
  512.   vh.Num_Inst := Modinstance;      { lit les instruments (15/31) }
  513.   seek(gusmf,20+ias);
  514.  
  515.   for li := 1 to 32 do Instruments[li]^.Nom := '';
  516.  
  517.   for li := 1 to vh.Num_Inst do begin;
  518.     Blockread(gusmf,dummya,22);   { Noms des instruments }
  519.     Instruments[li]^.Nom := ConvertString(daptr,22);
  520.  
  521.     Blockread(gusmf,dumw,2);      { Longueur du sample }
  522.     Instruments[li]^.Taille := swap(dumw) * 2;
  523.  
  524.     Blockread(gusmf,dumb,1);      { lit le volume }
  525.     Blockread(gusmf,dumb,1);
  526.     Instruments[li]^.Volume := dumb;
  527.  
  528.     Blockread(gusmf,dumw,2);      { lit le départ du loop }
  529.     Instruments[li]^.Loop_Start := swap(dumw) * 2;
  530.     Blockread(gusmf,dumw,2);
  531.  
  532.     dumw := swap(dumw) * 2;       { lit la fin du loop : début + longueur}
  533.     Instruments[li]^.Loop_Fin := Instruments[li]^.Loop_Start+dumw;
  534.  
  535.     if (Instruments[li]^.Loop_Fin -      { Looping dans l'instrument ?           }
  536.         Instruments[li]^.Loop_Start) >= 10 then begin;
  537.       Instruments[li]^.Looping := Avec_loop;
  538.     end else begin;
  539.       Instruments[li]^.Looping := no_loop;
  540.     end;
  541.     Dec(Longreste,Instruments[li]^.Taille);
  542.   end;
  543.  
  544.   Vh.Num_Patts := Longreste DIV MOD_Patternsize ; { nombre de patterns ?    }
  545.   seek(gusmf,1084+ias);
  546.  
  547.   for li := 1 to Vh.Num_Patts do begin; { lit les patterns }
  548.     dos_getmem(Pattern[li],MOD_Patternsize );
  549.     Blockread(gusmf,Pattern[li]^,MOD_Patternsize );
  550.   end;
  551.  
  552.   for li := 1 to vh.Num_Inst do begin; { lit les instruments }
  553.     Charge_Instrument(li);
  554.     screen[16,23+li].a := 5;
  555.   end;
  556.  
  557.   close(gusmf);
  558.  
  559.   for i := 1 to 31 do begin; { initialise les variables de canaux }
  560.     u_VoiceBalance (i,7) ;
  561.     u_VoiceVolume (i,0) ;
  562.     u_VoiceFreq (i,12000);
  563.     U_StartVoice(i,Stop_Voice);
  564.     u_Voicedata(0,0,0,i);
  565.   end;
  566.   runinf.Ligne := 0;                     { initialise les variables run }
  567.   runinf.Pattnr := -1;
  568.   tickcounter := 0;
  569.   ticklimit := 6;
  570.   runinf.speed := 6;
  571.   runinf.bpm := 125;
  572.   if MOD_Voix = 4 then begin;  { ordonne les voix en demi-cercle }
  573.     chpos[1] := 2;
  574.     chpos[2] := 5;
  575.     chpos[3] := 9;
  576.     chpos[4] := 12;
  577.     _gus_set_chanelpos;;
  578.   end;
  579.   if MOD_Voix = 8 then begin;
  580.     chpos[1] := 1;
  581.     chpos[2] := 3;
  582.     chpos[3] := 5;
  583.     chpos[4] := 7;
  584.     chpos[5] := 7;
  585.     chpos[6] := 9;
  586.     chpos[7] := 11;
  587.     chpos[8] := 13;
  588.     _gus_set_chanelpos;;
  589.   end;
  590.  
  591.   nouv_interrupt_Speed(runinf.bpm);
  592.   restore_screen;
  593.   Modinf.Voix  := MOD_Voix;  { Constante MOD-Infos dans la structure }
  594.   Modinf.Titre   := vh.Songname;  { à transmettre }
  595.   Modinf.Nb_patt := Vh.Longchanson;
  596.   _gus_modload    := true;
  597. end;
  598.  
  599.  
  600. procedure effet_vibrato(nr : byte);
  601. {
  602.  Procédure vibrato tirée du traitement des effets
  603. }
  604. var vibswap : integer;
  605. begin;
  606.   inc(Canaux[nr]^.vibpos,Canaux[nr]^.vibx);
  607.   if Canaux[nr]^.vibpos > 64 then
  608.     dec(Canaux[nr]^.vibpos,64);
  609.   vibswap :=
  610.     (VibratoTable[Canaux[nr]^.vibpos] * Canaux[nr]^.viby) div 256;
  611.   inc(Canaux[nr]^.Son_init,vibswap);
  612.   if Canaux[nr]^.Son_init < 1 then
  613.     Canaux[nr]^.Son_init := 1;
  614.   Canaux[nr]^.Freq :=
  615.     longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  616.   u_VoiceFreq(nr,Canaux[nr]^.Freq);
  617. end;
  618.  
  619.  
  620. procedure E_toneportamento(nr : byte);
  621. {
  622.  Procédure TonePortamento tirée du traitement des effets
  623. }
  624. begin;
  625.   if Canaux[nr]^.slidespeed < 0 then
  626.   begin
  627.     inc(Canaux[nr]^.Son_init,Canaux[nr]^.slidespeed);
  628.     if Canaux[nr]^.Son_init < Canaux[nr]^.Son_final then
  629.       Canaux[nr]^.Son_init := Canaux[nr]^.Son_final;
  630.   end else begin
  631.     inc(Canaux[nr]^.Son_init,Canaux[nr]^.slidespeed);
  632.     if Canaux[nr]^.Son_init > Canaux[nr]^.Son_final then
  633.       Canaux[nr]^.Son_init := Canaux[nr]^.Son_final;
  634.   end;
  635.   if Canaux[nr]^.Son_init < 1 then
  636.     Canaux[nr]^.Son_init := 1;
  637.   Canaux[nr]^.Freq :=
  638.     longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  639.   u_VoiceFreq(nr,Canaux[nr]^.Freq);
  640.   oldv[nr] := Canaux[nr]^.Son_init;
  641. end;
  642.  
  643.  
  644. procedure EI_toneportamento(nr : byte);
  645. {
  646.  Init pour la procédure vibrato tirée du traitement des effets 
  647. }
  648. begin;
  649.   { Définit le facteur Inc }
  650.   if Canaux[nr]^.Operand <> 0 then
  651.   begin;
  652.     if Canaux[nr]^.Son_init > Canaux[nr]^.Son_final then
  653.     begin;
  654.       Canaux[nr]^.slidespeed := -(Canaux[nr]^.Operand);
  655.     end else begin;
  656.       Canaux[nr]^.slidespeed := (Canaux[nr]^.Operand);
  657.     end;
  658.   end;
  659.   if Canaux[nr]^.Son_init < 1 then
  660.     Canaux[nr]^.Son_init := 1;
  661.   Canaux[nr]^.Freq :=
  662.     longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  663.   u_VoiceFreq(nr,Canaux[nr]^.Freq);
  664.   oldv[nr] := Canaux[nr]^.Son_init;
  665. end;
  666.  
  667.  
  668. procedure Initialiser_Effets(nr : byte);
  669. var swaplong      : longint;
  670.     vibswap       : integer;
  671. begin;
  672.   if Canaux[nr]^.Effet = 0 then exit;
  673.   case Canaux[nr]^.Effet of
  674.     0 : begin; { Appegio }
  675.           Canaux[nr]^.Appegpos := 0;
  676.           Canaux[nr]^.Effetx := Canaux[nr]^.Operand shr 4;
  677.           Canaux[nr]^.Effety := Canaux[nr]^.Operand and $0f;
  678.  
  679.           inc(Canaux[nr]^.Appegpos);
  680.           case (Canaux[nr]^.Appegpos MOD 3) of
  681.             0 : begin; {ap = 3 !}
  682.                   Canaux[nr]^.Son_init :=
  683.                   Canaux[nr]^.Son + Canaux[nr]^.Effety;
  684.                 end;
  685.             1 : begin; {ap = 1 !}
  686.                   Canaux[nr]^.Son_init :=
  687.                   Canaux[nr]^.Son;
  688.                 end;
  689.             2 : begin; {ap = 2 !}
  690.                   Canaux[nr]^.Son_init :=
  691.                   Canaux[nr]^.Son + Canaux[nr]^.Effetx;
  692.                 end;
  693.           end;
  694.           if Canaux[nr]^.Son_init < 1 then
  695.             Canaux[nr]^.Son_init := 1;
  696.           Canaux[nr]^.Freq :=
  697.             longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  698.           u_VoiceFreq(nr,Canaux[nr]^.Freq);
  699.         end;
  700.     1 : begin;  { Portamento up }
  701.           dec(Canaux[nr]^.Son_init,Canaux[nr]^.Operand);
  702.           if Canaux[nr]^.Son_init < 1 then
  703.             Canaux[nr]^.Son_init := 1;
  704.           Canaux[nr]^.Freq :=
  705.             longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  706.           u_VoiceFreq(nr,Canaux[nr]^.Freq);
  707.         end;
  708.     2 : begin;  { Portamento down }
  709.           inc(Canaux[nr]^.Son_init,Canaux[nr]^.Operand);
  710.           if Canaux[nr]^.Son_init < 1 then
  711.             Canaux[nr]^.Son_init := 1;
  712.           Canaux[nr]^.Freq :=
  713.             longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  714.           u_VoiceFreq(nr,Canaux[nr]^.Freq);
  715.         end;
  716.     3 : begin; { Tone Portamento }
  717.           EI_toneportamento(nr);
  718.         end;
  719.     4 : begin;  { Vibrato  *new* }
  720.           Canaux[nr]^.vibx := Canaux[nr]^.Operand shr 4;
  721.           Canaux[nr]^.viby := Canaux[nr]^.Operand and $0f;
  722.           effet_vibrato(nr);
  723.         end;
  724.     5 : begin; {NOTE SLIDE + VOLUME SLIDE:   *new* }
  725.           { init }
  726.           if Canaux[nr]^.Operand <= $0f then
  727.           begin;
  728.             Canaux[nr]^.vslide := -(Canaux[nr]^.Operand AND $0f);
  729.             Canaux[nr]^.slidespeed := -(Canaux[nr]^.Operand AND $0f);
  730.           end else begin;
  731.             Canaux[nr]^.vslide := (Canaux[nr]^.Operand shr 4);
  732.             Canaux[nr]^.slidespeed := (Canaux[nr]^.Operand shr 4);
  733.           end;
  734.           { volume slide }
  735.           inc(Canaux[nr]^.volume,Canaux[nr]^.vslide);
  736.           if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
  737.           if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
  738.           u_VoiceVolume(Nr,Canaux[nr]^.volume);
  739.           { Note slide }
  740.           inc(Canaux[nr]^.Son_init,Canaux[nr]^.slidespeed);
  741.           if Canaux[nr]^.Son_init < 1 then
  742.             Canaux[nr]^.Son_init := 1;
  743.           Canaux[nr]^.Freq :=
  744.             longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  745.           u_VoiceFreq(nr,Canaux[nr]^.Freq);
  746.         end;
  747.     6 : begin;  { Vibrato & Volume slide  *new* }
  748.           { init }
  749.           Canaux[nr]^.vibx := Canaux[nr]^.Operand shr 4;
  750.           Canaux[nr]^.viby := Canaux[nr]^.Operand and $0f;
  751.           if Canaux[nr]^.Operand <= $0f then
  752.           begin;
  753.             Canaux[nr]^.vslide := -(Canaux[nr]^.Operand AND $0f);
  754.           end else begin;
  755.             Canaux[nr]^.vslide := (Canaux[nr]^.Operand shr 4);
  756.           end;
  757.           { volume slide }
  758.           inc(Canaux[nr]^.volume,Canaux[nr]^.vslide);
  759.           if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
  760.           if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
  761.           u_VoiceVolume(Nr,Canaux[nr]^.volume);
  762.           { vibrato }
  763.           effet_vibrato(nr);
  764.         end;
  765.     7 : begin; { tremolo  *new* }
  766.            Canaux[nr]^.vibx := Canaux[nr]^.Operand shr 4;
  767.            Canaux[nr]^.viby := Canaux[nr]^.Operand and $0f;
  768.            inc(Canaux[nr]^.vibpos,Canaux[nr]^.vibx);
  769.            if Canaux[nr]^.vibpos > 64 then
  770.              dec(Canaux[nr]^.vibpos);
  771.            vibswap :=
  772.              (VibratoTable[Canaux[nr]^.vibpos] * Canaux[nr]^.viby) div 256;
  773.            inc(Canaux[nr]^.Volume,vibswap);
  774.            if Canaux[nr]^.Volume < 0 then Canaux[nr]^.Volume := 0;
  775.            if Canaux[nr]^.Volume > 63 then Canaux[nr]^.Volume := 63;
  776.            u_VoiceVolume(nr,Canaux[nr]^.volume);
  777.         end;
  778.     8 : begin; { non utilisé !!! }
  779.           {
  780.            Non utilisé officiellement. Se prête donc à la programmation 
  781.            pour synchroniser des événements dans une démo...
  782.           }
  783.         end;
  784.     9 : begin;  { Sample - Offset *new* }
  785.           swaplong := longint((Canaux[nr]^.Operand+1)) * 256;
  786.           Canaux[nr]^.Mempos := Canaux[nr]^.Mempos+swaplong;
  787.           u_Voicedata(Canaux[nr]^.Mempos,Canaux[nr]^.Loop_Start,
  788.                     Canaux[nr]^.Fin,nr);
  789.           U_StartVoice(nr,Play_Voice+Bit8+Canaux[nr]^.Looping+Unidirect);
  790.         end;
  791.    $a : begin;  { Volume sliding  *new* }
  792.           if Canaux[nr]^.Operand <= $0f then
  793.           begin;
  794.             Canaux[nr]^.vslide := -(Canaux[nr]^.Operand AND $0f);
  795.           end else begin;
  796.             Canaux[nr]^.vslide := (Canaux[nr]^.Operand shr 4);
  797.           end;
  798.           inc(Canaux[nr]^.volume,Canaux[nr]^.vslide);
  799.           if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
  800.           if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
  801.           u_VoiceVolume(Nr,Canaux[nr]^.volume);
  802.         end;
  803.    $b : begin; { Position Jump *ok* }
  804.           runinf.Ligne := 64;
  805.           runinf.Pattnr := Canaux[nr]^.Operand;
  806.         end;
  807.    $c : begin; { Set Note Volume *ok* }
  808.           if Canaux[nr]^.Operand > 63 then Canaux[nr]^.Operand := 63;
  809.           if Canaux[nr]^.Operand < 1 then
  810.           begin
  811.             Canaux[nr]^.volume := 0;
  812.             u_VoiceVolume(nr,0);
  813.             U_StartVoice(nr,Stop_Voice);
  814.             stop_Thevoice[nr] := true;
  815.           end else begin
  816.             Canaux[nr]^.volume := Canaux[nr]^.Operand;
  817.             u_VoiceVolume(Nr,Canaux[nr]^.volume);
  818.             Runinf.Volumes[nr] := 63;
  819.           end;
  820.         end;
  821.    $d : begin; { Pattern Break *ok* }
  822.           runinf.Ligne := 64;
  823.         end;
  824.    $e : begin;  { Effet étendu }
  825.           case (Canaux[nr]^.Operand shr 4) of
  826.             1 : begin; { Fine slide up }
  827.                   dec(Canaux[nr]^.Son_init,Canaux[nr]^.Operand and $0f);
  828.                   if Canaux[nr]^.Son_init < 1 then Canaux[nr]^.Son_init := 1;
  829.                   Canaux[nr]^.Freq :=
  830.                     longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  831.                   u_VoiceFreq(nr,Canaux[nr]^.Freq);
  832.                 end;
  833.             2 : begin; { Fine slide down }
  834.                   inc(Canaux[nr]^.Son_init,Canaux[nr]^.Operand and $0f);
  835.                   if Canaux[nr]^.Son_init < 1 then Canaux[nr]^.Son_init := 1;
  836.                   Canaux[nr]^.Freq :=
  837.                     longint(Voice_Base[14] div Canaux[nr]^.Son_init);
  838.                   u_VoiceFreq(nr,Canaux[nr]^.Freq);
  839.                 end;
  840.             9 : begin; { Retriggering !!! *new* }
  841.                   Canaux[nr]^.Retrig_count :=
  842.                     Canaux[nr]^.Operand and $0f;
  843.                 end;
  844.            $a : begin; { fine volume slide up }
  845.                   Canaux[nr]^.vslide := (Canaux[nr]^.Operand AND $0f);
  846.                   inc(Canaux[nr]^.volume,Canaux[nr]^.vslide);
  847.                   if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
  848.                   if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
  849.                   u_VoiceVolume(Nr,Canaux[nr]^.volume);
  850.                 end;
  851.            $b : begin; { fine volume slide down }
  852.                   Canaux[nr]^.vslide := (Canaux[nr]^.Operand AND $0f);
  853.                   dec(Canaux[nr]^.volume,Canaux[nr]^.vslide);
  854.                   if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
  855.                   if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
  856.                   u_VoiceVolume(Nr,Canaux[nr]^.volume);
  857.                 end;
  858.            $c : begin;  { Cut Voice *ok* }
  859.                   stop_Thevoice[nr] := true;
  860.                 end;
  861.            end;
  862.         end;
  863.    $f : begin; { Set Speed  *ok* }
  864.           if Canaux[nr]^.Operand <= $f then begin;
  865.             ticklimit := Canaux[nr]^.Operand;
  866.             runinf.speed := ticklimit;
  867.           end else begin;
  868.             runinf.bpm := Canaux[nr]^.Operand;
  869.             nouv_interrupt_Speed(Canaux[nr]^.Operand);
  870.           end;
  871.         end;
  872.   end;
  873. end;
  874.  
  875.  
  876. procedure play_pattern_gus;
  877. {
  878.  On appellera cette procédure régulièrement. Elle exécute une ligne
  879.  du fichier MOD.
  880. }
  881. var li        : integer;
  882.     dumw      : word;
  883.     La_ligne : array[1..8,0..3] of Byte;
  884.     Effet    : byte;
  885.     Ton       : word;
  886.     Inst      : byte;
  887. begin;
  888. {
  889.  **************************************************************************
  890.  ***   Passer dans le fichier MOD                          ***
  891.  **************************************************************************
  892. }
  893.   inc(runinf.Ligne);              { En avant d'une ligne }
  894.   if runinf.Ligne > 64 then runinf.Ligne := 1;
  895.   if runinf.Ligne = 1 then begin; { Nouveau pattern ?                   }
  896.     inc(runinf.Pattnr);
  897.     if runinf.Pattnr > vh.Longchanson then runinf.Pattnr := 1;
  898.   end;
  899.                                   { Charge les notes }
  900.   move(ptr(seg(pattern[vh.Arrang[runinf.Pattnr]+1]^),
  901.        ofs(pattern[vh.Arrang[runinf.Pattnr]+1]^)+
  902.           (runinf.Ligne-1)*4*Mod_Voix)^,
  903.        La_ligne,4*8);
  904.  
  905. {
  906.  **************************************************************************
  907.  ***   Traiter les voix                                           ***
  908.  **************************************************************************
  909. }
  910.   for li := 1 to MOD_Voix do begin;
  911.     if play_chanel[li] = 1 then begin;
  912.       stop_Thevoice[li] := false;
  913.  
  914.       Ton  := ((La_ligne[li,0] AND $0f) shl 8)+La_ligne[li,1];
  915.       Inst := (La_ligne[li,0] AND $f0)+((La_ligne[li,2] AND $F0) SHR 4);
  916.       Canaux[li]^.Effet   := La_ligne[li,2] AND $0f;
  917.       Canaux[li]^.Operand := La_ligne[li,3];
  918.  
  919.       Canaux[li]^.Son_init := oldv[li];
  920.  
  921.       if Ton <> 0 then begin;  { Est-ce qu'un son a été indiqué ??? }
  922.         if Canaux[li]^.Effet = 3 then begin;
  923.           Canaux[li]^.Son_final := Ton;
  924.         end else begin;
  925.           Canaux[li]^.Son := Ton;
  926.           Canaux[li]^.Son_init := Ton;
  927.           oldv[li] := Canaux[li]^.Son_init;
  928.         end;
  929.       end;
  930.  
  931.       If Inst <> 0 then begin; { utiliser un nouvel instrument ??? }
  932.         Canaux[li]^.InstNr     := Inst;
  933.         Canaux[li]^.Mempos     := Instruments[Canaux[li]^.InstNr]^.Mempos;
  934.         Canaux[li]^.Loop_Start := Instruments[Canaux[li]^.InstNr]^.l_start;
  935.         Canaux[li]^.Fin       := Instruments[Canaux[li]^.InstNr]^.Fin;
  936.         Canaux[li]^.volume     := Instruments[Canaux[li]^.InstNr]^.volume;
  937.         Canaux[li]^.Looping    := Instruments[Canaux[li]^.InstNr]^.Looping;
  938.         u_Voicedata(Canaux[li]^.Mempos,Canaux[li]^.Loop_Start,
  939.                     Canaux[li]^.Fin,li);
  940.       end;
  941.       Canaux[li]^.Retrig_count := 0;
  942.  
  943.       Initialiser_Effets(li);
  944.  
  945.  
  946.       If (Ton <> 0) then begin; { note frappée }
  947.         Canaux[li]^.Freq := longint(Voice_Base[14] div Canaux[li]^.Son_init);
  948.         u_VoiceFreq(li,Canaux[li]^.Freq); { définir la fréquence }
  949.  
  950.  
  951.         if Canaux[li]^.Effet = $c then begin; { Extra, sinon trop tôt ! }
  952.           if Canaux[li]^.Operand > 63 then Canaux[li]^.Operand := 63;
  953.           if Canaux[li]^.Operand < 1 then
  954.           begin
  955.             Canaux[li]^.volume := 0;
  956.             u_VoiceVolume(li,0);
  957.             U_StartVoice(li,Stop_Voice);
  958.             stop_Thevoice[li] := true;
  959.           end else begin
  960.             Canaux[li]^.volume := Canaux[li]^.Operand;
  961.             u_VoiceVolume(li,Canaux[li]^.volume);
  962.             Runinf.Volumes[li] := 63;
  963.           end;
  964.         end else begin;
  965.           if Canaux[li]^.volume > 63 then Canaux[li]^.volume := 63;
  966.            voice_rampin(li,Canaux[li]^.volume);
  967.            Runinf.Volumes[li] := 63;
  968.         end;
  969.  
  970.         U_StartVoice(li,Stop_Voice); { Arrêter l'ancienne voix }
  971.  
  972.         u_Voicedata(Canaux[li]^.Mempos,Canaux[li]^.Loop_Start,
  973.                     Canaux[li]^.Fin,li);
  974.         if not stop_Thevoice[li] then begin; { lancer la nouvelle voix }
  975.           U_StartVoice(li,Play_Voice+Bit8+Canaux[li]^.Looping+Unidirect);
  976.           Runinf.Frappe[li] := Canaux[li]^.volume * 4; { Pour égaliseur }
  977.         end;
  978.       end; { note frappée }
  979.     end else begin;
  980.       u_VoiceVolume(li,0);
  981.     end;
  982.   end; {for}
  983. end;
  984.  
  985.  
  986. procedure tick_effects;
  987. var li : integer;
  988.     vibswap : integer;
  989. begin;
  990.   for li := 1 to MOD_Voix do begin;
  991.     if runinf.volumes[li] > 0 then
  992.       dec(runinf.volumes[li]);
  993.     case Canaux[li]^.Effet of { Traitement des effets en cours d'exécution }
  994.       0 : begin;
  995.             inc(Canaux[li]^.Appegpos);
  996.             case (Canaux[li]^.Appegpos MOD 3) of
  997.               0 : begin; {ap = 3 !}
  998.                     Canaux[li]^.Son_init :=
  999.                     Canaux[li]^.Son + Canaux[li]^.Effety;
  1000.                   end;
  1001.               1 : begin; {ap = 1 !}
  1002.                     Canaux[li]^.Son_init :=
  1003.                     Canaux[li]^.Son;
  1004.                   end;
  1005.               2 : begin; {ap = 2 !}
  1006.                     Canaux[li]^.Son_init :=
  1007.                     Canaux[li]^.Son + Canaux[li]^.Effetx;
  1008.                   end;
  1009.              end;
  1010.           end;
  1011.       1 : begin;
  1012.           {!"! new }
  1013.             Canaux[li]^.Operand := Canaux[li]^.Operand and $0F;
  1014.           {!"! new end }
  1015.             dec(Canaux[li]^.Son_init,Canaux[li]^.Operand);
  1016.             if Canaux[li]^.Son_init < 1 then
  1017.               Canaux[li]^.Son_init := 1;
  1018.             Canaux[li]^.Freq :=
  1019.               longint(Voice_Base[14] div Canaux[li]^.Son_init);
  1020.             u_VoiceFreq(li,Canaux[li]^.Freq);
  1021.           end;
  1022.       2 : begin;
  1023.           {!"! new }
  1024.             Canaux[li]^.Operand := Canaux[li]^.Operand and $0F;
  1025.           {!"! new end }
  1026.             inc(Canaux[li]^.Son_init,Canaux[li]^.Operand);
  1027.             if Canaux[li]^.Son_init < 1 then
  1028.               Canaux[li]^.Son_init := 1;
  1029.             Canaux[li]^.Freq :=
  1030.               longint(Voice_Base[14] div Canaux[li]^.Son_init);
  1031.             u_VoiceFreq(li,Canaux[li]^.Freq);
  1032.           end;
  1033.       3 : begin; { Tone Portamento }
  1034.             E_toneportamento(li);
  1035.           end;
  1036.       4 : begin;  { vibrato  *new* }
  1037.             effet_vibrato(li);
  1038.           end;
  1039.      5 : begin;
  1040.            { volume slide }
  1041.            inc(Canaux[li]^.volume,Canaux[li]^.vslide);
  1042.            if Canaux[li]^.volume < 0 then Canaux[li]^.volume := 0;
  1043.            if Canaux[li]^.volume > 63 then Canaux[li]^.volume := 63;
  1044.            u_VoiceVolume(li,Canaux[li]^.volume);
  1045.            { Note slide }
  1046.            inc(Canaux[li]^.Son_init,Canaux[li]^.slidespeed);
  1047.             if Canaux[li]^.Son_init < 1 then
  1048.               Canaux[li]^.Son_init := 1;
  1049.            Canaux[li]^.Freq :=
  1050.              longint(Voice_Base[14] div Canaux[li]^.Son_init);
  1051.            u_VoiceFreq(li,Canaux[li]^.Freq);
  1052.          end;
  1053.      6 : begin;
  1054.            { volume slide }
  1055.            inc(Canaux[li]^.volume,Canaux[li]^.vslide);
  1056.            if Canaux[li]^.volume < 0 then Canaux[li]^.volume := 0;
  1057.            if Canaux[li]^.volume > 63 then Canaux[li]^.volume := 63;
  1058.            u_VoiceVolume(li,Canaux[li]^.volume);
  1059.            { vibrato }
  1060.            inc(Canaux[li]^.vibpos,Canaux[li]^.vibx);
  1061.            if Canaux[li]^.vibpos > 64 then
  1062.              dec(Canaux[li]^.vibpos);
  1063.            vibswap :=
  1064.              (VibratoTable[Canaux[li]^.vibpos] * Canaux[li]^.viby) div 256;
  1065.            inc(Canaux[li]^.Son_init,vibswap);
  1066.             if Canaux[li]^.Son_init < 1 then
  1067.               Canaux[li]^.Son_init := 1;
  1068.            Canaux[li]^.Freq :=
  1069.              longint(Voice_Base[14] div Canaux[li]^.Son_init);
  1070.            u_VoiceFreq(li,Canaux[li]^.Freq);
  1071.          end;
  1072.      7 : begin; { tremolo  *new* }
  1073.             inc(Canaux[li]^.vibpos,Canaux[li]^.vibx);
  1074.             if Canaux[li]^.vibpos > 64 then
  1075.               dec(Canaux[li]^.vibpos);
  1076.             vibswap :=
  1077.               (VibratoTable[Canaux[li]^.vibpos] * Canaux[li]^.viby) div 256;
  1078.             inc(Canaux[li]^.Volume,vibswap);
  1079.             if Canaux[li]^.Volume < 0 then Canaux[li]^.Volume := 0;
  1080.             if Canaux[li]^.Volume > 63 then Canaux[li]^.Volume := 63;
  1081.             u_VoiceVolume(li,Canaux[li]^.volume);
  1082.          end;
  1083.     8 : begin; { not used !!! }
  1084.         end;
  1085.     $a : begin; { Volume sliding   **new* }
  1086.            inc(Canaux[li]^.volume,Canaux[li]^.vslide);
  1087.            if Canaux[li]^.volume < 0 then Canaux[li]^.volume := 0;
  1088.            if Canaux[li]^.volume > 63 then Canaux[li]^.volume := 63;
  1089.            u_VoiceVolume(li,Canaux[li]^.volume);
  1090.          end;
  1091.     $e : begin;  { Effet étendu }
  1092.           case (Canaux[li]^.Operand shr 4) of
  1093.               9: begin; { Retriggering !!! }
  1094.                    if Canaux[li]^.Operand and $0f <> 0 then begin;
  1095.                      dec(Canaux[li]^.Retrig_count);
  1096.                      if Canaux[li]^.Retrig_count = 0 then begin;
  1097.                        Canaux[li]^.Retrig_count := Canaux[li]^.Operand and $0f;
  1098.                        u_Voicedata(Canaux[li]^.Mempos,Canaux[li]^.Loop_Start,
  1099.                               Canaux[li]^.Fin,li);
  1100.                        U_StartVoice(li,Play_Voice+Bit8+Canaux[li]^.Looping+Unidirect);
  1101.                      end;
  1102.                    end;
  1103.                  end;
  1104.            end;
  1105.         end;
  1106.     end;
  1107.   end;
  1108. end;
  1109.  
  1110.  
  1111.  
  1112. {$F+}
  1113. procedure mytimer; interrupt;
  1114. {
  1115.  Mon interruption de timer
  1116. }
  1117. begin;
  1118.   tick_effects;
  1119.   inc(tickcounter);
  1120.   if tickcounter >= ticklimit then begin;
  1121.     Tickcounter := 0;
  1122.     Play_Pattern_gus;
  1123.   end;
  1124.   Port[$20] := $20;
  1125. end;
  1126.  
  1127. procedure rien; interrupt;
  1128. {
  1129.  Interrupt dummy. On passe à cette procédure pour arrêter la sortie du son.
  1130. }
  1131. begin;
  1132.   port[$20] := $20;
  1133. end;
  1134.  
  1135. procedure _gus_modstart;
  1136. {
  1137.  Lance la sortie du fichier MOD par l'intermédiaire de l'interruption du timer. Le fichier MOD
  1138.  doit avoir été chargé au préalable !
  1139. }
  1140. var compteur : word;
  1141.     loz,hiz : byte;
  1142. begin;
  1143.  compteur := 1193180 DIV interrupt_speed;
  1144.  loz := lo(compteur);
  1145.  hiz := hi(compteur);
  1146.  asm
  1147.   cli
  1148.   mov dx,43h
  1149.   mov al,36h
  1150.   out dx,al
  1151.   mov dx,40h
  1152.   mov al,loz
  1153.   out dx,al
  1154.   mov al,hiz
  1155.   out dx,al
  1156.  end;
  1157.  getintvec(8,ancientimer);
  1158.  setintvec(8,@Mytimer);
  1159.  asm sti end;
  1160. end;
  1161.  
  1162.  
  1163. procedure _gus_player_pause;
  1164. {
  1165.  Arrête la sortie par l'interruption du timer
  1166. }
  1167. var li : integer;
  1168. begin;
  1169.  setintvec(8,@Rien);
  1170.  for li := 0 to 31 do
  1171.    u_VoiceVolume (li,0) ;
  1172. end;
  1173.  
  1174. procedure _gus_player_continue;
  1175. {
  1176.  Continue la sortie par l'interruption du timer.
  1177. }
  1178. var li : integer;
  1179. begin;
  1180.  setintvec(8,@Mytimer);
  1181.  for li := 1 to 31 do
  1182.    Voice_Rampin(li,Canaux[li]^.volume);
  1183. end;
  1184.  
  1185. procedure timerint_rest;
  1186. {
  1187.  Restaure l'interruption du timer en lui restituant ses valeurs initiales.
  1188. }
  1189. begin;
  1190.  asm
  1191.   cli
  1192.   mov dx,43h
  1193.   mov al,36h
  1194.   out dx,al
  1195.   xor ax,ax
  1196.   mov dx,40h
  1197.   out dx,al
  1198.   out dx,al
  1199.  end;
  1200.  setintvec(8,ancientimer);
  1201.  asm sti end;
  1202. end;
  1203.  
  1204.  
  1205. procedure dispose_mod;
  1206. {
  1207.  Supprime un MOD chargé en mémoire principale. Les samples sur la GUS
  1208.  ne sont PAS supprimés.
  1209. }
  1210. begin;
  1211.   for i := 0 to 31 do begin;
  1212.     U_StartVoice(i,Stop_Voice);
  1213.   end;
  1214.   for i := 1 to Vh.Num_Patts do begin;
  1215.     dos_freemem(Pattern[i]);
  1216.   end;
  1217.   for i := 0 to 15 do begin;
  1218.     dispose(Canaux[i]);
  1219.   end;
  1220.   for i := 0 to 31 do begin;
  1221.      dispose(Instruments[i]);
  1222.   end;
  1223. end;
  1224.  
  1225. procedure _gus_mod_quitter;
  1226. {
  1227.  Met fin à la sortie d'un MOD
  1228. }
  1229. begin;
  1230.   timerint_rest;
  1231.   dispose_mod;
  1232. end;
  1233.  
  1234.  
  1235. procedure _gus_initialiser;
  1236. {
  1237.  Initialise la GUS
  1238. }
  1239. begin;
  1240.   u_init;
  1241.   gus_speaker_on;
  1242. end;
  1243.  
  1244. procedure get_from_environment;
  1245. {
  1246.  Extrait l'adresse de Base de la GUS à partir de la variable d'environment
  1247.  ULTRASND
  1248. }
  1249. var apos,ipos,dpos : integer;
  1250.     astr,istr,dstr,gusstr : string;
  1251.     code : integer;
  1252. begin;
  1253.   GUS_envstr := GetEnv('ULTRASND');
  1254.  
  1255.  { identifier GUS-Base }
  1256.   gusstr := Copy(GUS_envstr,1,3);
  1257.   val(gusstr,GUS_BASE,code);
  1258.   if code <> 0 then begin;
  1259.     GUS_Environment := false;
  1260.   end else
  1261.     GUS_Environment := true;
  1262. end;
  1263.  
  1264. function dec_2_hex(w : word) : word;
  1265. {
  1266.  Conversion d'un nombre décimal en un nombre héxadécimal.
  1267.  Important pour la prise en charge de l'environnement
  1268. }
  1269. const exp : array[1..4] of word = (4096,256,16,0);
  1270. var c,hs : string;
  1271.     v,i,li : integer;
  1272. begin;
  1273.   str(w,hs);
  1274.   while length(hs) < 4 do hs := '0'+hs;
  1275.   w := 0;
  1276.   for li := 1 to 4 do begin;
  1277.     c := hs[li];
  1278.     val(c,v,i);
  1279.     w := w + v * exp[li];
  1280.   end;
  1281.   dec_2_hex := w;
  1282. end;
  1283.  
  1284. procedure write_environment;
  1285. {
  1286.  Renvoie l'adresse de BASE de la GUS provenant de l'environnement
  1287. }
  1288. begin;
  1289.   if GUS_Environment then begin;
  1290.     writeln('■ GUS_BASE: ',GUS_BASE);
  1291.     writeln('■ initializing Gravis Ultrasound Card');
  1292.     gus_base := dec_2_hex(gus_base);
  1293.     init_the_gus(Gus_base);
  1294.     delay(777);
  1295.   end else begin;
  1296.     writeln('The environment-variable ULTRASND is not set !');
  1297.     delay(777);
  1298.   end;
  1299. end;
  1300.  
  1301. function _gus_init_env : boolean;
  1302. {
  1303.  Initialise la GUS, il n'y a pas une vérification de la configuration
  1304.  matérielle mais une vérification de la variable d'environnement ULTRASND
  1305. }
  1306. begin;
  1307.   clrscr;
  1308.   get_from_environment;
  1309.   write_environment;
  1310.   _gus_init_env := gus_environment;
  1311. end;
  1312.  
  1313. begin;
  1314. end.
  1315.