home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Interdit
/
pc-interdit.iso
/
sound
/
gusmod
/
gus_mod.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1994-10-27
|
43KB
|
1,315 lines
{$A+,B-,D+,E+,F-,G+,I-,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y+}
unit gus_mod;
{
****************************************************************************
*** DATA BECKERs "PC UNDERGROUND" ***
*** ================================ ***
*** ***
*** Modplayer-Unit GUS_MOD ***
*** ***
*** L'unité GUS_MOD est destinée à faire jouer des MODs avec Gravis ***
*** Ultrasound, la carte son habituelle de la Demo-Scene. ***
*** ***
*** Cette unité a été utilisé pour programmer le (FREEWARE-) ***
*** Mod-Player TCP V1.0. ***
*** ***
*** Auteur : Boris Bertelsons (InspirE) ***
*** Nom du fichier : GUS_MOD.PAS ***
*** Dernière modification : 28.06.1994 ***
*** Version : 2.0 ***
*** Compilateur : Turbo Pascal 6.0 und höher ***
****************************************************************************
}
interface
function _gus_modload(nom : string) : boolean;
{
Charge le fichier contenu dans la variable nom dans la mémoire et dans
la GUS-RAM. La fonction renvoie la valeur TRUE, si le chargement du
fichier MOD s'est effectuée comme il le faut. Sinon elle renvoie la
valeur FALSE.
}
procedure _gus_modstart;
{
Lance l'exécution d'un MOD chargé par le biais d'un Timer-Interrupt
}
procedure _gus_mod_quitter;
{
Termine l'exécution d'un fichier MOD
}
procedure _gus_initialiser;
{
Initialisation de la GUS
}
function _gus_init_env : boolean;
{
Initialise la GUS. Il n'y a pas une vérification de la configuration
matérielle mais une vérification de la variable d'environnement ULTRASND
}
procedure _gus_set_chanelpos;
{
Occupe les positions de tous les canaux de la GUS
}
{
*************************************************************************
*** Déclarations des TYPES ***
*************************************************************************
}
type Song_header = record { Les variables globales}
kennung : string[25]; { du fichier MOD}
SongName : string[30];
LongChanson : byte;
Arrang : array[0..255] of byte;
Num_Patts : byte;
Num_Inst : byte;
end;
type Modinfo = record
Voix : word;
Titre : string[20];
Nb_Patt : word;
end;
Type Runinfo = record
Frappe : array[1..8] of byte;
Ligne,
Pattnr : integer;
Volumes : array[1..8] of byte;
speed : byte;
bpm : byte;
end;
type
PCanalInfo = ^TCanalInfo;
TCanalInfo = record
InstNr : byte; { Variables de la configuration }
Mempos : longint; { matérielle }
Fin : longint;
Loop_Start : longint;
Loop_Fin : longint;
Volume : integer; { Variables relatives au fichier MOD }
Freq : word;
Looping : byte;
Son : integer;
Son_Init : integer;
Son_Final : integer;
Effet : byte;
Operand : byte;
Effetx, { Variables relatives aux effets }
Effety : integer;
Appegpos : integer;
slidespeed : integer;
vslide : integer;
retrig_count : byte;
vibpos : byte;
vibx : byte;
viby : byte;
end;
PInstrumentnrInfo = ^TInstrumentInfo;
TInstrumentInfo = record
Nom : string[22];
Mempos : longint;
Fin : longint;
l_Start : longint;
l_Fin : longint;
Taille : word;
Loop_Start : word;
Loop_Fin : word;
Volume : word;
Looping : byte;
end;
{
*************************************************************************
*** Variables et constantes globales ***
*************************************************************************
}
Const
Play_Chanel : array[1..14] { permet de réaliser un "muting" du canal }
of byte = (1,1,1,1,1,1,1, { 1 = Active le canal GUS correspondant }
1,1,1,1,1,1,1); { 0 = Désactive le canal GUS correspondant }
var canaux : array[0..31] of PCanalInfo;
Instruments : array[0..31] of PInstrumentnrInfo;
MOD_Voix : word; { Dépend du nombre de voix (4/8) }
MOD_Patternsize : word; { Taille des Patterns en octets }
stop_Thevoice : array[1..8] of boolean;
vh : Song_Header;
Modinfptr : pointer;
Modinf : Modinfo;
Runinf : Runinfo;
chpos : array[1..8] of integer; { Position des voix }
implementation
uses dos,crt,design,fselect;
const VibratoTable : array[0..63] of integer =(
0,24,49,74,97,120,141,161,
180,197,212,224,235,244,250,253,
255,253,250,244,235,224,212,197,
180,161,141,120,97,74,49,24,
0,-24,-49,-74,-97,-120,-141,-161,
-180,-197,-212,-224,-235,-244,-250,-253,
-255,-253,-250,-244,-235,-224,-212,-197,
-180,-161,-141,-120,-97,-74,-49,-24);
const Voice_Divisor : array[14..32] of byte =
(43,40,37,35,33,31,30,28,27,26,25,24,23,22,21,20,20,19,18);
Voice_Base : array[14..14] of longint =
(88195);
const GUS_Environment : boolean = true;
Modinstance : byte = 31; { Le nombre des instruments }
{ d'un fichier MOD (15 oder 31) }
ModId : array[1..3] of { Identification des MOD à 4 voix }
String = ('M.K.','FLT4','4CHN');
Chn6 : string = '6CHN'; { Identification des MOD à 6 voix }
chn8 : string = '8CHN'; { Identification des MOD à 8 voix }
Modidentit : string { Identification de tous les MOD }
= 'M.K.FLT44CHN6CHN8CHN'; { relatif à la détection}
Interrupt_speed : word = 50; { Nombre d'appels à une interruption}
Num_Voices = 14; { Nous utilisons les 14 canaux GUS }
U_Ram_Freepos : longint = 2; { pour la gestion de la GUS - RAM }
Play_Voice = 0; Stop_Voice = 3; { Les constantes destinés à la}
Bit8 = 0; Bit16 = 4; { sélection du type de la voix}
No_Loop = 0; Avec_Loop = 8;{ qu'on va écouter}
Unidirect = 0; Bidirect = 16;
Go_forw = 0; Go_Back = 64;
var GUS_envstr : string;
GUS_BASE : word;
oldv : array[0..15] of integer;
tickcounter, { Destiné au contrôle de la vitesse }
ticklimit : word;
ancientimer : pointer; { Pointeur sur la vieille timer, }
i : Integer ; { la variable la plus choyée }
gusmf : file; { Destiné au Handling du fichier MOD }
Pattern : array[0..127] { Pointeur sur le Pattern dans le Ram}
of pointer;
{$L c:\edition\prog\fr\asm\Gusasm}
procedure U_StartVoice(Nr,Modus : byte); external;
{
Démarre le canal contenu dans la variable Nr de la Gus dans
le modus activé par modus
}
procedure u_Voicefreq(Nr : byte;Freq : word); external;
{
Positionne la fréquence Freq pour le canal sélectionné par Nr }
procedure u_VoiceBalance(Nr,balance : byte); external;
{
Destiné à la configuration de la 'balance' du canal indiqué par Nr.
Les valeurs pour 'balance' peuvent se situer entre 0 et 15.
C'est à dire : 0 représente la position toute à la gauche, 7 le milieu
et 15 la position toute à la droite.
}
procedure u_VoiceVolume(Nr : byte; Vol : word); external;
{
En faisant cela vous réglez le volume sonore Vol de Nr contenant le canal
}
procedure u_delay; external;
{
Pour régler le temps d'attente lors de l'accès à des registres à modification automatique de GF1,
destiné à l'usage interne)
}
function detect_gus : word; external;
{
Destiné à l'identification de la GUS. La fonction renvoie une 0, si
le canal a été trouvé et le nombre 1 si aucune GUS n'a pu être
identifiée. La fonction règle le bon Base-Port pour la GUS.
}
procedure u_Initialize; external;
{
Initialise Gravis Ultrasound.
}
procedure Ultra_Mem2Gus(samp : pointer;start : longint;laenge : word); external;
{
Avec cette procédure vous allez copier un Sampel de la Ram dans la RAM de la GUS
En faisant cela, le Sampel adressé par samp se fait transmettre avec la
méthode Poke. Dans laenge vous indiquez la longueur du Sampel à transmettre.
}
procedure gus_speaker_on; external;
{
Active le haut-parleur de la GUS.
}
procedure u_Voicedata(start,lsta,sende : longint;Nr : word); external;
{
Règle les paramètres pour le canal. start désigne la position initiale de la
voix dans la GUS-Ram, lsta le début du boucle et renvoie
la position finale du canal. Vous sélectionnez le nombre du canal moyennant variable Nr.
}
function Ffacteur(t:word) : word; external;
{
La fonction Ffaktor renvoie la fréquence qui correspond au numéro des notes t
pour la GUS à partir du tableau des fréquences Mod.
}
function Note(hauteur : word) : byte; external;
{
Hiermit ermitteln Sie aus dem in hoehe übergebenen Tonhöhen-Wert aus der
MOD-Datei die Nummer der Note.
}
procedure voice_rampin(Stimme:byte;vol : word); external;
{
La fonction est à utiliser, si on ne veut pas entendre des crépitements.
La voix sélectionné dans 'voix' ne se fait pas répercuter toute de suite
sur le volume sonore indiqué par vol, mais se fait slider avec la Gus-Ramp
le plus rapidement possible de 0 au volume sonore souhaité.
Cette procédure remplace u_VoiceVolume.
}
procedure voice_slide(nr,speed : byte;vol : word); external;
{
Avec cette procédure vous pouvez intégrer un canal dans la GUS. Nr renvoie
au numéro du canal à intégrer, vous avez dans vol le volume sonore cible.
En ce qui concerne la vitesse, les deux bits supérieurs indique le
Ramp-Speed et les six 6 Bits inférieurs le facteur d'incrémentation.
Vous calculez le Ramp le plus vite avec une valeur de 63, le plus lent
avec une valeur de 192.
}
procedure dos_getmem(var indicateur:pointer;quantite:word); external;
{
Cett procédure remplace la Getmem-Procedure de PASCAL. Du fait qu'elle
utilise la mémoire du DOS elle est d'une nécessité vitale pour les
programmes résidents parce qu'il faut qu'ils n'occupent pas toujours
la même emplacement en mémoire et permettent de s'adapter à la MOD.
}
procedure dos_freemem(indicateur:pointer); external;
{
Dos_Freemem ist das Equivalent zur Pascal Freemem Procedure. Eine Größe
des freizugebenden Speichers ist nicht anzugeben.
}
procedure init_gus_base(base : word); external;
{
Initialise Gravis Ultrasound avec l'adresse transmise dans Base.
}
{$L c:\edition\prog\fr\asm\loadin}
procedure loadin; external; { Ansi - Pic }
procedure init_the_gus(base : word);
begin;
init_gus_base(base);
end;
procedure u_init;
var li : integer;
begin;
u_Initialize;
end;
FUNCTION ConvertString(Source : Pointer; Size : BYTE):String;
{
Transforme une chaine ASCIIZ en un String Pascal
}
VAR
WorkStr : String;
BEGIN
Move(Source^,WorkStr[1],Size);
WorkStr[0] := CHR(Size);
if pos(#0,Workstr) <> 0 then WorkStr[0] := chr(pos(#0,Workstr)-1);
ConvertString := WorkStr;
END;
procedure Charge_Instrument(Nr : byte);
{
Charge l'instrument de numéro nr dans la RAM de la carte GUS
}
var gr : longint;
samp : pointer;
begin;
gr := Instruments[nr]^.Taille;
if gr > 10 then begin; { ne charge que si > 10! }
dos_getmem(samp,gr);
Blockread(gusmf,samp^,gr);
U_Ram_freepos := U_Ram_freepos + (16-(U_Ram_freepos MOD 16));
Instruments[nr]^.Mempos := U_Ram_freepos;
Ultra_Mem2Gus(samp,Instruments[nr]^.Mempos,gr);
dos_freemem(samp); { Initialise les variables des voix }
Instruments[nr]^.l_start :=
Instruments[nr]^.Mempos + Instruments[nr]^.Loop_Start;
if Instruments[nr]^.Looping = Avec_loop then begin;
Instruments[nr]^.fin :=
Instruments[nr]^.Mempos + Instruments[nr]^.Loop_Fin;
end else begin;
Instruments[nr]^.fin := Instruments[nr]^.Mempos + gr - 25;
end;
Inc(U_Ram_Freepos,gr); { repousser le pointeur de gestion }
end;
end;
procedure Nouv_Interrupt_Speed(speed : word);
{
Règle la vitesse d'Interrupt correspondant au BpM.
}
var zaehler : word;
loz,hiz : byte;
begin;
interrupt_speed := round(speed / 2.5);
zaehler := 1193180 DIV interrupt_speed;
loz := lo(zaehler);
hiz := hi(zaehler);
asm
cli
mov dx,43h
mov al,36h
out dx,al
mov dx,40h
mov al,loz
out dx,al
mov al,hiz
out dx,al
sti
end;
end;
procedure _gus_set_chanelpos;
{
Positionne les différents canaux de la GUS
}
begin;
u_VoiceBalance(1,chpos[1]);
u_VoiceBalance(2,chpos[2]);
u_VoiceBalance(3,chpos[3]);
u_VoiceBalance(4,chpos[4]);
u_VoiceBalance(5,chpos[5]);
u_VoiceBalance(6,chpos[6]);
u_VoiceBalance(7,chpos[7]);
u_VoiceBalance(8,chpos[8]);
end;
procedure display_loading(s : string);
{
Indique la progression dans le chargment du Sample.
}
var li,slen : integer;
var z : integer;
begin;
for z := 0 to 12 do begin;
move(ptr(seg(loadin),ofs(loadin)+z*34*2)^,ptr($B800,z*160+8*160+44)^,34*2);
end;
while pos('\',s) <> 0 do begin;
delete(s,1,pos('\',s));
end;
slen := length(s);
slen := (15 - slen) div 2;
for li := 1 to slen do s := ' '+s;
gotoxy(33,13);
write(s);
end;
function _gus_modload(nom : string) : boolean;
{
Charge le fichier MOD transmis par "nom". Suppose que le fichier indiqué
dans le chemin d'accès existe et n'est pas protégé contre l'écriture.
}
var dummya : array[0..30] of byte;{ Pour le traitement de la chaîne }
daptr : pointer; { pointeur sur dummya }
dumw : word; { Variable dummy pour lire}
dumb : byte;
Longreste : longint; { pour connaître le nombre de patterns }
li : integer;
Identit : array[1..4] of char;{ Identité du fichier MOD }
ias : integer; { Position de départ fonction de l'instrument }
begin;
U_Ram_freepos := 32;
for li := 0 to 15 do begin;
new(Canaux[li]);
canaux[li]^.vibpos := 0;
end;
for li := 0 to 31 do begin;
new(Instruments[li]);
Instruments[li]^.Nom := '';
end;
runinf.Ligne := 0;
runinf.Pattnr := -1;
tickcounter := 0;
ticklimit := 6;
runinf.speed := 6;
runinf.bpm := 125;
ias := 0;
daptr := @dummya;
assign(gusmf,nom); { Ouvrir fichier + initialiser la longueur }
reset(gusmf,1);
save_screen;
display_loading(nom);
Longreste := filesize(gusmf);
Longreste := Longreste - 1084;
seek(gusmf,1080); { Vérifier si c'est un MOD à 15 ou à 31 voix }
Blockread(gusmf,Identit,4);
if pos(Identit,Modidentit) = 0 then begin;
{ 15 Voix? }
seek(gusmf,600);
Blockread(gusmf,Identit,4);
if pos(Identit,Modidentit) = 0 then begin;
{ Pas de fichier MOD valide }
writeln('Pas de fichier MOD valide !!!');
halt(0);
end else begin;
Modinstance := 15;
ias := -16*30;
end;
end;
if (Identit = MODId[1]) or { Nombre de voix du fichier MOD ? }
(Identit = MODId[2]) or
(Identit = MODId[3])
then begin;
MOD_Voix := 4;
MOD_Patternsize := 4*256;
end else
if (Identit = CHn6) then begin;
_gus_modload := false;
exit;
end else
if (Identit = CHn8) then begin;
MOD_Voix := 8;
MOD_Patternsize := 8*256;
end;
seek(gusmf,0);
Blockread(gusmf,dummya,20); { Connaître le nom du fichier }
vh.SongName := ConvertString(daptr,20);
seek(gusmf,950+ias); { Longueur en patterns }
Blockread(gusmf,vh.longchanson,1);
seek(gusmf,952+ias); { lit l'arrangement }
Blockread(gusmf,vh.Arrang,128);
vh.Num_Inst := Modinstance; { lit les instruments (15/31) }
seek(gusmf,20+ias);
for li := 1 to 32 do Instruments[li]^.Nom := '';
for li := 1 to vh.Num_Inst do begin;
Blockread(gusmf,dummya,22); { Noms des instruments }
Instruments[li]^.Nom := ConvertString(daptr,22);
Blockread(gusmf,dumw,2); { Longueur du sample }
Instruments[li]^.Taille := swap(dumw) * 2;
Blockread(gusmf,dumb,1); { lit le volume }
Blockread(gusmf,dumb,1);
Instruments[li]^.Volume := dumb;
Blockread(gusmf,dumw,2); { lit le départ du loop }
Instruments[li]^.Loop_Start := swap(dumw) * 2;
Blockread(gusmf,dumw,2);
dumw := swap(dumw) * 2; { lit la fin du loop : début + longueur}
Instruments[li]^.Loop_Fin := Instruments[li]^.Loop_Start+dumw;
if (Instruments[li]^.Loop_Fin - { Looping dans l'instrument ? }
Instruments[li]^.Loop_Start) >= 10 then begin;
Instruments[li]^.Looping := Avec_loop;
end else begin;
Instruments[li]^.Looping := no_loop;
end;
Dec(Longreste,Instruments[li]^.Taille);
end;
Vh.Num_Patts := Longreste DIV MOD_Patternsize ; { nombre de patterns ? }
seek(gusmf,1084+ias);
for li := 1 to Vh.Num_Patts do begin; { lit les patterns }
dos_getmem(Pattern[li],MOD_Patternsize );
Blockread(gusmf,Pattern[li]^,MOD_Patternsize );
end;
for li := 1 to vh.Num_Inst do begin; { lit les instruments }
Charge_Instrument(li);
screen[16,23+li].a := 5;
end;
close(gusmf);
for i := 1 to 31 do begin; { initialise les variables de canaux }
u_VoiceBalance (i,7) ;
u_VoiceVolume (i,0) ;
u_VoiceFreq (i,12000);
U_StartVoice(i,Stop_Voice);
u_Voicedata(0,0,0,i);
end;
runinf.Ligne := 0; { initialise les variables run }
runinf.Pattnr := -1;
tickcounter := 0;
ticklimit := 6;
runinf.speed := 6;
runinf.bpm := 125;
if MOD_Voix = 4 then begin; { ordonne les voix en demi-cercle }
chpos[1] := 2;
chpos[2] := 5;
chpos[3] := 9;
chpos[4] := 12;
_gus_set_chanelpos;;
end;
if MOD_Voix = 8 then begin;
chpos[1] := 1;
chpos[2] := 3;
chpos[3] := 5;
chpos[4] := 7;
chpos[5] := 7;
chpos[6] := 9;
chpos[7] := 11;
chpos[8] := 13;
_gus_set_chanelpos;;
end;
nouv_interrupt_Speed(runinf.bpm);
restore_screen;
Modinf.Voix := MOD_Voix; { Constante MOD-Infos dans la structure }
Modinf.Titre := vh.Songname; { à transmettre }
Modinf.Nb_patt := Vh.Longchanson;
_gus_modload := true;
end;
procedure effet_vibrato(nr : byte);
{
Procédure vibrato tirée du traitement des effets
}
var vibswap : integer;
begin;
inc(Canaux[nr]^.vibpos,Canaux[nr]^.vibx);
if Canaux[nr]^.vibpos > 64 then
dec(Canaux[nr]^.vibpos,64);
vibswap :=
(VibratoTable[Canaux[nr]^.vibpos] * Canaux[nr]^.viby) div 256;
inc(Canaux[nr]^.Son_init,vibswap);
if Canaux[nr]^.Son_init < 1 then
Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
end;
procedure E_toneportamento(nr : byte);
{
Procédure TonePortamento tirée du traitement des effets
}
begin;
if Canaux[nr]^.slidespeed < 0 then
begin
inc(Canaux[nr]^.Son_init,Canaux[nr]^.slidespeed);
if Canaux[nr]^.Son_init < Canaux[nr]^.Son_final then
Canaux[nr]^.Son_init := Canaux[nr]^.Son_final;
end else begin
inc(Canaux[nr]^.Son_init,Canaux[nr]^.slidespeed);
if Canaux[nr]^.Son_init > Canaux[nr]^.Son_final then
Canaux[nr]^.Son_init := Canaux[nr]^.Son_final;
end;
if Canaux[nr]^.Son_init < 1 then
Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
oldv[nr] := Canaux[nr]^.Son_init;
end;
procedure EI_toneportamento(nr : byte);
{
Init pour la procédure vibrato tirée du traitement des effets
}
begin;
{ Définit le facteur Inc }
if Canaux[nr]^.Operand <> 0 then
begin;
if Canaux[nr]^.Son_init > Canaux[nr]^.Son_final then
begin;
Canaux[nr]^.slidespeed := -(Canaux[nr]^.Operand);
end else begin;
Canaux[nr]^.slidespeed := (Canaux[nr]^.Operand);
end;
end;
if Canaux[nr]^.Son_init < 1 then
Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
oldv[nr] := Canaux[nr]^.Son_init;
end;
procedure Initialiser_Effets(nr : byte);
var swaplong : longint;
vibswap : integer;
begin;
if Canaux[nr]^.Effet = 0 then exit;
case Canaux[nr]^.Effet of
0 : begin; { Appegio }
Canaux[nr]^.Appegpos := 0;
Canaux[nr]^.Effetx := Canaux[nr]^.Operand shr 4;
Canaux[nr]^.Effety := Canaux[nr]^.Operand and $0f;
inc(Canaux[nr]^.Appegpos);
case (Canaux[nr]^.Appegpos MOD 3) of
0 : begin; {ap = 3 !}
Canaux[nr]^.Son_init :=
Canaux[nr]^.Son + Canaux[nr]^.Effety;
end;
1 : begin; {ap = 1 !}
Canaux[nr]^.Son_init :=
Canaux[nr]^.Son;
end;
2 : begin; {ap = 2 !}
Canaux[nr]^.Son_init :=
Canaux[nr]^.Son + Canaux[nr]^.Effetx;
end;
end;
if Canaux[nr]^.Son_init < 1 then
Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
end;
1 : begin; { Portamento up }
dec(Canaux[nr]^.Son_init,Canaux[nr]^.Operand);
if Canaux[nr]^.Son_init < 1 then
Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
end;
2 : begin; { Portamento down }
inc(Canaux[nr]^.Son_init,Canaux[nr]^.Operand);
if Canaux[nr]^.Son_init < 1 then
Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
end;
3 : begin; { Tone Portamento }
EI_toneportamento(nr);
end;
4 : begin; { Vibrato *new* }
Canaux[nr]^.vibx := Canaux[nr]^.Operand shr 4;
Canaux[nr]^.viby := Canaux[nr]^.Operand and $0f;
effet_vibrato(nr);
end;
5 : begin; {NOTE SLIDE + VOLUME SLIDE: *new* }
{ init }
if Canaux[nr]^.Operand <= $0f then
begin;
Canaux[nr]^.vslide := -(Canaux[nr]^.Operand AND $0f);
Canaux[nr]^.slidespeed := -(Canaux[nr]^.Operand AND $0f);
end else begin;
Canaux[nr]^.vslide := (Canaux[nr]^.Operand shr 4);
Canaux[nr]^.slidespeed := (Canaux[nr]^.Operand shr 4);
end;
{ volume slide }
inc(Canaux[nr]^.volume,Canaux[nr]^.vslide);
if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
u_VoiceVolume(Nr,Canaux[nr]^.volume);
{ Note slide }
inc(Canaux[nr]^.Son_init,Canaux[nr]^.slidespeed);
if Canaux[nr]^.Son_init < 1 then
Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
end;
6 : begin; { Vibrato & Volume slide *new* }
{ init }
Canaux[nr]^.vibx := Canaux[nr]^.Operand shr 4;
Canaux[nr]^.viby := Canaux[nr]^.Operand and $0f;
if Canaux[nr]^.Operand <= $0f then
begin;
Canaux[nr]^.vslide := -(Canaux[nr]^.Operand AND $0f);
end else begin;
Canaux[nr]^.vslide := (Canaux[nr]^.Operand shr 4);
end;
{ volume slide }
inc(Canaux[nr]^.volume,Canaux[nr]^.vslide);
if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
u_VoiceVolume(Nr,Canaux[nr]^.volume);
{ vibrato }
effet_vibrato(nr);
end;
7 : begin; { tremolo *new* }
Canaux[nr]^.vibx := Canaux[nr]^.Operand shr 4;
Canaux[nr]^.viby := Canaux[nr]^.Operand and $0f;
inc(Canaux[nr]^.vibpos,Canaux[nr]^.vibx);
if Canaux[nr]^.vibpos > 64 then
dec(Canaux[nr]^.vibpos);
vibswap :=
(VibratoTable[Canaux[nr]^.vibpos] * Canaux[nr]^.viby) div 256;
inc(Canaux[nr]^.Volume,vibswap);
if Canaux[nr]^.Volume < 0 then Canaux[nr]^.Volume := 0;
if Canaux[nr]^.Volume > 63 then Canaux[nr]^.Volume := 63;
u_VoiceVolume(nr,Canaux[nr]^.volume);
end;
8 : begin; { non utilisé !!! }
{
Non utilisé officiellement. Se prête donc à la programmation
pour synchroniser des événements dans une démo...
}
end;
9 : begin; { Sample - Offset *new* }
swaplong := longint((Canaux[nr]^.Operand+1)) * 256;
Canaux[nr]^.Mempos := Canaux[nr]^.Mempos+swaplong;
u_Voicedata(Canaux[nr]^.Mempos,Canaux[nr]^.Loop_Start,
Canaux[nr]^.Fin,nr);
U_StartVoice(nr,Play_Voice+Bit8+Canaux[nr]^.Looping+Unidirect);
end;
$a : begin; { Volume sliding *new* }
if Canaux[nr]^.Operand <= $0f then
begin;
Canaux[nr]^.vslide := -(Canaux[nr]^.Operand AND $0f);
end else begin;
Canaux[nr]^.vslide := (Canaux[nr]^.Operand shr 4);
end;
inc(Canaux[nr]^.volume,Canaux[nr]^.vslide);
if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
u_VoiceVolume(Nr,Canaux[nr]^.volume);
end;
$b : begin; { Position Jump *ok* }
runinf.Ligne := 64;
runinf.Pattnr := Canaux[nr]^.Operand;
end;
$c : begin; { Set Note Volume *ok* }
if Canaux[nr]^.Operand > 63 then Canaux[nr]^.Operand := 63;
if Canaux[nr]^.Operand < 1 then
begin
Canaux[nr]^.volume := 0;
u_VoiceVolume(nr,0);
U_StartVoice(nr,Stop_Voice);
stop_Thevoice[nr] := true;
end else begin
Canaux[nr]^.volume := Canaux[nr]^.Operand;
u_VoiceVolume(Nr,Canaux[nr]^.volume);
Runinf.Volumes[nr] := 63;
end;
end;
$d : begin; { Pattern Break *ok* }
runinf.Ligne := 64;
end;
$e : begin; { Effet étendu }
case (Canaux[nr]^.Operand shr 4) of
1 : begin; { Fine slide up }
dec(Canaux[nr]^.Son_init,Canaux[nr]^.Operand and $0f);
if Canaux[nr]^.Son_init < 1 then Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
end;
2 : begin; { Fine slide down }
inc(Canaux[nr]^.Son_init,Canaux[nr]^.Operand and $0f);
if Canaux[nr]^.Son_init < 1 then Canaux[nr]^.Son_init := 1;
Canaux[nr]^.Freq :=
longint(Voice_Base[14] div Canaux[nr]^.Son_init);
u_VoiceFreq(nr,Canaux[nr]^.Freq);
end;
9 : begin; { Retriggering !!! *new* }
Canaux[nr]^.Retrig_count :=
Canaux[nr]^.Operand and $0f;
end;
$a : begin; { fine volume slide up }
Canaux[nr]^.vslide := (Canaux[nr]^.Operand AND $0f);
inc(Canaux[nr]^.volume,Canaux[nr]^.vslide);
if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
u_VoiceVolume(Nr,Canaux[nr]^.volume);
end;
$b : begin; { fine volume slide down }
Canaux[nr]^.vslide := (Canaux[nr]^.Operand AND $0f);
dec(Canaux[nr]^.volume,Canaux[nr]^.vslide);
if Canaux[nr]^.volume < 0 then Canaux[nr]^.volume := 0;
if Canaux[nr]^.volume > 63 then Canaux[nr]^.volume := 63;
u_VoiceVolume(Nr,Canaux[nr]^.volume);
end;
$c : begin; { Cut Voice *ok* }
stop_Thevoice[nr] := true;
end;
end;
end;
$f : begin; { Set Speed *ok* }
if Canaux[nr]^.Operand <= $f then begin;
ticklimit := Canaux[nr]^.Operand;
runinf.speed := ticklimit;
end else begin;
runinf.bpm := Canaux[nr]^.Operand;
nouv_interrupt_Speed(Canaux[nr]^.Operand);
end;
end;
end;
end;
procedure play_pattern_gus;
{
On appellera cette procédure régulièrement. Elle exécute une ligne
du fichier MOD.
}
var li : integer;
dumw : word;
La_ligne : array[1..8,0..3] of Byte;
Effet : byte;
Ton : word;
Inst : byte;
begin;
{
**************************************************************************
*** Passer dans le fichier MOD ***
**************************************************************************
}
inc(runinf.Ligne); { En avant d'une ligne }
if runinf.Ligne > 64 then runinf.Ligne := 1;
if runinf.Ligne = 1 then begin; { Nouveau pattern ? }
inc(runinf.Pattnr);
if runinf.Pattnr > vh.Longchanson then runinf.Pattnr := 1;
end;
{ Charge les notes }
move(ptr(seg(pattern[vh.Arrang[runinf.Pattnr]+1]^),
ofs(pattern[vh.Arrang[runinf.Pattnr]+1]^)+
(runinf.Ligne-1)*4*Mod_Voix)^,
La_ligne,4*8);
{
**************************************************************************
*** Traiter les voix ***
**************************************************************************
}
for li := 1 to MOD_Voix do begin;
if play_chanel[li] = 1 then begin;
stop_Thevoice[li] := false;
Ton := ((La_ligne[li,0] AND $0f) shl 8)+La_ligne[li,1];
Inst := (La_ligne[li,0] AND $f0)+((La_ligne[li,2] AND $F0) SHR 4);
Canaux[li]^.Effet := La_ligne[li,2] AND $0f;
Canaux[li]^.Operand := La_ligne[li,3];
Canaux[li]^.Son_init := oldv[li];
if Ton <> 0 then begin; { Est-ce qu'un son a été indiqué ??? }
if Canaux[li]^.Effet = 3 then begin;
Canaux[li]^.Son_final := Ton;
end else begin;
Canaux[li]^.Son := Ton;
Canaux[li]^.Son_init := Ton;
oldv[li] := Canaux[li]^.Son_init;
end;
end;
If Inst <> 0 then begin; { utiliser un nouvel instrument ??? }
Canaux[li]^.InstNr := Inst;
Canaux[li]^.Mempos := Instruments[Canaux[li]^.InstNr]^.Mempos;
Canaux[li]^.Loop_Start := Instruments[Canaux[li]^.InstNr]^.l_start;
Canaux[li]^.Fin := Instruments[Canaux[li]^.InstNr]^.Fin;
Canaux[li]^.volume := Instruments[Canaux[li]^.InstNr]^.volume;
Canaux[li]^.Looping := Instruments[Canaux[li]^.InstNr]^.Looping;
u_Voicedata(Canaux[li]^.Mempos,Canaux[li]^.Loop_Start,
Canaux[li]^.Fin,li);
end;
Canaux[li]^.Retrig_count := 0;
Initialiser_Effets(li);
If (Ton <> 0) then begin; { note frappée }
Canaux[li]^.Freq := longint(Voice_Base[14] div Canaux[li]^.Son_init);
u_VoiceFreq(li,Canaux[li]^.Freq); { définir la fréquence }
if Canaux[li]^.Effet = $c then begin; { Extra, sinon trop tôt ! }
if Canaux[li]^.Operand > 63 then Canaux[li]^.Operand := 63;
if Canaux[li]^.Operand < 1 then
begin
Canaux[li]^.volume := 0;
u_VoiceVolume(li,0);
U_StartVoice(li,Stop_Voice);
stop_Thevoice[li] := true;
end else begin
Canaux[li]^.volume := Canaux[li]^.Operand;
u_VoiceVolume(li,Canaux[li]^.volume);
Runinf.Volumes[li] := 63;
end;
end else begin;
if Canaux[li]^.volume > 63 then Canaux[li]^.volume := 63;
voice_rampin(li,Canaux[li]^.volume);
Runinf.Volumes[li] := 63;
end;
U_StartVoice(li,Stop_Voice); { Arrêter l'ancienne voix }
u_Voicedata(Canaux[li]^.Mempos,Canaux[li]^.Loop_Start,
Canaux[li]^.Fin,li);
if not stop_Thevoice[li] then begin; { lancer la nouvelle voix }
U_StartVoice(li,Play_Voice+Bit8+Canaux[li]^.Looping+Unidirect);
Runinf.Frappe[li] := Canaux[li]^.volume * 4; { Pour égaliseur }
end;
end; { note frappée }
end else begin;
u_VoiceVolume(li,0);
end;
end; {for}
end;
procedure tick_effects;
var li : integer;
vibswap : integer;
begin;
for li := 1 to MOD_Voix do begin;
if runinf.volumes[li] > 0 then
dec(runinf.volumes[li]);
case Canaux[li]^.Effet of { Traitement des effets en cours d'exécution }
0 : begin;
inc(Canaux[li]^.Appegpos);
case (Canaux[li]^.Appegpos MOD 3) of
0 : begin; {ap = 3 !}
Canaux[li]^.Son_init :=
Canaux[li]^.Son + Canaux[li]^.Effety;
end;
1 : begin; {ap = 1 !}
Canaux[li]^.Son_init :=
Canaux[li]^.Son;
end;
2 : begin; {ap = 2 !}
Canaux[li]^.Son_init :=
Canaux[li]^.Son + Canaux[li]^.Effetx;
end;
end;
end;
1 : begin;
{!"! new }
Canaux[li]^.Operand := Canaux[li]^.Operand and $0F;
{!"! new end }
dec(Canaux[li]^.Son_init,Canaux[li]^.Operand);
if Canaux[li]^.Son_init < 1 then
Canaux[li]^.Son_init := 1;
Canaux[li]^.Freq :=
longint(Voice_Base[14] div Canaux[li]^.Son_init);
u_VoiceFreq(li,Canaux[li]^.Freq);
end;
2 : begin;
{!"! new }
Canaux[li]^.Operand := Canaux[li]^.Operand and $0F;
{!"! new end }
inc(Canaux[li]^.Son_init,Canaux[li]^.Operand);
if Canaux[li]^.Son_init < 1 then
Canaux[li]^.Son_init := 1;
Canaux[li]^.Freq :=
longint(Voice_Base[14] div Canaux[li]^.Son_init);
u_VoiceFreq(li,Canaux[li]^.Freq);
end;
3 : begin; { Tone Portamento }
E_toneportamento(li);
end;
4 : begin; { vibrato *new* }
effet_vibrato(li);
end;
5 : begin;
{ volume slide }
inc(Canaux[li]^.volume,Canaux[li]^.vslide);
if Canaux[li]^.volume < 0 then Canaux[li]^.volume := 0;
if Canaux[li]^.volume > 63 then Canaux[li]^.volume := 63;
u_VoiceVolume(li,Canaux[li]^.volume);
{ Note slide }
inc(Canaux[li]^.Son_init,Canaux[li]^.slidespeed);
if Canaux[li]^.Son_init < 1 then
Canaux[li]^.Son_init := 1;
Canaux[li]^.Freq :=
longint(Voice_Base[14] div Canaux[li]^.Son_init);
u_VoiceFreq(li,Canaux[li]^.Freq);
end;
6 : begin;
{ volume slide }
inc(Canaux[li]^.volume,Canaux[li]^.vslide);
if Canaux[li]^.volume < 0 then Canaux[li]^.volume := 0;
if Canaux[li]^.volume > 63 then Canaux[li]^.volume := 63;
u_VoiceVolume(li,Canaux[li]^.volume);
{ vibrato }
inc(Canaux[li]^.vibpos,Canaux[li]^.vibx);
if Canaux[li]^.vibpos > 64 then
dec(Canaux[li]^.vibpos);
vibswap :=
(VibratoTable[Canaux[li]^.vibpos] * Canaux[li]^.viby) div 256;
inc(Canaux[li]^.Son_init,vibswap);
if Canaux[li]^.Son_init < 1 then
Canaux[li]^.Son_init := 1;
Canaux[li]^.Freq :=
longint(Voice_Base[14] div Canaux[li]^.Son_init);
u_VoiceFreq(li,Canaux[li]^.Freq);
end;
7 : begin; { tremolo *new* }
inc(Canaux[li]^.vibpos,Canaux[li]^.vibx);
if Canaux[li]^.vibpos > 64 then
dec(Canaux[li]^.vibpos);
vibswap :=
(VibratoTable[Canaux[li]^.vibpos] * Canaux[li]^.viby) div 256;
inc(Canaux[li]^.Volume,vibswap);
if Canaux[li]^.Volume < 0 then Canaux[li]^.Volume := 0;
if Canaux[li]^.Volume > 63 then Canaux[li]^.Volume := 63;
u_VoiceVolume(li,Canaux[li]^.volume);
end;
8 : begin; { not used !!! }
end;
$a : begin; { Volume sliding **new* }
inc(Canaux[li]^.volume,Canaux[li]^.vslide);
if Canaux[li]^.volume < 0 then Canaux[li]^.volume := 0;
if Canaux[li]^.volume > 63 then Canaux[li]^.volume := 63;
u_VoiceVolume(li,Canaux[li]^.volume);
end;
$e : begin; { Effet étendu }
case (Canaux[li]^.Operand shr 4) of
9: begin; { Retriggering !!! }
if Canaux[li]^.Operand and $0f <> 0 then begin;
dec(Canaux[li]^.Retrig_count);
if Canaux[li]^.Retrig_count = 0 then begin;
Canaux[li]^.Retrig_count := Canaux[li]^.Operand and $0f;
u_Voicedata(Canaux[li]^.Mempos,Canaux[li]^.Loop_Start,
Canaux[li]^.Fin,li);
U_StartVoice(li,Play_Voice+Bit8+Canaux[li]^.Looping+Unidirect);
end;
end;
end;
end;
end;
end;
end;
end;
{$F+}
procedure mytimer; interrupt;
{
Mon interruption de timer
}
begin;
tick_effects;
inc(tickcounter);
if tickcounter >= ticklimit then begin;
Tickcounter := 0;
Play_Pattern_gus;
end;
Port[$20] := $20;
end;
procedure rien; interrupt;
{
Interrupt dummy. On passe à cette procédure pour arrêter la sortie du son.
}
begin;
port[$20] := $20;
end;
procedure _gus_modstart;
{
Lance la sortie du fichier MOD par l'intermédiaire de l'interruption du timer. Le fichier MOD
doit avoir été chargé au préalable !
}
var compteur : word;
loz,hiz : byte;
begin;
compteur := 1193180 DIV interrupt_speed;
loz := lo(compteur);
hiz := hi(compteur);
asm
cli
mov dx,43h
mov al,36h
out dx,al
mov dx,40h
mov al,loz
out dx,al
mov al,hiz
out dx,al
end;
getintvec(8,ancientimer);
setintvec(8,@Mytimer);
asm sti end;
end;
procedure _gus_player_pause;
{
Arrête la sortie par l'interruption du timer
}
var li : integer;
begin;
setintvec(8,@Rien);
for li := 0 to 31 do
u_VoiceVolume (li,0) ;
end;
procedure _gus_player_continue;
{
Continue la sortie par l'interruption du timer.
}
var li : integer;
begin;
setintvec(8,@Mytimer);
for li := 1 to 31 do
Voice_Rampin(li,Canaux[li]^.volume);
end;
procedure timerint_rest;
{
Restaure l'interruption du timer en lui restituant ses valeurs initiales.
}
begin;
asm
cli
mov dx,43h
mov al,36h
out dx,al
xor ax,ax
mov dx,40h
out dx,al
out dx,al
end;
setintvec(8,ancientimer);
asm sti end;
end;
procedure dispose_mod;
{
Supprime un MOD chargé en mémoire principale. Les samples sur la GUS
ne sont PAS supprimés.
}
begin;
for i := 0 to 31 do begin;
U_StartVoice(i,Stop_Voice);
end;
for i := 1 to Vh.Num_Patts do begin;
dos_freemem(Pattern[i]);
end;
for i := 0 to 15 do begin;
dispose(Canaux[i]);
end;
for i := 0 to 31 do begin;
dispose(Instruments[i]);
end;
end;
procedure _gus_mod_quitter;
{
Met fin à la sortie d'un MOD
}
begin;
timerint_rest;
dispose_mod;
end;
procedure _gus_initialiser;
{
Initialise la GUS
}
begin;
u_init;
gus_speaker_on;
end;
procedure get_from_environment;
{
Extrait l'adresse de Base de la GUS à partir de la variable d'environment
ULTRASND
}
var apos,ipos,dpos : integer;
astr,istr,dstr,gusstr : string;
code : integer;
begin;
GUS_envstr := GetEnv('ULTRASND');
{ identifier GUS-Base }
gusstr := Copy(GUS_envstr,1,3);
val(gusstr,GUS_BASE,code);
if code <> 0 then begin;
GUS_Environment := false;
end else
GUS_Environment := true;
end;
function dec_2_hex(w : word) : word;
{
Conversion d'un nombre décimal en un nombre héxadécimal.
Important pour la prise en charge de l'environnement
}
const exp : array[1..4] of word = (4096,256,16,0);
var c,hs : string;
v,i,li : integer;
begin;
str(w,hs);
while length(hs) < 4 do hs := '0'+hs;
w := 0;
for li := 1 to 4 do begin;
c := hs[li];
val(c,v,i);
w := w + v * exp[li];
end;
dec_2_hex := w;
end;
procedure write_environment;
{
Renvoie l'adresse de BASE de la GUS provenant de l'environnement
}
begin;
if GUS_Environment then begin;
writeln('■ GUS_BASE: ',GUS_BASE);
writeln('■ initializing Gravis Ultrasound Card');
gus_base := dec_2_hex(gus_base);
init_the_gus(Gus_base);
delay(777);
end else begin;
writeln('The environment-variable ULTRASND is not set !');
delay(777);
end;
end;
function _gus_init_env : boolean;
{
Initialise la GUS, il n'y a pas une vérification de la configuration
matérielle mais une vérification de la variable d'environnement ULTRASND
}
begin;
clrscr;
get_from_environment;
write_environment;
_gus_init_env := gus_environment;
end;
begin;
end.