home *** CD-ROM | disk | FTP | other *** search
- {****************************************************************************}
- { }
- { MODULE: ModCommands }
- { }
- { DESCRIPTION: This UNIT implements the routines that interpret the }
- { various commands that appear in a MOD file`s partiture }
- { }
- { It's independent of the number of channels used. }
- { }
- { Designed for use from within the PlayMod UNIT. }
- { }
- { AUTHOR: Juan Carlos Arévalo }
- { }
- { MODIFICATIONS: Nobody (yet... ;-) }
- { }
- { HISTORY: 02-Jan-1993 Creation/definition. It used to be part of the }
- { PlayMod UNIT, but it was getting too big. }
- { }
- { (C) 1992 VangeliSTeam }
- {____________________________________________________________________________}
-
- UNIT ModCommands;
-
- INTERFACE
-
- USES SongUnit, SongElements;
-
-
-
-
- { Configuration. }
-
- CONST
- MyLoopMod : BOOLEAN = FALSE; { If TRUE, then the MOD will loop if it was so defined. }
- PermitFilterChange : BOOLEAN = FALSE; { TRUE if the partiture is allowed to change the filter. }
- BPMDivider : WORD = 125;
- BPMIncrement : WORD = 125;
- BPMCount : WORD = 0;
- MyFirstPattern : WORD = 0;
- MyRepStart : WORD = 0;
- MySongLen : WORD = 0;
- FirstPattern : WORD = 0;
- RepStart : WORD = 0;
- SongLen : WORD = 0;
-
-
-
-
- { Values common to all the channels. }
-
- CONST
- FilterIsOn : BOOLEAN = FALSE; { Position of the filter (FALSE = OFF). }
- Tempo : BYTE = 6; { Number of ticks in the current note. }
-
-
-
-
- { Values set from outside this UNIT, apart from this one. }
-
- CONST
- NextNote : WORD = 1; { Next note in the pattern. }
- NextSeq : WORD = 1; { Next pattern index (for the next note). }
- { They both must have been set BEFORE calling this UNIT. }
-
- TempoCt : BYTE = 0; { Number of the actual tick. Not changed in this UNIT. }
-
-
-
-
- { General definition of the state of a channel. }
-
- TYPE { Channel state definition. }
- PCanal = ^TCanal;
- TCanal = RECORD
- Note : TFullNote; { Note being played in the channel. }
- Instrument : PInstrumentRec; { Pointer to the instrument data. }
- Volume : BYTE; { Actual volume (0 - 64). }
- Period : WORD; { Actual Period. }
- RealPeriod : WORD; { Actual adjusted Period. }
-
- PeriodIncr, { Note portamento increment. }
- PeriodDest : INTEGER; { Note portamento destination. }
-
- arpct : BYTE; { Arpeggio count. }
- arp0, { Arpeggio 1st Period. }
- arp1, { Arpeggio 2nd Period. }
- arp2 : WORD; { Arpeggio 3rd Period. }
-
- VibWave, { Vibrato wave form. }
- VibPos, { Vibrato position. }
- VibWidth, { Vibrato width (period). }
- VibDepth : BYTE; { Vibrato depth (amplitude). }
- VibReset : BOOLEAN; { Vibrato reset. }
-
- TPortaIncr : INTEGER; { Tone portamento increment. }
- VolumeIncr : SHORTINT; { Volume increment. }
- TPortIsFine: BOOLEAN;
- VSldIsFine : BOOLEAN;
- END;
-
-
-
-
- PROCEDURE DoTickCommand;
- PROCEDURE CommandStart (VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
-
-
-
-
- IMPLEMENTATION
-
- USES SongUtils, SoundDevices;
-
-
-
- {----------------------------------------------------------------------------}
- { Rutinas de comandos, para el comienzo y cada Tick. }
- { }
- { En las del tick, se entra con SI apuntando al TCanal correspondiente. }
- {____________________________________________________________________________}
-
-
- { 0 xx }
-
- PROCEDURE StartArpeggio(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- VAR
- f, g: INTEGER;
- BEGIN
- can.arpct := 0;
-
- f := n.Period;
- IF f = 0 THEN f := can.Note.Period;
-
- can.arp0 := f;
- g := WORD((n.Parameter SHR 4));
- can.arp1 := PeriodArray[(NoteIdx[f] AND $FF) + g];
- g := WORD((n.Parameter AND $F));
- can.arp2 := PeriodArray[(NoteIdx[f] AND $FF) + g];
- END;
-
- PROCEDURE TickArpeggio; ASSEMBLER;
- ASM
-
- INC TCanal([SI]).arpct
- MOV AL,TCanal([SI]).arpct
- DEC AL
- JNZ @@2
- MOV AX,TCanal([SI]).arp0
- MOV TCanal([SI]).Period,AX
- JMP @@Fin
- @@2: DEC AL
- JNZ @@3
- MOV AX,TCanal([SI]).arp1
- MOV TCanal([SI]).Period,AX
- JMP @@Fin
- @@3: MOV AX,TCanal([SI]).arp2
- MOV TCanal([SI]).Period,AX
- MOV TCanal([SI]).arpct,0
- @@Fin:
- END;
-
-
- { 1 xx , 2 xx }
-
- PROCEDURE StartFinePortaUp (VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote); FORWARD;
-
- PROCEDURE StartFinePortaDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote); FORWARD;
-
- PROCEDURE StartTPortUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter <> 0 THEN
- BEGIN
- can.TPortaIncr := WORD(n.Parameter);
- can.TPortIsFine := FALSE;
- END
- ELSE IF can.TPortIsFine THEN
- BEGIN
- can.Note.Command := mcFinePortaUp;
- StartFinePortaUp(Song, can, n);
- END;
- END;
-
- PROCEDURE StartTPortDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter <> 0 THEN
- BEGIN
- can.TPortaIncr := WORD(n.Parameter);
- can.TPortIsFine := FALSE;
- END
- ELSE IF can.TPortIsFine THEN
- BEGIN
- can.Note.Command := mcFinePortaDn;
- StartFinePortaDown(Song, can, n);
- END;
- END;
-
- PROCEDURE TickTPortUp; ASSEMBLER;
- ASM
-
- MOV AX,TCanal([SI]).Note.Period
- SUB AX,TCanal([SI]).TPortaIncr
- MOV TCanal([SI]).Note.Period,AX
- MOV TCanal([SI]).Period,AX
-
- END;
-
-
- PROCEDURE TickTPortDown; ASSEMBLER;
- ASM
-
- MOV AX,TCanal([SI]).Note.Period
- ADD AX,TCanal([SI]).TPortaIncr
- MOV TCanal([SI]).Note.Period,AX
- MOV TCanal([SI]).Period,AX
-
- END;
-
-
- { 3 xy }
-
- PROCEDURE StartNPortamento(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Period <> 0 THEN
- can.PeriodDest := n.Period
- ELSE IF can.PeriodDest = 0 THEN
- can.PeriodDest := can.Period;
-
- IF n.Parameter = 0 THEN BEGIN
- IF can.PeriodIncr > 0 THEN n.Parameter := BYTE( can.PeriodIncr)
- ELSE n.Parameter := BYTE(-can.PeriodIncr);
- END;
-
- IF INTEGER(can.PeriodDest - can.Period) >= 0 THEN
- can.PeriodIncr := INTEGER(n.Parameter)
- ELSE
- can.PeriodIncr := -INTEGER(n.Parameter);
-
- can.Note.Period := can.Period;
- END;
-
- PROCEDURE TickNPortamento; ASSEMBLER;
- ASM
-
- MOV AX,TCanal([SI]).PeriodDest
- AND AX,AX
- JZ @@Fin
- MOV AX,TCanal([SI]).PeriodIncr
- AND AX,AX
- JZ @@Fin
- MOV BX,TCanal([SI]).Note.Period
- ADD BX,AX
- TEST AH,80h
- JNZ @@neg
- CMP BX,TCanal([SI]).PeriodDest
- JA @@pneg
- JMP @@cnt
- @@neg: TEST BH,80h
- JNZ @@pneg
- CMP BX,TCanal([SI]).PeriodDest
- JAE @@cnt
- @@pneg: MOV BX,TCanal([SI]).PeriodDest
- @@cnt: MOV TCanal([SI]).Note.Period,BX
- MOV TCanal([SI]).Period,BX
- @@Fin:
-
- END;
-
-
- { 4 xy }
-
- PROCEDURE StartVibrato(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- VAR
- f : WORD;
- BEGIN
- f := n.Parameter AND $F;
- IF f <> 0 THEN
- CASE can.VibWave OF
- 0: can.VibWidth := f;
- 1: can.VibWidth := f;
- 2: can.VibWidth := (f*255) SHR 7;
- END;
-
- f := n.Parameter SHR 4;
- IF f <> 0 THEN can.VibDepth := f SHL 2;
-
- IF (n.Period <> 0) AND can.VibReset THEN
- can.VibPos := 0;
- END;
-
- PROCEDURE TickVibrato; ASSEMBLER;
- CONST
- VibTabla : ARRAY[0..31] OF BYTE = ( { Sinus table for the vibrato. }
- 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
- );
- ASM
-
- MOV AH,TCanal([SI]).VibWave
- MOV DH,TCanal([SI]).VibWidth
- MOV DL,TCanal([SI]).VibPos
- MOV AL,DL
- AND AH,AH
- JNZ @@nosn
- SHR AL,2
- AND AL,1Fh
- MOV BX,OFFSET VibTabla
- XLAT
- JMP @@set
- @@nosn: DEC AH
- JNZ @@notr
- SHL AL,1
- JNC @@set
- NOT AL
- @@set: MUL DH
- SHL AX,1
- MOV AL,AH
- XOR AH,AH
- JMP @@calc
- @@notr: MOV AL,DH
- XOR AH,AH
- @@calc: MOV BX,TCanal([SI]).Note.Period
- TEST DL,80h
- JZ @@mas
- NEG AX
- @@mas: ADD BX,AX
- MOV TCanal([SI]).Period,BX
- ADD DL,TCanal([SI]).VibDepth
- MOV TCanal([SI]).VibPos,DL
-
- END;
-
-
- { 5 xy }
-
- PROCEDURE TickVolSlide; FORWARD;
-
- PROCEDURE TickT_VSlide; ASSEMBLER;
- ASM
-
- CALL TickNPortamento
- JMP TickVolSlide
-
- END;
-
-
- { 6 xy }
-
- PROCEDURE TickVib_VSlide; ASSEMBLER;
- ASM
-
- CALL TickVibrato
- JMP TickVolSlide
-
- END;
-
-
- { 7 xy }
-
- PROCEDURE TickTremolo; ASSEMBLER;
- ASM
- END;
-
-
- { 8 xx }
-
- PROCEDURE TickNPI1; ASSEMBLER;
- ASM
- END;
-
-
- { 9 xx }
-
- PROCEDURE TickSampleOffs; ASSEMBLER;
- ASM
- END;
-
-
- { A xy }
-
- PROCEDURE StartVolSlide(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter <> 0 THEN
- BEGIN
- can.VSldIsFine := FALSE;
- IF n.Parameter > $F THEN can.VolumeIncr := n.Parameter SHR 4
- ELSE can.VolumeIncr := -SHORTINT(n.Parameter AND $F);
- END
- ELSE
- BEGIN
- IF can.VSldIsFine THEN
- BEGIN
- can.VSldIsFine := FALSE;
- ASM
- MOV SI,WORD PTR can
- CALL TickVolSlide
- END;
- can.VSldIsFine := TRUE;
- END;
- END;
-
- END;
-
- PROCEDURE TickVolSlide; ASSEMBLER;
- ASM
-
- MOV AL,TCanal([SI]).VSldIsFine
- AND AL,AL
- JNZ @@Sale
-
- MOV AL,TCanal([SI]).Volume
- MOV AH,TCanal([SI]).VolumeIncr
- ADD AL,AH
- CMP AL,64
- JBE @@Fin
- XOR AL,AL
- TEST AH,80h
- JNZ @@Fin
- MOV AL,64
- @@Fin: MOV TCanal([SI]).Volume,AL
- @@Sale:
- END;
-
-
-
- { B xx }
-
- PROCEDURE StartJumpPattern(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- NextSeq := n.Parameter;
- IF NextSeq >= MySongLen THEN
- NextNote := $FFFF
- ELSE
- NextNote := 1;
- END;
-
-
- { C xx }
-
- PROCEDURE StartSetVolume(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter > 64 THEN n.Parameter := 64;
- can.Volume := n.Parameter;
- END;
-
-
- { D xx }
-
- PROCEDURE StartEndPattern(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF NextNote <> 1 THEN INC(NextSeq);
- IF NextSeq > MySongLen THEN
- NextNote := $FFFF
- ELSE BEGIN
- NextNote := (n.Parameter AND $0F) +
- (n.Parameter SHR 4)*10 + 1;
- END;
- IF NextNote <> $FFFF THEN NextNote := 1;
- END;
-
-
- { F xx }
-
- PROCEDURE StartSetTempo(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter > $30 THEN
- BPMIncrement := n.Parameter
- ELSE
- IF n.Parameter <> 0 THEN Tempo := n.Parameter;
- END;
-
-
- { E 0x }
-
- PROCEDURE StartSetFilter(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF PermitFilterChange THEN
- FilterIsOn := n.Parameter <> 0;
- END;
-
- PROCEDURE TickSetFilter; ASSEMBLER;
- ASM
- END;
-
-
- { E 1x , E 2x }
-
- PROCEDURE StartFinePortaUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter <> 0 THEN
- BEGIN
- can.TPortaIncr := WORD(n.Parameter);
- can.TPortIsFine := TRUE;
- END
- ELSE IF NOT can.TPortIsFine THEN
- BEGIN
- can.Note.Command := mcTPortUp;
- END;
-
- IF can.TPortIsFine THEN
- ASM
- MOV SI,WORD PTR [can]
- CALL TickTPortUp
- END;
- END;
-
- PROCEDURE StartFinePortaDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter <> 0 THEN
- BEGIN
- can.TPortaIncr := WORD(n.Parameter);
- can.TPortIsFine := TRUE;
- END
- ELSE IF NOT can.TPortIsFine THEN
- BEGIN
- can.Note.Command := mcTPortDown;
- END;
-
- IF can.TPortIsFine THEN
- ASM
- MOV SI,WORD PTR [can]
- CALL TickTPortDown
- END;
- END;
-
- PROCEDURE TickFPortUpDown; ASSEMBLER;
- ASM
- END;
-
-
- { E 3x }
-
- PROCEDURE TickGlissCtrl; ASSEMBLER;
- ASM
- END;
-
-
- { E 4x }
-
- PROCEDURE TickVibCtrl; ASSEMBLER;
- ASM
- END;
-
-
- { E 5x }
-
- PROCEDURE TickFineTune; ASSEMBLER;
- ASM
- END;
-
-
- { E 6x }
-
- PROCEDURE TickJumpLoop; ASSEMBLER;
- ASM
- END;
-
-
- { E 7x }
-
- PROCEDURE TickTremCtrl; ASSEMBLER;
- ASM
- END;
-
-
- { E 8x }
-
- PROCEDURE TickNPI2; ASSEMBLER;
- ASM
- END;
-
-
- { E 9x }
-
- PROCEDURE TickRetrigNote; ASSEMBLER;
- ASM
- END;
-
-
- { E Ax y E Bx }
-
- PROCEDURE StartVolFineUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter <> 0 THEN
- BEGIN
- can.VSldIsFine := TRUE;
- can.VolumeIncr := n.Parameter AND $F;
- END;
-
- IF can.VSldIsFine THEN
- BEGIN
- can.VSldIsFine := FALSE;
- ASM
- MOV SI,WORD PTR can
- CALL TickVolSlide
- END;
- can.VSldIsFine := TRUE;
- END;
- END;
-
- PROCEDURE StartVolFineDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- BEGIN
- IF n.Parameter <> 0 THEN
- BEGIN
- can.VSldIsFine := TRUE;
- can.VolumeIncr := -SHORTINT(n.Parameter AND $F);
- END;
-
- IF can.VSldIsFine THEN
- BEGIN
- can.VSldIsFine := FALSE;
- ASM
- MOV SI,WORD PTR can
- CALL TickVolSlide
- END;
- can.VSldIsFine := TRUE;
- END;
- END;
-
- PROCEDURE TickVolFineUpDn; ASSEMBLER;
- ASM
- JMP TickVolSlide
- END;
-
-
- { E Cx }
-
- PROCEDURE TickNoteCut; ASSEMBLER;
- ASM
- END;
-
-
- { E Dx }
-
- PROCEDURE TickNoteDelay; ASSEMBLER;
- ASM
- END;
-
-
- { E Ex }
-
- PROCEDURE TickPattDelay; ASSEMBLER;
- ASM
- END;
-
-
- { E Fx }
-
- PROCEDURE TickFunkIt; ASSEMBLER;
- ASM
- END;
-
-
- { 0 00 }
-
- PROCEDURE TickNone; ASSEMBLER;
- ASM
- END;
-
-
- PROCEDURE StartOktArp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- VAR
- f, g: INTEGER;
- BEGIN
- can.arpct := 0;
-
- f := n.Period;
- IF f = 0 THEN f := can.Note.Period;
-
- can.arp1 := f;
- g := WORD((n.Parameter SHR 4));
- can.arp0 := PeriodArray[(NoteIdx[f] AND $FF) - g];
- g := WORD((n.Parameter AND $F));
- can.arp2 := PeriodArray[(NoteIdx[f] AND $FF) + g];
- END;
-
-
-
- PROCEDURE TickArpeggio2; ASSEMBLER;
- ASM
-
- INC TCanal([SI]).arpct
- MOV AL,TCanal([SI]).arpct
- DEC AL
- JNZ @@2
- MOV AX,TCanal([SI]).arp1
- MOV TCanal([SI]).Period,AX
- JMP @@Fin
- @@2: DEC AL
- JNZ @@3
- MOV AX,TCanal([SI]).arp2
- MOV TCanal([SI]).Period,AX
- JMP @@Fin
- @@3: DEC AL
- JNZ @@4
- MOV AX,TCanal([SI]).arp1
- MOV TCanal([SI]).Period,AX
- JMP @@Fin
- @@4: MOV AX,TCanal([SI]).arp0
- MOV TCanal([SI]).Period,AX
- MOV TCanal([SI]).arpct,0
- @@Fin:
- END;
-
-
-
-
-
- CONST
- TickCommOfs : ARRAY[mcNone..mcLast] OF WORD = (
- OFS(TickNone), { 0 00 }
-
- OFS(TickArpeggio), { 0 xx }
- OFS(TickTPortUp), { 1 xx }
- OFS(TickTPortDown), { 2 xx }
- OFS(TickNPortamento),{ 3 xy }
- OFS(TickVibrato), { 4 xy }
- OFS(TickT_VSlide), { 5 xy }
- OFS(TickVib_VSlide), { 6 xy }
- OFS(TickTremolo), { 7 xy }
- OFS(TickNPI1), { 8 xx }
- OFS(TickSampleOffs), { 9 xx }
- OFS(TickVolSlide), { A xy }
- OFS(TickNone), { B xx }
- OFS(TickNone), { C xx }
- OFS(TickNone), { D xx }
- OFS(TickNone), { E xy }
- OFS(TickNone), { F xx }
-
- OFS(TickSetFilter), { E 0x }
- OFS(TickFPortUpDown),{ E 1x }
- OFS(TickFPortUpDown),{ E 2x }
- OFS(TickGlissCtrl), { E 3x }
- OFS(TickVibCtrl), { E 4x }
- OFS(TickFineTune), { E 5x }
- OFS(TickJumpLoop), { E 6x }
- OFS(TickTremCtrl), { E 7x }
- OFS(TickNPI2), { E 8x }
- OFS(TickRetrigNote), { E 9x }
- OFS(TickVolFineUpDn),{ E Ax }
- OFS(TickVolFineUpDn),{ E Bx }
- OFS(TickNoteCut), { E Cx }
- OFS(TickNoteDelay), { E Dx }
- OFS(TickPattDelay), { E Ex }
- OFS(TickFunkIt), { E Fx }
-
- OFS(TickArpeggio), { Okt }
- OFS(TickArpeggio2), { Okt }
-
- OFS(TickNone) { 0 00 }
-
- );
-
- PROCEDURE DoTickCommand; ASSEMBLER;
- ASM
-
- CMP BX,mcLast*2
- JNC @@1
- ADD BX,OFFSET TickCommOfs
- CALL WORD PTR [BX]
- @@1:
- END;
-
-
-
-
- PROCEDURE CommandStart(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
- CONST
- f : INTEGER = 0;
- g : INTEGER = 0;
- BEGIN
-
- IF (can.Note.Command = mcArpeggio) OR
- (((can.Note.Command = mcVibrato) OR
- (can.Note.Command = mcVib_VSlide)) AND
- (( n.Command <> mcVibrato) AND
- ( n.Command <> mcVib_VSlide))) THEN can.Period := can.Note.Period;
-
- IF (n.Period <> 0) THEN
- can.Note.Period := n.Period;
-
- can.Note.Command := n.Command;
- can.Note.Parameter := n.Parameter;
-
- CASE n.Command OF
- mcArpeggio: StartArpeggio (Song, can, n);
- mcTPortUp: StartTPortUp (Song, can, n);
- mcTPortDown: StartTPortDown (Song, can, n);
- mcNPortamento: StartNPortamento (Song, can, n);
- mcVibrato: StartVibrato (Song, can, n);
- mcJumpPattern: StartJumpPattern (Song, can, n);
- mcT_VSlide,
- mcVib_VSlide,
- mcVolSlide: StartVolSlide (Song, can, n);
- mcSetVolume: StartSetVolume (Song, can, n);
- mcEndPattern: StartEndPattern (Song, can, n);
- mcSetTempo: StartSetTempo (Song, can, n);
- mcSetFilter: StartSetFilter (Song, can, n);
- mcVolFineUp: StartVolFineUp (Song, can, n);
- mcVolFineDown: StartVolFineDown (Song, can, n);
- mcFinePortaUp: StartFinePortaUp (Song, can, n);
- mcFinePortaDn: StartFinePortaDown(Song, can, n);
- mcOktArp: StartOktArp (Song, can, n);
- mcOktArp2: StartOktArp (Song, can, n);
- END;
-
- IF (n.Period <> 0) AND (n.Command <> mcNPortamento) THEN
- can.Period := n.Period;
-
- END;
-
-
-
-
- END.
-