zpliku=1
; ORIGIN SOURCE CODE CAME FROM THE PROTRACKER V2.1A
;
;                        BY LARS "ZAP" HAMRE (AMIGA FREELANCERS)
;
; FEATURES: 4/8-CHANNEL-MODS (M.K./FLT4/FLT8/8CHN), MIXINGRATE 10000-22222 HZ
;
;           2/4-FX-CHANNELS, FULL MOD-FX SUPPORT EXCEPT FILTER & REVERSE FUNK
;
;           4 TIMES AMPLIFIED (2 BITS HIGHER QUALITY), LINEAR INTERPOLATION
;
;           STEREO FOR SBPRO&16, ONLY 15% (APPROX.) PERFORMANCE REDUCTION
;
;           656 KB EMS-MEMORY SUPPORT FOR FX
;
; MEMORY:   12K CODE, 8K MIXBUF, 16K VOLTABLE, 0-64K TRACKBUF, 0-???K SAMPLES
;
.ALPHA
.MODEL MEDIUM
COM_OR_OBJ      = 1
STACKLENGTH     = 0100H
UGROUP1 GROUP CODE_SEG1, DATA_SEG1
ASSUME CS:UGROUP1, DS:UGROUP1, SS:UGROUP1
;=============================================================================
MAX_CHAN_NUMB   = 8
IRQ1            = 20H
IRQ2            = 21H
IRQ3            =0A0H
IRQ4            =0A1H
TIMER0          = 40H
PIT1            = 43H
UHR_INDEX       = 70H
UHR_PORT        = 71H
UHR_STATA       = 0AH
UHR_STATB       = 0BH
UHR_STATC       = 0CH
;-----------------------------------------------------------------------------
DATA_SEG1 SEGMENT       para    public  WORD USE16
PROG_START_SEG  DW 0
PROG_END_SEG    DW 0
IF COM_OR_OBJ
VAR_BUFSEG      DW 0
ELSE
VAR_BUFSEG      DW 8000H
ENDIF

SYSTEM          DB 0
IRQCOUNT        DB 10;56
SBPRO_FLAG      DB 0            ;0=SB, 1= SBPRO
SB_VERSION      DB 1            ;SB=1.0,SBPRO=2.0-3.0,SB16=4.0+
SB_TYP          DB 1            ;0=NO SOUND, 1=SB, 2=SBPRO, 3=GUS, 4=AWE32?
SB_MODUS        DB 0            ;0=MUSIC&FX, 1=MUSIC, 2=FX, 3=NO_SOUND
CD_MIXER        DB 0            ;0=MODULES ONLY, 1=CD MIXED
IRQ_REENTER     DB 0
LOADMOD_FLAG    DB 0
PAN_FX          DB 0            ;FLIP SAMPLE CHANNEL
SAM_FLAG1       DB 0
SAM_FLAG2       DB 0
SAMPLE_RATE     DW 22222
SBP_MIXERI      DW 0224H
SBP_MIXERD      DW 0225H
SB_RESET        DW 0226H
SB_READ         DW 022AH
SB_WRITE        DW 022CH
SB_RSTAT        DW 022EH
IRQ_NUMBER      DB 7
DMA_CHANNEL     DB 1
DMA_RATE        DB 211
DMA_PAGE        DB 0
DMA_POFF        DW 0
DMA_DATA        DB 87H,83H,81H,82H
MAINFREQ        DD 41236
DMA_CX          DW 434
DMA_MORE        DW 434*4
DMA_MAX         DW 434*16
DMA_NEWPTR      DW 0
DMA_PTR         DW 0
DMA_SEG         DW 0
DMA_OFFSET      DW 0
MIXMUL_OFFSET   DW 0
COMP_SPEED2     DW 0106H
COMP_SPEED3     DW 4006H
COMP_SPEED4     DW 0
COMP_SPEED5     DW 1165
HOLD70  LABEL   DWORD
		DW OFFSET TIMER_HANDLER, 0
HOLDSB  LABEL   DWORD
		DW OFFSET SBIRQ_HANDLER, 0
STEREO_PANNING  DW 0,2,0,-2,0,2,0,-2,0
;-----------------------------------------------------------------------------
GDDLENGTH       DD 0
GDDREST         DW 0
GDDHANDLE       DW 0
GDDZEIG         DB 0
SONG_START      DB 0
;-----------------------------------------------------------------------------
; PLAYER - KONTROLLSTRUKTUREN
;-----------------------------------------------------------------------------
ALIGN 2
MUSIC_VOL       DB 255
MUSIC_VOLUME    DB 255
FX_VOL          DB 255
FX_VOLUME       DB 255
MASTER_VOLUME   DB 255
MOD_STAT        DB 0
BPM_RATE        DW 1024
BPM_VALUE       DW 125
BPM_COUNT       DD 0
BPM_SPEED       DD 0
CH_NUMB         DW 4
QUEUE_BUFFER    LABEL   WORD            ;256 BYTES
NOTE            DW MAX_CHAN_NUMB DUP(0)
CMD             DB MAX_CHAN_NUMB DUP(0)
CMDLO           DB MAX_CHAN_NUMB DUP(0)
START           DW MAX_CHAN_NUMB DUP(0)
LENGTHI         DW MAX_CHAN_NUMB DUP(0)
LOOPSTART       DW MAX_CHAN_NUMB DUP(0)
REPLEN          DW MAX_CHAN_NUMB DUP(0)
PERIOD          DW MAX_CHAN_NUMB DUP(0)
FINETUNE        DB MAX_CHAN_NUMB DUP(0)
VOLUME          DB MAX_CHAN_NUMB DUP(0)
TONEPORTDIREC   DB MAX_CHAN_NUMB DUP(1)
TONEPORTSPEED   DB MAX_CHAN_NUMB DUP(0)
WANTEDPERIOD    DW MAX_CHAN_NUMB DUP(0)
VIBRATOCMD      DB MAX_CHAN_NUMB DUP(0)
VIBRATOPOS      DB MAX_CHAN_NUMB DUP(0)
TREMOLOCMD      DB MAX_CHAN_NUMB DUP(0)
TREMOLOPOS      DB MAX_CHAN_NUMB DUP(0)
WAVECONTROL     DB MAX_CHAN_NUMB DUP(0)
GLISSFUNK       DB MAX_CHAN_NUMB DUP(0)
SAMPLEOFFSET    DB MAX_CHAN_NUMB DUP(0)
PATTPOS         DB MAX_CHAN_NUMB DUP(0)
LOOPCOUNT       DB MAX_CHAN_NUMB DUP(0)

MFREQ           DW MAX_CHAN_NUMB DUP(0)
MOFLOW          DB MAX_CHAN_NUMB DUP(0)
SONG_DATA       LABEL   BYTE            ;128 BYTES
MVOL            DB MAX_CHAN_NUMB DUP(0)
MSEG            DW MAX_CHAN_NUMB DUP(0)
MOFS            DW MAX_CHAN_NUMB DUP(0)
MREPEAT         DW MAX_CHAN_NUMB DUP(0)
MREPLEN         DW MAX_CHAN_NUMB DUP(0)
MMAXREP         DW MAX_CHAN_NUMB DUP(0)
MOD_NAME        DB 120 DUP(0)           ;MUSS MINDEST. 40 SEIN!
;-----------------------------------------------------------------------------
; Seg                           Stores the segment of the current sample.  If
;                               the segment is zero, then there is no sample
;                               begin played.
; Offset                        The current offset of the sample being played
;                               in the segment specified.
; MaxRep                        The offset of the place in the sample to
;                               repeat from (i.e. the end of the sample).
; Freq                          The frequency to be played out the output
;                               device.  It is actually a playback period,
;                               the upper byte determining the number of
;                               bytes to be added to the sample offset each
;                               interrupt, and the lower byte to be added
;                               over and over to generate carry flags to be
;                               added to additional offsets.
; Vol                           The actual volume to multiply the frequency
;                               by.
; Repeat                        The place to repeat from when the end of the
;                               loop is found.
; RepLen                        The number of bytes from Repeat to go to.
;                               When the end of this is found, it goes back
;                               to Repeat.
; OFlow                         The overflow variable used to generate the
;                               carry flags.
;-----------------------------------------------------------------------------
; PROTRACKER VARIABLEN
;-----------------------------------------------------------------------------
ALIGN 2
MT_SPEED                DB 6
MT_COUNTER              DB 0
MT_PATTERNPOS           DW 0
MT_SONGPOS              DB 0
MT_PATTDELAYTIME2       DB 0
MT_PATTDELAYTIME        DB 0
MT_PBREAKFLAG           DB 0
MT_PBREAKPOS            DB 0
MT_POSJUMPFLAG          DB 0
MT_LOWMASK              DB 0FFH

ALIGN 2
Effect_Jump_Table1      LABEL   WORD
DW OFFSET Go_Arpeggio, OFFSET Go_PortaUp, OFFSET Go_PortaDown
DW OFFSET Go_TonePortamento, OFFSET Go_vibrato, OFFSET Go_TonePlusVolSlide
DW OFFSET Go_VibratoPlusVolSlide, OFFSET Go_Tremolo, OFFSET Go_Return
DW OFFSET Go_Return, OFFSET Go_VolumeSlide, OFFSET Go_Return, OFFSET Go_Return
DW OFFSET Go_Return, OFFSET Go_E_Commands, OFFSET Go_Return

Effect_Jump_Table2      LABEL   WORD
DW OFFSET Go_PerNop, OFFSET Go_PerNop, OFFSET Go_PerNop
DW OFFSET Go_PerNop, OFFSET Go_PerNop, OFFSET Go_PerNop
DW OFFSET Go_PerNop, OFFSET Go_PerNop, OFFSET Go_PerNop
DW OFFSET Go_SampleOffset, OFFSET Go_PerNop, OFFSET Go_PositionJump
DW OFFSET Go_VolumeChange, OFFSET Go_PatternBreak
DW OFFSET Go_E_Commands, OFFSET Go_SetSpeed

Effect_Jump_Table3      LABEL   WORD
DW OFFSET Go_Return, OFFSET Go_FinePortaUp, OFFSET Go_FinePortaDown
DW OFFSET Go_SetGlissControl, OFFSET Go_SetVibratoControl
DW OFFSET Go_SeTFineTune, OFFSET Go_JumpLoop, OFFSET Go_SetTremoloControl
DW OFFSET Go_Return, OFFSET Go_RetrigNote, OFFSET Go_VolumeFineUp
DW OFFSET Go_VolumeFineDown, OFFSET Go_NoteCut, OFFSET Go_NoteDelay
DW OFFSET Go_PatternDelay, OFFSET Go_Return

ALIGN 2
MT_VIBRATOTABLE         DB   0, 24, 49, 74, 97,120,141,161
			DB 180,197,212,224,235,244,250,253
			DB 255,253,250,244,235,224,212,197
			DB 180,161,141,120, 97, 74, 49, 24

ALIGN 2
MT_PERIODTABLE  LABEL   WORD
DW 856,808,762,720,678,640,604,570,538,508,480,453 ;C-1 to H-1 Finetune +0.
DW 428,404,381,360,339,320,302,285,269,254,240,226 ;C-2 to H-2 Finetune +0.
DW 214,202,190,180,170,160,151,143,135,127,120,113 ;C-3 to H-3 Finetune +0.
DW 107,101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56 ;C-4 to H-4 Finetune +0.

DW 850,802,757,715,674,637,601,567,535,505,477,450 ;C-1 to H-1 Finetune +1.
DW 425,401,379,357,337,318,300,284,268,253,239,225 ;C-2 to H-2 Finetune +1.
DW 213,201,189,179,169,159,150,142,134,126,119,113 ;C-3 to H-3 Finetune +1.
DW 106,100, 94, 89, 84, 79, 75, 71, 67, 83, 59, 56 ;C-4 to H-4 Finetune +1.

DW 844,796,752,709,670,632,597,563,532,502,474,447 ;C-1 to H-1 Finetune +2.
DW 422,398,376,355,335,316,298,282,266,251,237,224 ;C-2 to H-2 Finetune +2.
DW 211,199,188,177,167,158,149,141,133,125,118,112 ;C-3 to H-3 Finetune +2.
DW 105, 99, 94, 88, 83, 79, 74, 70, 66, 62, 59, 56 ;C-4 to H-4 Finetune +2.

DW 838,791,746,704,665,628,592,559,528,498,470,444 ;C-1 to H-1 Finetune +3.
DW 419,395,373,352,332,314,296,280,264,249,235,222 ;C-2 to H-2 Finetune +3.
DW 209,198,187,176,166,157,148,140,132,125,118,111 ;C-3 to H-3 Finetune +3.
DW 104, 99, 93, 88, 83, 78, 74, 70, 66, 62, 59, 55 ;C-4 to H-4 Finetune +3.

DW 832,785,741,699,660,623,588,555,524,495,467,441 ;C-1 to H-1 Finetune +4.
DW 416,392,370,350,330,312,294,278,262,247,233,220 ;C-2 to H-2 Finetune +4.
DW 208,196,185,175,165,156,147,139,131,124,117,110 ;C-3 to H-3 Finetune +4.
DW 104, 98, 92, 87, 82, 78, 73, 69, 65, 62, 58, 55 ;C-4 to H-4 Finetune +4.

DW 826,779,736,694,655,619,584,551,520,491,463,437 ;C-1 to H-1 Finetune +5.
DW 413,390,368,347,328,309,292,276,260,245,232,219 ;C-2 to H-2 Finetune +5.
DW 206,195,184,174,164,155,146,138,130,123,116,109 ;C-3 to H-3 Finetune +5.
DW 103, 97, 92, 87, 82, 77, 73, 69, 65, 61, 58, 54 ;C-4 to H-4 Finetune +5.

DW 820,774,730,689,651,614,580,547,516,487,460,434 ;C-1 to H-1 Finetune +6.
DW 410,387,365,345,325,307,290,274,258,244,230,217 ;C-2 to H-2 Finetune +6.
DW 205,193,183,172,163,154,145,137,129,122,115,109 ;C-3 to H-3 Finetune +6.
DW 102, 96, 91, 86, 81, 77, 72, 68, 64, 61, 57, 54 ;C-4 to H-4 Finetune +6.

DW 814,768,725,684,646,610,575,543,513,484,457,431 ;C-1 to H-1 Finetune +7.
DW 407,384,363,342,323,305,288,272,256,242,228,216 ;C-2 to H-2 Finetune +7.
DW 204,192,181,171,161,152,144,136,128,121,114,108 ;C-3 to H-3 Finetune +7.
DW 102, 96, 90, 85, 80, 76, 72, 68, 64, 60, 57, 54 ;C-4 to H-4 Finetune +7.

DW 907,856,808,762,720,678,640,604,570,538,504,480 ;C-1 to H-1 Finetune -8.
DW 453,428,404,381,360,339,320,302,285,269,254,240 ;C-2 to H-2 Finetune -8.
DW 226,214,202,190,180,170,160,151,143,135,127,120 ;C-3 to H-3 Finetune -8.
DW 113,107,101, 95, 90, 85, 80, 75, 71, 67, 63, 60 ;C-4 to H-4 Finetune -8.

DW 900,850,802,757,715,675,636,601,567,535,505,477 ;C-1 to H-1 Finetune -7.
DW 450,425,401,379,357,337,318,300,284,268,253,238 ;C-2 to H-2 Finetune -7.
DW 225,212,200,189,179,169,159,150,142,134,126,119 ;C-3 to H-3 Finetune -7.
DW 112,106,100, 94, 89, 84, 79, 75, 71, 67, 63, 59 ;C-4 to H-4 Finetune -7.

DW 894,844,796,752,709,670,632,597,563,532,502,474 ;C-1 to H-1 Finetune -6.
DW 447,422,398,376,355,335,316,298,282,266,251,237 ;C-2 to H-2 Finetune -6.
DW 223,211,199,188,177,167,158,149,141,133,125,118 ;C-3 to H-3 Finetune -6.
DW 111,105, 99, 94, 88, 83, 79, 74, 70, 66, 62, 59 ;C-4 to H-4 Finetune -6.

DW 887,838,791,746,704,665,628,592,559,528,498,470 ;C-1 to H-1 Finetune -5.
DW 444,419,395,373,352,332,314,296,280,264,249,235 ;C-2 to H-2 Finetune -5.
DW 222,209,198,187,176,166,157,148,140,132,125,118 ;C-3 to H-3 Finetune -5.
DW 111,104, 99, 93, 88, 83, 78, 74, 70, 66, 62, 59 ;C-4 to H-4 Finetune -5.

DW 881,832,785,741,699,660,623,588,555,524,494,467 ;C-1 to H-1 Finetune -4.
DW 441,416,392,370,350,330,312,294,278,262,247,233 ;C-2 to H-2 Finetune -4.
DW 220,208,196,185,175,165,156,147,139,131,123,117 ;C-3 to H-3 Finetune -4.
DW 110,104, 98, 92, 87, 82, 78, 73, 69, 65, 61, 58 ;C-4 to H-4 Finetune -4.

DW 875,826,779,736,694,655,619,584,551,520,491,463 ;C-1 to H-1 Finetune -3.
DW 437,413,390,368,347,338,309,292,276,260,245,232 ;C-2 to H-2 Finetune -3.
DW 219,206,195,184,174,164,155,146,138,130,123,116 ;C-3 to H-3 Finetune -3.
DW 109,103, 97, 92, 87, 82, 77, 73, 69, 65, 61, 58 ;C-4 to H-4 Finetune -3.

DW 868,820,774,730,689,651,614,580,547,516,487,460 ;C-1 to H-1 Finetune -2.
DW 434,410,387,365,345,325,307,290,274,258,244,230 ;C-2 to H-2 Finetune -2.
DW 217,205,193,183,172,163,154,145,137,129,122,115 ;C-3 to H-3 Finetune -2.
DW 108,102, 96, 91, 86, 81, 77, 72, 68, 64, 61, 57 ;C-4 to H-4 Finetune -2.

DW 862,814,768,725,684,646,610,575,543,513,484,457 ;C-1 to H-1 Finetune -1.
DW 431,407,384,363,342,323,305,288,272,256,242,228 ;C-2 to H-2 Finetune -1.
DW 216,203,192,181,171,161,152,144,136,128,121,114 ;C-3 to H-3 Finetune -1.
DW 108,101, 96, 90, 85, 80, 76, 72, 68, 64, 60, 57 ;C-4 to H-4 Finetune -1.
;-----------------------------------------------------------------------------
; MTM - TRACKSTRUKTUR
;-----------------------------------------------------------------------------
ALIGN 2
TRACK_NUMBER    DW 0
TRACK_INFO      DB 8 DUP(0)
TRACK_SEG       DW 0
TRACKS_OFFSET   DW OFFSET TRACK1_DATA, OFFSET TRACK2_DATA, OFFSET TRACK3_DATA
		DW OFFSET TRACK4_DATA, OFFSET TRACK5_DATA, OFFSET TRACK6_DATA
		DW OFFSET TRACK7_DATA, OFFSET TRACK8_DATA
TRACK1_DATA     DB 128 DUP(0)
TRACK2_DATA     DB 128 DUP(0)
TRACK3_DATA     DB 128 DUP(0)
TRACK4_DATA     DB 128 DUP(0)
TRACK5_DATA     DB 128 DUP(0)
TRACK6_DATA     DB 128 DUP(0)
TRACK7_DATA     DB 128 DUP(0)
TRACK8_DATA     DB 128 DUP(0)
;-----------------------------------------------------------------------------
; MOD - DATEISTRUKTUR
;-----------------------------------------------------------------------------
ALIGN 2
SAMPLE_SIZE     DW 0
PATTERN_SIZE    DW 0
PATTERN_SEG     DW 0
PATTERN_NUMBER  DW 0
PATTERN_CURRENT DW 0
ISIZE           DW 31 DUP(0)
IVOL_FINETUNE   DW 31 DUP(0)
ILOOP_START     DW 31 DUP(0)
ILOOP_SIZE      DW 31 DUP(0)
SONG_SIZE       DB 0
SONG_LOOP       DB 0
MOD_SIGN        DD 0
SAMPLE_SEG      DW 31 DUP(0)
;-----------------------------------------------------------------------------
; SINGLE SAMPLE VARIABLES
;-----------------------------------------------------------------------------
SAMPLE_ZEIG     DW 0
SAMPLE_MEM      DW 64 DUP(0)
SAMPLE_BIG      DW 64 DUP(0)
EMS_SEG         DW 0
EMS_OFFSET      DW 0
EMS_HANDLE      DW 0
SAM_SEG1        DW 0
SAM_SEG2        DW 0
SAM_SEG3        DW 0
SAM_SEG4        DW 0
SAM_OFS1        DD 0
SAM_OFS2        DD 0
SAM_OFS3        DD 0
SAM_OFS4        DD 0
SAM_FRQ1        DW 0
SAM_FRQ2        DW 0
SAM_FRQ3        DW 0
SAM_FRQ4        DW 0
SAM_OFL1        DB 0
SAM_OFL2        DB 0
SAM_OFL3        DB 0
SAM_OFL4        DB 0
SAM_MAX1        DW 0
SAM_MAX2        DW 0
SAM_MAX3        DW 0
SAM_MAX4        DW 0
;-----------------------------------------------------------------------------
PROG_END        LABEL   BYTE    ;MUSS LETZE ZEILE IM DATENSEGMENT SEIN!
;-----------------------------------------------------------------------------
DATA_SEG1 ENDS

.386
CODE_SEG1 SEGMENT       para    public  PAGE USE16
ORG 100H

;=============================================================================
;comment #
PUBLIC  CONFIGINIT              ;0104
PUBLIC  LOADMODSB                       ;0108
PUBLIC  PLAYMUSIC               ;010C
PUBLIC  STOPMUSIC               ;0110
PUBLIC  ENDMUSIC                ;0114
;PUBLIC SETSAMPLERATE           ;0124
;PUBLIC GETVOLUME               ;0128
PUBLIC  SETVOLUME               ;012C
;PUBLIC SETSONGLOOP             ;0130
PUBLIC GETSONGPOSITION         ;0134
;PUBLIC SETSONGPOSITION         ;0138
;PUBLIC GETSONGMOD              ;013C
;PUBLIC SETSONGMOD              ;0140
PUBLIC  DSPOFF                  ;0144
PUBLIC  DSPRESET                ;0148
;PUBLIC	adr_wlk

;#
;=============================================================================
PUBLIC _MAIN1
_MAIN1 PROC FAR
        nop
        nop
        nop
	RETF
CONFIGINIT      :       ;0104
	CALL    CONFIG_INIT             ;0104
	RETF
LOADMODsb               :;0108
	CALL    LOAD_MOD                ;0108
	RETF
PLAYMUSIC       :       ;010C
	CALL    PLAY_MUSIC              ;010C
	RETF
STOPMUSIC       :       ;0110
	CALL    STOP_MUSIC              ;0110
	RETF
ENDMUSIC        :       ;0114
	CALL    END_MUSIC               ;0114
	RETF
GetSongPosition:	;24d
	call	Get_songPOsition
	retf
SETSAMPLERATE   :       ;0124
Comment #
	CALL    SET_SAMPLERATE          ;0124
	RETF
GETVOLUME       :       ;0128
	CALL    GET_VOLUME              ;0128
	RETF
#
SETVOLUME       :       ;012C
	CALL    SET_VOLUME              ;012C
	RETF
SETSONGLOOP     :       ;0130
comment #
	CALL    SET_SONGLOOP            ;0130
	RETF
#
comment #
SETSONGPOSITION :;0138
	CALL    SET_SONGPOSITION        ;0138
	RETF
GETSONGMOD      :       ;013C
	CALL    GET_SONGMOD             ;013C
	RETF
SETSONGMOD      :       ;0140
	CALL    SET_SONGMOD             ;0140
	RETF
#
DSPOFF          :       ;0144
	CALL    DSP_OFF                 ;0144
	RETF
DSPRESET:               ;0148
	CALL    DSP_RESET               ;0148
	RETF
_MAIN1 ENDP


;adr_wlk		dw SEG 	  Mt_PatternPos
;			dw offset Mt_PatternPos

;=============================================================================
;
; MOD ROUTINEN
;
;=============================================================================
; Format of a note: (ORIGINALLY MOD)
;
;                   0 0          0 0          0 0           0 0
;                   | |          | |          | |           | |
;                  /   \        / /          /   \           \ \
;         MSB of Ins.     Note        LSB Ins.  Spec. Com.   Data for special
;
; Format of a note: (MODIFIED BY LOADER)
;
;                   0 0          0 0          0 0           0 0
;                   | |          | |          | |           | |
;                  / /          /   \         \ \           \ \
;            LSB NOTE   SPEC.COM.    MSB NOTE  INSTRUMENT    DATA FOR SPECIAL
;
;ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¸
;³ DESCRIPTION: This procedure shouldn't need to be called by anything else  ³
;³              but the interrupt (ever).  It handles all note updating,     ³
;³              special effects, pointers, etc.                              ³
;³                                                                           ³
;³              *** This code came directly from the Amiga Protracker        ³
;³                  playback code, written by Lars "Zap" Hamre.  Give this   ³
;³                  guy a pat on the back for such excellent code.           ³
;³                                                                           ³
;³ BUGS       : Or rather, non-implementations.  Command EF - Funk it is     ³
;³              not all the way implemented.  Command E0 - Filter is not     ³
;³              implemented at all.  It is Amiga-specific, directly with     ³
;³              the Paula chip.                                              ³
;³                                                                           ³
;³ IMPROVEMENTS:    Optimized code for PC-architecure by the Frontman        ³
;³                                                                           ³
;ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¾
CONTROL_CHANNELS PROC NEAR
	CMP     LOADMOD_FLAG,0
	JNE     Go_NoNewPosYet
	CMP     MOD_STAT,3
	JAE     Go_NoNewPosYet
	INC     MT_COUNTER
	MOV     AL,MT_COUNTER
	CMP     AL,MT_SPEED             ; Does it match the current speed?
	JB      SHORT Go_NoNewNote      ; No, just do fx.
	MOV     MT_COUNTER,0
	CMP     MT_PATTDELAYTIME2,0
	JE      SHORT Go_GetNewNote
	CALL    Go_CheckEfx             ; Otherwise, just do fx only.
	JMP     Go_Dskip                ; Then, jump to update block values.
Go_NoNewNote:
	CALL    Go_CheckEfx             ; Do fx.
	JMP     Go_NoNewPosYet          ; We don't update block values
					; when we are just doing fx.
Go_GetNewNote:
	MOV     ES,TRACK_SEG
	XOR     SI,SI
Go_PlayVoice:
	PUSH    SI
	MOV     DI,SI
	SHL     DI,1
	MOVZX   BX,MT_SONGPOS           ; BLOCK BEGINNING TO ES:BX
	ADD     BX,[TRACKS_OFFSET+DI]
	MOVZX   BX,[BX]
	XCHG    BL,BH                   ; MULTIPLY WITH 256 (TRACK-SIZE)
	ADD     BX,MT_PATTERNPOS
	CMP     [NOTE+DI],0             ; See if there is a note.
	JNE     SHORT Go_plvskip        ; No, go on.
	CMP     [CMD+SI],0
	JNE     SHORT Go_plvskip
	CMP     [CMDLO+SI],0
	JNE     SHORT Go_plvskip
	CALL    Go_PerNop               ; Otherwise, figure out the frequency.
Go_plvskip:
	MOV     AX,ES:[BX]              ; Load this channel's information
	MOV     [NOTE+DI],AX            ; from the actual track block and
	AND     [NOTE+DI],0FFFH
	SHR     AH,4                    ; into our own internal structure
	MOV     [CMD+SI],AH             ; to access it from.
	MOV     AX,ES:[BX+2]
	MOV     [CMDLO+SI],AH
	OR      AL,AL                   ; Instrument byte.  Is there an ins?
	JZ      SHORT Go_SetRegs
	DEC     AL
	MOVZX   BX,AL                   ; GET SAMPLE SEGMENT
	SHL     BX,1
	MOV     AX,[SAMPLE_SEG+BX]
	MOV     [START+DI],AX           ; Store it in our structure.
	MOV     AX,[ISIZE+BX]           ; Get the length.
	MOV     [LENGTHI+DI],AX         ; Store it appropriately.
	MOV     AX,[IVOL_FINETUNE+BX]   ; Get the instrument volume and fine tune.
	MOV     [VOLUME+SI],AL          ; Store it appropriately.
	MOV     [FINETUNE+SI],AH
	MOV     [MVOL+SI],AL
	MOV     CX,[ILOOP_SIZE+BX]      ; Get Repeat length
	CMP     CX,8                    ; If the length is less than four,
	JB      SHORT Go_NoLoop         ; then there is no loop.
	MOV     AX,[ILOOP_START+BX]     ; Get the Repeat start.
	MOV     [MREPEAT+DI],AX         ; Move it into the appropriate
	MOV     [LOOPSTART+DI],AX       ; structures and locations.
	MOV     [REPLEN+DI],CX          ; Move the length into its storage.
	ADD     AX,CX                   ; We're figuring out the offset of
	MOV     [MREPLEN+DI],AX
	MOV     [MMAXREP+DI],AX         ; where the repeat length breaks.
	JMP     SHORT Go_SetRegs        ; Skip the no loop part.
Go_NoLoop:
	XOR     AX,AX                   ; Zero out AX.
	MOV     [REPLEN+DI],AX
	MOV     [MREPLEN+DI],AX         ; Make sure that no loop exists and
	MOV     [MREPEAT+DI],AX
	MOV     [LOOPSTART+DI],AX
Go_SetRegs:
	CMP     [NOTE+DI],0             ; Grab the note.
	JE      Go_CheckMore            ; Check the fx.
	MOV     AH,[CMD+SI]             ; Get the special fx command.
	MOV     AL,[CMDLO+SI]
	AND     AL,0F0H                 ; Mask out the bits we don't want.
	CMP     AX,0E50H                ; Is there a fine tune command
	JE      SHORT Go_DoSetFineTune
	CMP     AH,3                    ; Is it a tone portamento?
	JE      SHORT Go_ChkTonePorta
	CMP     AH,5                    ; Is it a tone and volume slide?
	JE      SHORT Go_ChkTonePorta
	CMP     AH,9                    ; Is it a sample offset command?
	JNE     SHORT Go_SetPeriod      ; If not, go do the actual note.
	PUSH    AX                      ; keep the command byte in mem
	CALL    Go_CheckMoreEfx
	POP     AX
	JMP     SHORT Go_SetPeriod      ; Go do the actual note.
Go_ChkTonePorta:
	CALL    Go_SetTonePorta         ; Do part of the tone portamento.
	JMP     Go_CheckMore            ; Go do the fx.
Go_DoSetFineTune:
	PUSH    AX
	MOV     AL,[CMDLO+SI]
	AND     AL,0FH
	CALL    Go_SetFineTune          ; Update the fine tune.
	POP     AX
;-----------------------------------------------------------------------------
; ÄÄÄÄ We are now going to find the note in the period table.  If it
; ÄÄÄÄ doesn't exist, then no fine tuning can be performed.  If it
; ÄÄÄÄ does, and fine tuning is specified, then we can update it.
;-----------------------------------------------------------------------------
Go_SetPeriod:
	MOV     CL,AH
	MOV     AX,[NOTE+DI]            ; Get the note.
	DEC     AX
	MOV     BX,OFFSET MT_PERIODTABLE; Set pointer to beginning of table.
	CMP     CL,3
	JE      SHORT Seek_Period
	CMP     CL,5
	JNE     SHORT Go_ftufound
Seek_Period:
	INC     AX
	MOV     CX,36+12                ; 36 periods to cycle through.
Go_ftuloop:
	CMP     AX,[BX]                 ; Check the note against the period.
	JAE     SHORT Go_Wizzyfound     ; We found it!
	INC     BX
	INC     BX                      ; Otherwise, update the pointer and
	LOOP    Go_ftuloop              ; keep looping.
	JMP     SHORT Go_Wizzyfound
Go_ftufound:
	ADD     BX,AX
Go_WizzyFound:
	MOV     AL,[FINETUNE+SI]        ; Get the fine tune.
	MOV     CL,(36+12)*2            ; The period table's size is 72.
	MUL     CL                      ; Multiply it by the fine tune.
	ADD     BX,AX                   ; Add it onto the pointer to point to
	MOV     AX,[BX]                 ; the new period and get it.
	MOV     [PERIOD+DI],AX          ; Store it.
	MOV     AH,[CMD+SI]             ; Get the special fx command.
	MOV     AL,[CMDLO+SI]
	AND     AL,0F0H                 ; Mask out the bits we don't want.
	CMP     AX,0ED0H
	JE      SHORT Go_delnoc
	MOV     AL,[WAVECONTROL+SI]     ; Get the WaveControl.
	TEST    AL,00000100B            ; Amiga: BTST #2,WaveControl.
	JZ      SHORT Go_vibnoc         ; If it is zero, then skip.
	MOV     [VIBRATOPOS+SI],0
Go_vibnoc:
	TEST    AL,01000000B            ; Amiga: BTST #6,WaveControl
	JZ      SHORT Go_trenoc         ; If it is zero, then skip.
	MOV     [TREMOLOPOS+SI],0       ; Zero the Tremolo offset.
Go_trenoc:
	MOV     AX,[START+DI]           ; Get the start segment.
	MOV     [MSEG+DI],AX            ; Store it to be updated.
	MOV     [MOFS+DI],0             ; Set the offset to zero.
	MOV     [MOFLOW+SI],0
	MOV     AX,[LENGTHI+DI]
	MOV     [MMAXREP+DI],AX         ; Store in MaxRepeat
	MOV     CX,[PERIOD+DI]
	CALL    Go_PerNop2
	JMP     SHORT Go_CheckMore
Go_delnoc:
	MOV     AX,[MMAXREP+DI]
	MOV     [MOFS+DI],AX
Go_CheckMore:
	CALL    Go_CheckMoreEfx
Go_DoNext:
	POP     SI                      ;SKIP TO NEXT CHANNEL
	INC     SI
	CMP     SI,CH_NUMB
	JB      Go_PlayVoice
;-----------------------------------------------------------------------------
Go_Dskip:
	ADD     MT_PATTERNPOS,4         ; Increment position by one
	MOV     AL,MT_PATTDELAYTIME
	OR      AL,AL
	JZ      SHORT Go_dskc
	MOV     MT_PATTDELAYTIME2,AL
	MOV     MT_PATTDELAYTIME,0
Go_dskc:
	CMP     MT_PATTDELAYTIME2,0
	JE      SHORT Go_dska
	DEC     MT_PATTDELAYTIME2
	JZ      SHORT Go_dska
	SUB     MT_PATTERNPOS,4
Go_dska:
	CMP     MT_PBREAKFLAG,0
	JE      SHORT Go_nnpysk
	MOV     MT_PBREAKFLAG,0
	MOVZX   AX,MT_PBREAKPOS
	MOV     MT_PBREAKPOS,AH
	SHL     AX,2
	MOV     MT_PATTERNPOS,AX
Go_nnpysk:
	CMP     MT_PATTERNPOS,256
	JB      SHORT Go_NoNewPosYet
Go_NextPosition:
	MOVZX   AX,MT_PBREAKPOS
	SHL     AX,2
	MOV     MT_PATTERNPOS,AX
	MOV     MT_PBREAKPOS,0
	MOV     MT_POSJUMPFLAG,0
	MOV     AL,MT_SONGPOS
	INC     AL
	AND     AL,7FH
	MOV     MT_SONGPOS,AL
	CMP     AL,SONG_SIZE
	JB      SHORT Go_NoNewPosYet
	MOV     AL,SONG_LOOP
	CMP     AL,SONG_SIZE
	JB      SHORT Go_NoSongRestart
	MOV     MOD_STAT,3
	XOR     AL,AL
Go_NoSongRestart:
	MOV     MT_SONGPOS,AL
	MOV     MT_SPEED,6              ;DEFAULT PROTRACKER SPEED
	MOV     MT_COUNTER,0            ;RESET PROTRACKER VARIABLES
	MOV     AL,125
	CALL    Go_SetBPM
	MOV     BPM_COUNT,0
Go_NoNewPosYet:
	CMP     MT_POSJUMPFLAG,0
	JNE     Go_NextPosition
	RET
CONTROL_CHANNELS ENDP
;=============================================================================
Go_CheckEfx PROC NEAR
	XOR     SI,SI
Go_DoEfx:
	PUSH    SI
	MOV     DI,SI
	SHL     DI,1
	MOV     BL,[CMD+SI]              ; Get the special command
	MOV     BH,[CMDLO+SI]
	OR      BX,BX
	JNZ     SHORT SetBack1
	CALL    Go_PerNop
	JMP     SHORT SetBack2
SetBack1:
	XOR     BH,BH
	SHL     BX,1
	CALL    [Effect_Jump_Table1+BX]
SetBack2:
	POP     SI
	INC     SI
	CMP     SI,CH_NUMB
	JB      Go_DoEfx
Go_Return:
	RET
;-----------------------------------------------------------------------------
Go_PerNop PROC NEAR
	MOV     CX,[PERIOD+DI]
Go_PerNop2 PROC NEAR
	XOR     AX,AX
	JCXZ    SHORT Go_DivZero
	MOV     AX,WORD PTR MAINFREQ
	MOV     DX,WORD PTR MAINFREQ+2
	DIV     CX
Go_DivZero:
	MOV     [MFREQ+DI],AX
	RET
Go_PerNop2 ENDP
Go_PerNop ENDP
Go_CheckEfx ENDP
;=============================================================================
;
; SI IS THE CHANNEL-BYTE-INDEX, DI IS THE CHANNEL-WORD-INDEX
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 0 -- Arpeggio
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_Arpeggio PROC NEAR
	MOVZX   AX,MT_COUNTER
	MOV     BL,3
	MOV     CX,[PERIOD+DI]
	DIV     BL
	OR      AH,AH
	JZ      SHORT Go_Arpeggio1
	MOV     AL,[CMDLO+SI]
	CMP     AH,2
	JE      SHORT Go_Arpeggio2
	SHR     AL,4
Go_Arpeggio2:
	AND     AL,0FH
	SHL     AL,1
	MOVZX   BX,AL
	MOV     AL,[FINETUNE+SI]
	MOV     DX,CX
	MOV     CL,(36+12)*2
	MUL     CL
	PUSH    DI
	MOV     DI,OFFSET MT_PERIODTABLE
	ADD     DI,AX
	MOV     AH,36+12
Go_arploop:
	MOV     CX,[BX+DI]
	CMP     DX,[DI]
	JAE     SHORT Go_arpafterloop
	INC     DI
	INC     DI
	DEC     AH
	JNZ     Go_arploop
	POP     DI
	RET
Go_arpafterloop:
	POP     DI
Go_Arpeggio1:
	CALL    Go_PerNop2
	RET
Go_Arpeggio ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 1 -- Portamento Up
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_PortaUp PROC NEAR
	MOVZX   AX,[CMDLO+SI]           ; Number to slide up (was lo)
	AND     AL,MT_LOWMASK
	MOV     MT_LOWMASK,0FFH
	SUB     [PERIOD+DI],AX
	MOV     CX,[PERIOD+DI]
	CMP     CX,113
	JGE     SHORT Go_PortaUSkip
	MOV     CX,113
	MOV     [PERIOD+DI],CX
Go_PortaUSkip:
	CALL    Go_PerNop2
	RET
Go_PortaUp ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 2 -- Portamento Down
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_PortaDown PROC NEAR
	MOVZX   AX,[CMDLO+SI]           ; Number to slide down
	AND     AL,MT_LOWMASK
	MOV     MT_LOWMASK,0FFH
	ADD     [PERIOD+DI],AX
	MOV     CX,[PERIOD+DI]
	CMP     CX,856
	JL      SHORT Go_PortaDSkip
	MOV     CX,856
	MOV     [PERIOD+DI],CX
Go_PortaDSkip:
	CALL    Go_PerNop2
	RET
Go_PortaDown ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 3 -- Tone Portamento
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_TonePortamento PROC NEAR
	MOV     AL,[CMDLO+SI]
	OR      AL,AL
	JZ      SHORT Go_TonePortNoChange
	MOV     [TONEPORTSPEED+SI],AL
	MOV     [CMDLO+SI],0
Go_TonePortNoChange:
	CMP     [WANTEDPERIOD+DI],0
	JZ      Go_Return
	MOVZX   DX,[TONEPORTSPEED+SI]
	MOV     CX,[PERIOD+DI]
	MOV     AX,[WANTEDPERIOD+DI]
	CMP     [TONEPORTDIREC+SI],0
	JNE     SHORT Go_TonePortaUp
Go_TonePortaDown:
	ADD     CX,DX
	CMP     AX,CX
	JG      SHORT Go_TonePortaSetPer
	JMP     SHORT Go_TonePortaEnd
Go_TonePortaUp:
	SUB     CX,DX
	CMP     AX,CX
	JL      SHORT Go_TonePortaSetPer
Go_TonePortaEnd:
	MOV     CX,AX
	MOV     [WANTEDPERIOD+DI],0
Go_TonePortaSetPer:
	MOV     [PERIOD+DI],CX
	MOV     AL,[GLISSFUNK+SI]
	AND     AL,0FH
	JZ      SHORT Go_GlissSkip
	MOV     AL,[FINETUNE+SI]
	MOV     BL,(36+12)*2
	MUL     BL
	PUSH    DI
	MOV     DI,OFFSET MT_PERIODTABLE
	ADD     DI,AX
	XOR     BX,BX
Go_GlissLoop:
	CMP     CX,[BX+DI]
	JAE     SHORT Go_GlissFound
	INC     BX
	INC     BX
	CMP     BX,(36+12)*2
	JB      Go_GlissLoop
	MOV     BX,(35+12)*2
Go_GlissFound:
	MOV     CX,[BX+DI]
	POP     DI
Go_GlissSkip:
	CALL    Go_PerNop2
	RET
Go_TonePortamento ENDP
;-----------------------------------------------------------------------------
Go_SetTonePorta PROC NEAR
	MOV     DX,[NOTE+DI]
	MOV     AL,[FINETUNE+SI]
	MOV     CL,48*2                 ;37
	MUL     CL
	PUSH    DI
	MOV     DI,OFFSET MT_PERIODTABLE
	ADD     DI,AX
	XOR     BX,BX
Go_StpLoop:
	CMP     DX,[BX+DI]
	JAE     SHORT Go_StpFound
	INC     BX
	INC     BX
	CMP     BX,48*2                 ;37
	JB      Go_StpLoop
	MOV     BX,47*2                 ;35
Go_StpFound:
	MOV     DL,[FINETUNE+SI]
	AND     DL,8
	JZ      SHORT Go_StpGoss
	OR      BX,BX
	JZ      SHORT Go_StpGoss
	DEC     BX
	DEC     BX
Go_StpGoss:
	MOV     DX,[BX+DI]
	POP     DI
	MOV     [WANTEDPERIOD+DI],DX
	MOV     AX,[PERIOD+DI]
	MOV     [TONEPORTDIREC+SI],0
	CMP     DX,AX
	JE      SHORT Go_ClearTonePorta
	JA      Go_Return
	INC     [TONEPORTDIREC+SI]
	RET
Go_ClearTonePorta:
	MOV     [WANTEDPERIOD+DI],0
	RET
Go_SetTonePorta ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 4 -- Vibrato
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_Vibrato PROC NEAR
	MOV     AL,[CMDLO+SI]
	OR      AL,AL
	JZ      SHORT Go_Vibrato2
	MOV     BL,[VIBRATOCMD+SI]
	AND     AL,0FH
	JZ      SHORT Go_vibskip
	AND     BL,0F0H
	OR      BL,AL
Go_vibskip:
	MOV     AL,[CMDLO+SI]
	AND     AL,0F0H
	JZ      SHORT Go_vibskip2
	AND     BL,0FH
	OR      BL,AL
Go_vibskip2:
	MOV     [VIBRATOCMD+SI],BL
Go_Vibrato2:
	MOV     AL,[VIBRATOPOS+SI]
	SHR     AL,2
	AND     AX,1FH
	MOV     BL,[WAVECONTROL+SI]
	AND     BL,3
	JZ      SHORT Go_vib_sine
	SHL     AL,3
	CMP     BL,1
	JE      SHORT Go_vib_rampdown
	MOV     BL,255
	JMP     SHORT Go_vib_set
Go_vib_rampdown:
	CMP     [VIBRATOPOS+SI],0
	JG      SHORT Go_vib_rampdown2
	MOV     BL,AL
	NOT     BL
	JMP     SHORT Go_vib_set
Go_vib_rampdown2:
	MOV     BL,AL
	JMP     SHORT Go_vib_set
Go_vib_sine:
	MOVZX   BX,AL
	MOV     BL,[MT_VIBRATOTABLE+BX]
Go_vib_set:
	MOV     AL,[VIBRATOCMD+SI]
	AND     AL,0FH
	MUL     BL
	SHR     AX,7
	MOV     BX,AX
	MOV     AX,[PERIOD+DI]
	CMP     [VIBRATOPOS+SI],0
	JG      SHORT Go_VibratoNeg     ; BMI
	NEG     BX
Go_VibratoNeg:
	ADD     AX,BX
Go_Vibrato3:
	MOV     CX,AX
	CALL    Go_PerNop2
	MOV     AL,[VIBRATOCMD+SI]
	AND     AL,0F0H
	SHR     AL,2
	ADD     [VIBRATOPOS+SI],AL
	RET
Go_Vibrato ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 5 -- Tone and Volume Slide
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_TonePlusVolSlide PROC NEAR
	CALL    Go_TonePortNoChange
	JMP     Go_VolumeSlide
Go_TonePlusVolSlide ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 6 -- Vibrato and Volume Slide
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_VibratoPlusVolSlide PROC NEAR
	CALL    Go_Vibrato2             ;was mt_vibrato2
	JMP     Go_VolumeSlide
Go_VibratoPlusVolSlide ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 7 -- Tremolo
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_Tremolo PROC NEAR
	MOV     AL,[CMDLO+SI]
	OR      AL,AL
	JZ      SHORT Go_Tremolo2
	MOV     BL,[TREMOLOCMD+SI]
	AND     AL,0FH
	JZ      SHORT Go_treskip
	AND     BL,0F0H
	OR      BL,AL
Go_treskip:
	MOV     AL,[CMDLO+SI]
	AND     AL,0F0H
	JZ      SHORT Go_treskip2
	AND     BL,0FH
	OR      BL,AL
Go_treskip2:
	MOV     [TREMOLOCMD+SI],BL
Go_Tremolo2:
	MOV     AL,[TREMOLOPOS+SI]
	SHR     AL,2
	AND     AX,1FH
	MOV     BL,[WAVECONTROL+SI]
	SHR     BL,4
	AND     BL,3
	JZ      SHORT Go_tre_sine
	SHL     AL,3
	CMP     BL,1
	JE      SHORT Go_tre_rampdown
	MOV     BL,255
	JMP     SHORT Go_tre_set
Go_tre_rampdown:
	CMP     [TREMOLOPOS+SI],0
	JG      SHORT Go_tre_rampdown2
	MOV     BL,AL
	NOT     BL
	JMP     SHORT Go_tre_set
Go_tre_rampdown2:
	MOV     BL,AL
	JMP     SHORT Go_tre_set
Go_tre_sine:
	MOVZX   BX,AL
	MOV     BL,[MT_VIBRATOTABLE+BX]
Go_tre_set:
	MOV     AL,[TREMOLOCMD+SI]
	AND     AL,0FH
	MUL     BL
	MOV     BX,AX
	SHR     BX,6
	MOV     AL,[VOLUME+SI]
	CMP     [TREMOLOPOS+SI],0
	JG      SHORT Go_TremoloNeg             ; BMI  jns
	ADD     AL,BL
	JMP     SHORT Go_Tremolo3
Go_TremoloNeg:
	SUB     AL,BL
Go_Tremolo3:
	JNC     SHORT Go_TremoloSkip
	XOR     AX,AX
Go_TremoloSkip:
	CMP     AL,40H
	JBE     SHORT Go_TremoloOK              ; BLS
	MOV     AL,40H
Go_TremoloOK:
	MOV     [MVOL+SI],AL                    ;was ah
	MOV     AL,[TREMOLOCMD+SI]
	AND     AL,0F0H
	SHR     AL,2
	ADD     [TREMOLOPOS+SI],AL
	RET
Go_Tremolo ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect 9 -- Sample Offset
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_SampleOffset PROC NEAR
	MOVZX   AX,[CMDLO+SI]
	OR      AL,AL
	JZ      SHORT Go_sononew
	MOV     [SAMPLEOFFSET+SI],AL
Go_sononew:
	MOVZX   AX,[SAMPLEOFFSET+SI]
	XCHG    AL,AH
	CMP     AX,[MMAXREP+DI]
	JAE     SHORT Go_sofskip
	MOV     [MOFS+DI],AX
	RET
Go_sofskip:
	MOV     AX,[MOFS+DI]
	MOV     [MMAXREP+DI],AX
	RET
Go_SampleOffset ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect A -- Volume Slide
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_VolumeSlide PROC NEAR
	MOV     AL,[CMDLO+SI]
	SHR     AL,4
	OR      AL,AL
	JZ      SHORT Go_VolSlideDown
Go_VolSlideUp:
	ADD     [VOLUME+SI],AL
	CMP     [VOLUME+SI],40H
	JBE     SHORT Go_vsdskip
	MOV     [VOLUME+SI],40H
	JMP     SHORT Go_vsdskip
Go_VolSlideDown:
	MOV     AL,[CMDLO+SI]
	AND     AL,0FH
Go_VolSlideDown2:
	SUB     [VOLUME+SI],AL
	JNC     SHORT Go_vsdskip
	MOV     [VOLUME+SI],0
Go_vsdskip:
	MOV     AL,[VOLUME+SI]
	MOV     [MVOL+SI],AL            ;was ah
	RET
Go_VolumeSlide ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect B -- Position Jump
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_PositionJump PROC NEAR
	MOV     AL,[CMDLO+SI]           ; Get where to jump
	DEC     AL                      ; Update the
	MOV     MT_SONGPOS,AL           ; information.
Go_pj2: MOV     MT_PBREAKPOS,0
	MOV     MT_POSJUMPFLAG,1
	RET
Go_PositionJump ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect C -- Volume Change
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_VolumeChange PROC NEAR
	MOV     AL,[CMDLO+SI]           ; Get value for volume
	CMP     AL,40H                  ; Is it greater than 40h?
	JBE     SHORT Go_VolumeOK       ; Nope
	MOV     AL,40H
Go_VolumeOK:
	MOV     [VOLUME+SI],AL
	MOV     [MVOL+SI],AL            ;was ah
	RET
Go_VolumeChange ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect D -- Pattern Break
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_PatternBreak PROC NEAR
	MOV     AL,[CMDLO+SI]           ; Break to where?
	MOV     BL,AL                   ; POSITION IS IN DECIMAL
	SHR     AL,4
	MOV     CL,10
	MUL     CL
	AND     BL,0FH
	ADD     AL,BL
	CMP     AL,63
	JG      Go_pj2
	MOV     MT_PBREAKPOS,AL
	MOV     MT_POSJUMPFLAG,1
	RET
Go_PatternBreak ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect F -- Set Speed
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_SetSpeed PROC NEAR
	MOV     AL,[CMDLO+SI]           ; Get value for speed
	OR      AL,AL
	JZ      Go_Return
	CMP     AL,32                   ; Is it a BPM value ?
	JAE     SHORT Go_SetBPM
	MOV     MT_COUNTER,0
	MOV     MT_SPEED,AL
	RET
Go_SetBPM:
	XOR     AH,AH
	MOV     BPM_VALUE,AX
	CMP     AL,76                   ; MIXROUTINE CANT HANDLE LESS THAN 76
	JAE     SHORT Go_CheckBPM1
	MOV     AL,76
Go_CheckBPM1:
	CMP     AL,202                  ; MIXROUTINE CANT HANDLE MORE THAN 202
	JBE     SHORT Go_CheckBPM2
	MOV     AL,202
Go_CheckBPM2:
	SHL     AX,1
	MOV     BL,5                    ; Denna bit „r f”r att st„lla
	DIV     BL                      ; EFFECTs till annat „n 50Hz
	MOV     DL,AL                   ; Detta ger automatiskt en annan
	XOR     DH,DH                   ; PATT_SPEED.; Hz=2*BPM/5
	XOR     AX,AX
	MOV     BX,BPM_RATE
	DIV     BX
	MOV     WORD PTR BPM_SPEED,AX
	XOR     AX,AX
	DIV     BX
	MOV     WORD PTR BPM_SPEED+2,AX
	RET
Go_SetSpeed ENDP
;=============================================================================
Go_CheckMoreEfx PROC NEAR
	MOVZX   BX,[CMD+SI]
	SHL     BL,1
	JMP     [Effect_Jump_Table2+BX]
Go_CheckMoreEfx ENDP
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Effect E
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Go_E_Commands PROC NEAR
	MOVZX   BX,[CMDLO+SI]
	SHR     BL,4
	SHL     BL,1
	MOV     AL,[CMDLO+SI]
	AND     AL,0FH
	JMP     [Effect_Jump_Table3+BX]
;-----------------------------------------------------------------------------
; Effect 0 -- FilterOnOff
; Effect 1 -- Fine Porta Up
;-----------------------------------------------------------------------------
Go_FinePortaUp:
	CMP     MT_COUNTER,0
	JNE     Go_Return
	MOV     MT_LOWMASK,0FH
	JMP     Go_PortaUp
;-----------------------------------------------------------------------------
; Effect 2 -- Fine Porta Down
;-----------------------------------------------------------------------------
Go_FinePortaDown:
	CMP     MT_COUNTER,0
	JNE     Go_Return
	MOV     MT_LOWMASK,0FH
	JMP     Go_PortaDown
;-----------------------------------------------------------------------------
; Effect 3 -- Set Gliss Control
;-----------------------------------------------------------------------------
Go_SetGlissControl:
	AND     [GLISSFUNK+SI],0F0H
	OR      [GLISSFUNK+SI],AL
	RET
;-----------------------------------------------------------------------------
; Effect 4 -- Set Vibrato Control
;-----------------------------------------------------------------------------
Go_SetVibratoControl:
	AND     [WAVECONTROL+SI],0F0H
	OR      [WAVECONTROL+SI],AL
	RET
;-----------------------------------------------------------------------------
; Effect 5 -- Set Fine Tune
;-----------------------------------------------------------------------------
Go_SetFineTune:
	MOV     [FINETUNE+SI],AL
	RET
;-----------------------------------------------------------------------------
; Effect 6 -- Jump Loop
;-----------------------------------------------------------------------------
Go_JumpLoop:
	CMP     MT_COUNTER,0
	JNE     Go_Return
	OR      AL,AL
	JZ      SHORT Go_SetLoop
	CMP     [LOOPCOUNT+SI],0
	JE      SHORT Go_jumpcnt
	DEC     [LOOPCOUNT+SI]
	JZ      Go_Return
Go_jmploop:
	MOV     AL,[PATTPOS+SI]
	MOV     MT_PBREAKPOS,AL
	MOV     MT_PBREAKFLAG,1
	RET
Go_jumpcnt:
	MOV     [LOOPCOUNT+SI],AL
	JMP     Go_jmploop
Go_SetLoop:
	MOV     AX,MT_PATTERNPOS
	SHR     AX,2
	MOV     [PATTPOS+SI],AL
	RET
;-----------------------------------------------------------------------------
; Effect 7 -- Set Tremolo Control
;-----------------------------------------------------------------------------
Go_SetTremoloControl:
	SHL     AL,4
	AND     [WAVECONTROL+SI],0FH
	OR      [WAVECONTROL+SI],AL
	RET
;-----------------------------------------------------------------------------
; Effect 9 -- Retrig Note
;-----------------------------------------------------------------------------
Go_RetrigNote:
	MOV     BL,AL
	OR      BL,BL
	JZ      SHORT Go_rtnend
	MOVZX   AX,MT_COUNTER
	OR      AL,AL
	JNZ     SHORT Go_rtnskp
	CMP     [NOTE+DI],0
	JNE     SHORT Go_rtnskp
	MOV     MT_COUNTER,0
Go_rtnskp:
	DIV     BL
	XCHG    AL,AH
	OR      AL,AL
	JNZ     SHORT Go_rtnend
Go_DoRetrig:
	XOR     AX,AX
	MOV     [MOFS+DI],AX
	MOV     [MOFLOW+SI],AL
	MOV     AX,[LENGTHI+DI]
	MOV     [MMAXREP+DI],AX
	MOV     AX,[LOOPSTART+DI]
	MOV     [MREPEAT+DI],AX
	ADD     AX,[REPLEN+DI]
	MOV     [MREPLEN+DI],AX
Go_rtnend:
	RET
;-----------------------------------------------------------------------------
; Effect A -- Volume Fine Up
;-----------------------------------------------------------------------------
Go_VolumeFineUp:
	CMP     MT_COUNTER,0
	JNE     Go_Return
	JMP     Go_VolSlideUp
;-----------------------------------------------------------------------------
; Effect B -- Volume Fine Down
;-----------------------------------------------------------------------------
Go_VolumeFineDown:
	CMP     MT_COUNTER,0
	JNZ     Go_Return
	JMP     Go_VolSlideDown2
;-----------------------------------------------------------------------------
; Effect C -- Note Cut
;-----------------------------------------------------------------------------
Go_NoteCut:
	CMP     AL,MT_COUNTER
	JNE     Go_Return
	MOV     [VOLUME+SI],0
	MOV     [MVOL+SI],AL
	RET
;-----------------------------------------------------------------------------
; Effect D -- Note Delay
;-----------------------------------------------------------------------------
Go_NoteDelay:
	CMP     AL,MT_COUNTER
	JNE     Go_Return
	CMP     [NOTE+DI],0
	JE      Go_Return
	JMP     Go_DoRetrig
;-----------------------------------------------------------------------------
; Effect E -- Pattern Delay
;-----------------------------------------------------------------------------
Go_PatternDelay:
	CMP     MT_COUNTER,0
	JNE     Go_Return
	CMP     MT_PATTDELAYTIME2,0
	JNZ     Go_Return
	INC     AL
	MOV     MT_PATTDELAYTIME,AL
	RET
;-----------------------------------------------------------------------------
; Effect F -- Funk It
;-----------------------------------------------------------------------------
Go_E_Commands ENDP
;=============================================================================


;=============================================================================
MIXUP_CHANNELS PROC NEAR
	CMP     MOD_STAT,3              ;MOD HAS FINISHED
	JB      SHORT GMX7
	XOR     AX,AX
	XOR     BX,BX
	MOV     CX,MAX_CHAN_NUMB
LMX4:   MOV     [MSEG+BX],AX
	INC     BX
	INC     BX
	LOOP    LMX4
GMX7:   MOV     CX,DMA_CX
	CMP     MOD_STAT,2
	JB      SHORT GMX3
	OUT     0CH,AL                  ;DMA FLIP-FLOP RESET
	MOVZX   DX,DMA_CHANNEL
	SHL     DL,1
	IN      AL,DX                   ;GET DMA POSITION
	XCHG    AL,AH
	IN      AL,DX
	XCHG    AL,AH
	SUB     AX,DMA_POFF             ;AX IS OFFSET OF DMA-POS
	AND     AX,0FFFEH
	ADD     AX,DMA_MORE
	CMP     AX,DMA_MAX
	JB      SHORT GMX1
	SUB     AX,DMA_MAX
GMX1:   ADD     AX,DMA_OFFSET
	SUB     AX,DMA_PTR
	JNC     SHORT GMX2
	ADD     AX,DMA_MAX
GMX2:   MOV     CX,AX                   ;CX IS NUMBER OF BYTES TO CALCULATE
	ADD     AX,DMA_PTR
	SUB     AX,DMA_OFFSET
	SUB     AX,2000H
	JC      SHORT GMX3
	SUB     CX,AX
GMX3:   XOR     BX,BX
	XOR     DI,DI
	CLD
	SHR     CX,1
	JZ      SHORT GMX5
	TEST    SBPRO_FLAG,1
	JNZ     SHORT SBPRO_MIXING      ;SB MONO-MIXING
	CALL    MIX_CHANNELA            ;INIT BUFFER WITH FIRST CHANNEL
	INC     BX
	INC     DI
	INC     DI
	DEC     CH_NUMB
LMX1:   CALL    MIX_CHANNELM            ;MIX CHANNELS
	INC     BX
	INC     DI
	INC     DI
	CMP     BX,CH_NUMB
	JB      LMX1
	INC     CH_NUMB
	CALL    MIX_CHANNELX            ;END UP BUFFER WITH LAST CHANNEL
	MOV     AX,SAM_SEG1
	OR      AX,SAM_SEG2
	JZ      SHORT LMX2
	CALL    MIX_CHANNELS1           ;SAMPLE1: MIDDLE CHANNEL
	CALL    MIX_CHANNELS2           ;SAMPLE2: MIDDLE CHANNEL
	CALL    FIXUP_CHANNELS1         ;END UP CHANNEL BY CONVERTING IT TO PC
LMX2:   MOV     AX,DMA_NEWPTR           ;CHECK DMA-BUFFER OVERFLOW
	MOV     SI,DMA_MAX              ;ITS A RING BUFFER
	ADD     SI,DMA_OFFSET
	CMP     AX,SI
	JB      SHORT GMX4
	MOV     CX,AX
	MOV     DI,DMA_OFFSET
	SUB     CX,SI
	JZ      SHORT GMX6
	CLD
	SHR     CX,1
	PUSH    DS
	MOV     ES,DMA_SEG
	MOV     DS,DMA_SEG
	REP MOVSW                       ;MOVE OVERFLOW DATA
	POP     DS
GMX6:   MOV     AX,DI
GMX4:   MOV     DMA_PTR,AX              ;START DSP OUTPUT
	CMP     MOD_STAT,1
	JNE     SHORT GMX5
	INC     MOD_STAT
	CALL    DSP_OUT
GMX5:   RET
SBPRO_MIXING:
	SHR     CX,1                    ;SBPRO STEREO-MIXING
	JZ      GMX5
	MOV     AX,[STEREO_PANNING+DI]
	ADD     DMA_PTR,AX
	CALL    MIX_CHANNELA            ;INIT BUFFER WITH FIRST CHANNEL
	INC     BX
	INC     DI
	INC     DI
	PUSH    DMA_NEWPTR
	MOV     AX,[STEREO_PANNING+DI]
	ADD     DMA_PTR,AX
	CALL    MIX_CHANNELA            ;THIS CHANNEL SHOULD BE ON RIGHT
	INC     BX                      ;(OTHERWISE DMA_NEWPTR IS 2 TOO HIGH)
	INC     DI
	INC     DI
	POP     AX
	CMP     AX,DMA_NEWPTR
	JAE     SHORT LMX3
	MOV     DMA_NEWPTR,AX
LMX3:   MOV     AX,[STEREO_PANNING+DI]
	ADD     DMA_PTR,AX
	CALL    MIX_CHANNELM            ;MIX CHANNELS
	INC     BX
	INC     DI
	INC     DI
	CMP     BX,CH_NUMB
	JB      LMX3
	MOV     AX,[STEREO_PANNING+DI]
	ADD     DMA_PTR,AX
	CALL    MIX_CHANNELS1           ;SAMPLE1: LEFT CHANNEL
	CALL    MIX_CHANNELS2           ;SAMPLE2: LEFT CHANNEL
	ADD     DMA_PTR,2
	CALL    MIX_CHANNELS3           ;SAMPLE3: RIGHT CHANNEL
	CALL    MIX_CHANNELS4           ;SAMPLE4: RIGHT CHANNEL
	SUB     DMA_PTR,2
	CALL    FIXUP_CHANNELS2         ;END UP CHANNEL BY CONVERTING IT TO PC
	JMP     LMX2
MIXUP_CHANNELS ENDP
;-----------------------------------------------------------------------------
MIX_CHANNELA PROC NEAR
	PUSH    CX BX DI
	MOV     SI,[MOFS+DI]            ;GET OFFSET IN SAMPLE (START ALWAYS= 0)
	MOV     DX,[MFREQ+DI]           ;OFF ADD AFTER FIXED POINT (X/256)
	MOV     BYTE PTR SLA2+2,DL
	MOV     BYTE PTR SLA3+2,DH
	MOV     BYTE PTR SLA5+2,DL
	MOV     BYTE PTR SLA6+2,DH
	MOV     WORD PTR SLA1,01472H    ;JB SHORT +20
	MOV     WORD PTR SLA4,01472H    ;JB SHORT +20
	OR      DH,DH
	JNZ     SHORT MIX_NOIPA
	MOV     WORD PTR SLA1,0D68AH    ;MOV DL,DH
	MOV     WORD PTR SLA4,0D68AH    ;MOV DL,DH
MIX_NOIPA:
	MOV     DH,[MOFLOW+BX]          ;ACTUAL AFTER FIXED POINT VALUE
	MOV     AL,[MVOL+BX]            ;SAMPLE VOLUME
	MOV     BL,MUSIC_VOL            ;MASTER VOLUME
	MUL     BL
	XOR     AL,AL
	ADD     AX,MIXMUL_OFFSET
	MOV     BX,AX                   ;DS:BX POINTS INTO MIXMUL_VOLUMETABLE
	MOV     ES,[MSEG+DI]
	MOV     AX,[MMAXREP+DI]         ;SP IS OFFSET OF SAMPLE ENDING
	DEC     AX
	MOV     WORD PTR SELFM1+2,AX
	MOV     WORD PTR SELFM2+2,AX
	JMP     SHORT CLEAR_PREF1       ;CLEAR PREFETCH QUEUE!!!
CLEAR_PREF1:
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG              ;DS:DI IS DMA-BUFFER POINTER
	MOV     AX,ES                   ;ES:SI IS SAMPLE-DATA POINTER
	OR      AX,AX
	JZ      SILENT_FILLA
MIX_LOOPA:
SELFM1: CMP     SI,0FFFFH               ;SELFMODIFYING CODE
	JAE     SHORT REST_FILLA
	MOV     AX,ES:[SI]
SLA1:   MOV     DL,DH                   ;SMCODE
	MOVSX   BP,AL
	SAR     AH,1
	SAR     AL,1
	SHR     DL,1
	SUB     AL,AH
	NEG     AL
	IMUL    DL
	SAR     AX,6
	ADD     AX,BP
	XLATB
SLA2:   ADD     DH,0                    ;SMCODE
SLA3:   ADC     SI,0                    ;SMCODE
	MOV     [DI],AL
SELFM2: CMP     SI,0FFFFH               ;SELFMODIFYING CODE
	JAE     SHORT REST_FILLA
	MOV     AX,ES:[SI]
SLA4:   MOV     DL,DH                   ;SMCODE
	MOVSX   BP,AL
	SAR     AH,1
	SAR     AL,1
	SHR     DL,1
	SUB     AL,AH
	NEG     AL
	IMUL    DL
	SAR     AX,6
	ADD     AX,BP
	XLATB
SLA5:   ADD     DH,0                    ;SMCODE
SLA6:   ADC     SI,0                    ;SMCODE
	MOV     [DI+1],AL
SELFN1: ADD     DI,2                    ;SELFMODIFYING CODE
	LOOP    MIX_LOOPA
MIX_ENDA:
	MOV     AX,CS
	MOV     DS,AX
	MOV     AX,ES
	MOV     DMA_NEWPTR,DI
	POP     DI BX CX
	MOV     [MSEG+DI],AX
	MOV     [MOFLOW+BX],DH
	MOV     [MOFS+DI],SI
	RET
REST_FILLA:
	POP     SI
	PUSH    SI
	MOV     AX,CS:[MREPLEN+SI]
	OR      AX,AX
	JZ      SHORT SILENT_FILLA
	MOV     CS:[MMAXREP+SI],AX
	DEC     AX
	MOV     WORD PTR CS:SELFM1+2,AX
	MOV     WORD PTR CS:SELFM2+2,AX
	MOV     SI,CS:[MREPEAT+SI]
	JMP     MIX_LOOPA
SILENT_FILLA:
	MOV     BX,DS
	MOV     ES,BX
	TEST    CS:SBPRO_FLAG,1
	JNZ     SHORT SILENT_FILLB
	REP STOSW
	MOV     ES,AX
	JMP     MIX_ENDA
SILENT_FILLB:
	STOSW
	INC     DI
	INC     DI
	LOOP    SILENT_FILLB
	MOV     ES,AX
	JMP     MIX_ENDA
MIX_CHANNELA ENDP
;-----------------------------------------------------------------------------
MIX_CHANNELM PROC NEAR
	PUSH    CX BX DI
	MOV     SI,[MOFS+DI]            ;GET OFFSET IN SAMPLE (START ALWAYS= 0)
	MOV     DX,[MFREQ+DI]           ;OFF ADD AFTER FIXED POINT (X/256)
	MOV     BYTE PTR SLM2+2,DL
	MOV     BYTE PTR SLM3+2,DH
	MOV     BYTE PTR SLM5+2,DL
	MOV     BYTE PTR SLM6+2,DH
	MOV     WORD PTR SLM1,01472H    ;JB SHORT +20
	MOV     WORD PTR SLM4,01472H    ;JB SHORT +20
	OR      DH,DH
	JNZ     SHORT MIX_NOIPM
	MOV     WORD PTR SLM1,0D68AH    ;MOV DL,DH
	MOV     WORD PTR SLM4,0D68AH    ;MOV DL,DH
MIX_NOIPM:
	MOV     DH,[MOFLOW+BX]          ;ACTUAL AFTER FIXED POINT VALUE
	MOV     AL,[MVOL+BX]            ;SAMPLE VOLUME
	MOV     BL,MUSIC_VOL            ;MASTER VOLUME
	MUL     BL
	XOR     AL,AL
	ADD     AX,MIXMUL_OFFSET
	MOV     BX,AX                   ;DS:BX POINTS INTO MIXMUL_VOLUMETABLE
	MOV     ES,[MSEG+DI]
	MOV     AX,[MMAXREP+DI]         ;OFFSET OF SAMPLE ENDING
	DEC     AX
	MOV     WORD PTR SELFM3+2,AX
	MOV     WORD PTR SELFM4+2,AX
	JMP     SHORT CLEAR_PREF2       ;CLEAR PREFETCH QUEUE!!!
CLEAR_PREF2:
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG              ;DS:DI IS DMA-BUFFER POINTER
	MOV     AX,ES
	OR      AX,AX
	JZ      SHORT MIX_ENDM
MIX_LOOPM:
SELFM3: CMP     SI,0FFFFH               ;SELFMODIFYING CODE
	JAE     SHORT REST_FILLM
	MOV     AX,ES:[SI]
SLM1:   MOV     DL,DH                   ;SMCODE
	MOVSX   BP,AL
	SAR     AH,1
	SAR     AL,1
	SHR     DL,1
	SUB     AL,AH
	NEG     AL
	IMUL    DL
	SAR     AX,6
	ADD     AX,BP
	XLATB
SLM2:   ADD     DH,0                    ;SMCODE
SLM3:   ADC     SI,0                    ;SMCODE
	ADD     [DI],AL
	JNO     SHORT SELFM4
	SHR     AL,7
	ADD     AL,7FH
	MOV     [DI],AL
SELFM4: CMP     SI,0FFFFH               ;SELFMODIFYING CODE
	JAE     SHORT REST_FILLM
	MOV     AX,ES:[SI]
SLM4:   MOV     DL,DH                   ;SMCODE
	MOVSX   BP,AL
	SAR     AH,1
	SAR     AL,1
	SHR     DL,1
	SUB     AL,AH
	NEG     AL
	IMUL    DL
	SAR     AX,6
	ADD     AX,BP
	XLATB
SLM5:   ADD     DH,0                    ;SMCODE
SLM6:   ADC     SI,0                    ;SMCODE
	ADD     [DI+1],AL
	JNO     SHORT SELFN2
	SHR     AL,7
	ADD     AL,7FH
	MOV     [DI+1],AL
SELFN2: ADD     DI,2                    ;SELFMODIFYING CODE
	LOOP    MIX_LOOPM
MIX_ENDM:
	MOV     AX,CS
	MOV     DS,AX
	MOV     AX,ES
	POP     DI BX CX
	MOV     [MSEG+DI],AX
	MOV     [MOFLOW+BX],DH
	MOV     [MOFS+DI],SI
	RET
REST_FILLM:
	POP     SI
	PUSH    SI
	MOV     AX,CS:[MREPLEN+SI]
	OR      AX,AX
	JZ      SHORT SILENT_FILLM
	MOV     CS:[MMAXREP+SI],AX
	DEC     AX
	MOV     WORD PTR CS:SELFM3+2,AX
	MOV     WORD PTR CS:SELFM4+2,AX
	MOV     SI,CS:[MREPEAT+SI]
	JMP     MIX_LOOPM
SILENT_FILLM:
	MOV     ES,AX
	JMP     MIX_ENDM
MIX_CHANNELM ENDP
;-----------------------------------------------------------------------------
MIX_CHANNELX PROC NEAR
	PUSH    CX BX DI
	MOV     SI,[MOFS+DI]            ;GET OFFSET IN SAMPLE (START ALWAYS= 0)
	MOV     DX,[MFREQ+DI]           ;OFF ADD AFTER FIXED POINT (X/256)
	MOV     BYTE PTR SLX2+2,DL
	MOV     BYTE PTR SLX3+2,DH
	MOV     BYTE PTR SLX5+2,DL
	MOV     BYTE PTR SLX6+2,DH
	MOV     WORD PTR SLX1,01472H    ;JB SHORT +20
	MOV     WORD PTR SLX4,01472H    ;JB SHORT +20
	OR      DH,DH
	JNZ     SHORT MIX_NOIPX
	MOV     WORD PTR SLX1,0D68AH    ;MOV DL,DH
	MOV     WORD PTR SLX4,0D68AH    ;MOV DL,DH
MIX_NOIPX:
	MOV     DH,[MOFLOW+BX]          ;ACTUAL AFTER FIXED POINT VALUE
	MOV     AL,[MVOL+BX]            ;SAMPLE VOLUME
	MOV     BL,MUSIC_VOL            ;MASTER VOLUME
	MUL     BL
	XOR     AL,AL
	ADD     AX,MIXMUL_OFFSET
	MOV     BX,AX                   ;DS:BX POINTS INTO MIXMUL_VOLUMETABLE
	MOV     ES,[MSEG+DI]
	MOV     AX,[MMAXREP+DI]         ;SP IS OFFSET OF SAMPLE ENDING
	DEC     AX
	MOV     WORD PTR SELFM5+2,AX
	MOV     WORD PTR SELFM6+2,AX
	MOV     WORD PTR SELFM7+2,0
	MOV     AX,SAM_SEG1
	OR      AX,SAM_SEG2
	JNZ     SHORT YES_SAMPLES
	MOV     WORD PTR SELFM7+2,8080H
YES_SAMPLES:
	JMP     SHORT CLEAR_PREF3       ;CLEAR PREFETCH QUEUE!!!
CLEAR_PREF3:
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG              ;DS:DI IS DMA-BUFFER POINTER
	MOV     AX,ES                   ;ES:SI IS SAMPLE-DATA POINTER
	OR      AX,AX
	JZ      SILENT_FILLX
MIX_LOOPX:
SELFM5: CMP     SI,0FFFFH               ;SELFMODIFYING CODE
	JAE     SHORT REST_FILLX
	MOV     AX,ES:[SI]
SLX1:   MOV     DL,DH                   ;SMCODE
	MOVSX   BP,AL
	SAR     AH,1
	SAR     AL,1
	SHR     DL,1
	SUB     AL,AH
	NEG     AL
	IMUL    DL
	SAR     AX,6
	ADD     AX,BP
	XLATB
SLX2:   ADD     DH,0                    ;SMCODE
SLX3:   ADC     SI,0                    ;SMCODE
	ADD     [DI],AL
	JNO     SHORT SELFM6
	SHR     AL,7
	ADD     AL,7FH
	MOV     [DI],AL
SELFM6: CMP     SI,0FFFFH               ;SELFMODIFYING CODE
	JAE     SHORT REST_FILLX
	MOV     AX,ES:[SI]
SLX4:   MOV     DL,DH                   ;SMCODE
	MOVSX   BP,AL
	SAR     AH,1
	SAR     AL,1
	SHR     DL,1
	SUB     AL,AH
	NEG     AL
	IMUL    DL
	SAR     AX,6
	ADD     AX,BP
	XLATB
SLX5:   ADD     DH,0                    ;SMCODE
SLX6:   ADC     SI,0                    ;SMCODE
	ADD     [DI+1],AL
	JNO     SHORT SELFM7
	SHR     AL,7
	ADD     AL,7FH
	MOV     [DI+1],AL
SELFM7: XOR     WORD PTR [DI],8080H
	INC     DI
	INC     DI
	LOOP    MIX_LOOPX
MIX_ENDX:
	MOV     AX,CS
	MOV     DS,AX
	MOV     AX,ES
	POP     DI BX CX
	MOV     [MSEG+DI],AX
	MOV     [MOFLOW+BX],DH
	MOV     [MOFS+DI],SI
	RET
REST_FILLX:
	POP     SI
	PUSH    SI
	MOV     AX,CS:[MREPLEN+SI]
	OR      AX,AX
	JZ      SHORT SILENT_FILLX
	MOV     CS:[MMAXREP+SI],AX
	DEC     AX
	MOV     WORD PTR CS:SELFM5+2,AX
	MOV     WORD PTR CS:SELFM6+2,AX
	MOV     SI,CS:[MREPEAT+SI]
	JMP     MIX_LOOPX
SILENT_FILLX:
	MOV     ES,AX
	MOV     AX,CS:[SAM_SEG1]
	OR      AX,CS:[SAM_SEG2]
	JNZ     MIX_ENDX
SILENT_FILLL:
	XOR     WORD PTR [DI],8080H
	INC     DI
	INC     DI
	LOOP    SILENT_FILLL
	JMP     MIX_ENDX
MIX_CHANNELX ENDP
;-----------------------------------------------------------------------------
FIXUP_CHANNELS1 PROC NEAR
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG
	SHR     CX,1
	JNC     SHORT FIXUP_LOOP1
	XOR     WORD PTR [DI],8080H
	INC     DI
	INC     DI
FIXUP_LOOP1:
	XOR     DWORD PTR [DI],80808080H
	ADD     DI,4
	LOOP    FIXUP_LOOP1
	MOV     AX,CS
	MOV     DS,AX
	RET
FIXUP_CHANNELS1 ENDP
;-----------------------------------------------------------------------------
FIXUP_CHANNELS2 PROC NEAR
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG
FIXUP_LOOP2:
	XOR     DWORD PTR [DI],80808080H
	INC     DI
	ROL     WORD PTR [DI],8
	ADD     DI,3
	LOOP    FIXUP_LOOP2
	MOV     AX,CS
	MOV     DS,AX
	RET
FIXUP_CHANNELS2 ENDP
;-----------------------------------------------------------------------------
MIX_CHANNELS1 PROC NEAR
	CMP     SAM_SEG1,0
	JE      GO_BACKS1
	CALL    EMS_SAVE
	PUSH    EAX
	MOV     EAX,SAM_OFS1
	CALL    EMS_PAGING
	POP     EAX
	MOV     SI,DI                   ;GET OFFSET IN SAMPLE (START ALWAYS= 0)
	MOV     DX,SAM_FRQ1             ;OFF ADD AFTER FIXED POINT (X/256)
	MOVZX   BP,DH                   ;OFF ADD BEFORE FIXED POINT
	MOV     DH,SAM_OFL1             ;ACTUAL AFTER FIXED POINT VALUE
	MOV     BX,SAM_MAX1             ;COUNTER FOR SAMPLE ENDING
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG              ;DS:DI IS DMA-BUFFER POINTER
	PUSH    CX SI
MIX_LOOPS1:
	MOV     AL,ES:[SI]
	ADD     DH,DL
	ADC     SI,BP
	SUB     DH,DL
	ADD     DH,DL
	SBB     BX,BP
	JC      SHORT MIX_ENDS1
	JZ      SHORT MIX_ENDS1
	MOV     AH,ES:[SI]
	ADD     DH,DL
	ADC     SI,BP
	ADD     [DI],AL
	JNO     SHORT MIX_OS11
	SHR     AL,7
	ADD     AL,7FH
	MOV     [DI],AL
MIX_OS11:
	ADD     [DI+1],AH
	JNO     SHORT SELFN3
	SHR     AH,7
	ADD     AH,7FH
	MOV     [DI+1],AH
SELFN3: ADD     DI,2
	SUB     DH,DL
	ADD     DH,DL
	SBB     BX,BP
	JC      SHORT MIX_ENDS1
	JZ      SHORT MIX_ENDS1
	LOOP    MIX_LOOPS1
MIX_REST1:
	MOV     AX,CS
	MOV     DS,AX
	MOV     SAM_OFL1,DH
	POP     AX CX
	SUB     SI,AX
	PUSH    EAX
	MOVZX   EAX,SI
	ADD     SAM_OFS1,EAX
	POP     EAX
	MOV     SAM_MAX1,BX
	CALL    EMS_RESTORE
GO_BACKS1:
	RET
MIX_ENDS1:
	MOV     CS:SAM_SEG1,0
	JMP     MIX_REST1
MIX_CHANNELS1 ENDP
;-----------------------------------------------------------------------------
MIX_CHANNELS2 PROC NEAR
	CMP     SAM_SEG2,0
	JE      GO_BACKS2
	CALL    EMS_SAVE
	PUSH    EAX
	MOV     EAX,SAM_OFS2
	CALL    EMS_PAGING
	POP     EAX
	MOV     SI,DI                   ;GET OFFSET IN SAMPLE (START ALWAYS= 0)
	MOV     DX,SAM_FRQ2             ;OFF ADD AFTER FIXED POINT (X/256)
	MOVZX   BP,DH                   ;OFF ADD BEFORE FIXED POINT
	MOV     DH,SAM_OFL2             ;ACTUAL AFTER FIXED POINT VALUE
	MOV     BX,SAM_MAX2             ;COUNTER FOR SAMPLE ENDING
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG              ;DS:DI IS DMA-BUFFER POINTER
	PUSH    CX SI
MIX_LOOPS2:
	MOV     AL,ES:[SI]
	ADD     DH,DL
	ADC     SI,BP
	SUB     DH,DL
	ADD     DH,DL
	SBB     BX,BP
	JC      SHORT MIX_ENDS2
	JZ      SHORT MIX_ENDS2
	MOV     AH,ES:[SI]
	ADD     DH,DL
	ADC     SI,BP
	ADD     [DI],AL
	JNO     SHORT MIX_OS21
	SHR     AL,7
	ADD     AL,7FH
	MOV     [DI],AL
MIX_OS21:
	ADD     [DI+1],AH
	JNO     SHORT SELFN4
	SHR     AH,7
	ADD     AH,7FH
	MOV     [DI+1],AH
SELFN4: ADD     DI,2
	SUB     DH,DL
	ADD     DH,DL
	SBB     BX,BP
	JC      SHORT MIX_ENDS2
	JZ      SHORT MIX_ENDS2
	LOOP    MIX_LOOPS2
MIX_REST2:
	MOV     AX,CS
	MOV     DS,AX
	MOV     SAM_OFL2,DH
	POP     AX CX
	SUB     SI,AX
	PUSH    EAX
	MOVZX   EAX,SI
	ADD     SAM_OFS2,EAX
	POP     EAX
	MOV     SAM_MAX2,BX
	CALL    EMS_RESTORE
GO_BACKS2:
	RET
MIX_ENDS2:
	MOV     CS:SAM_SEG2,0
	JMP     MIX_REST2
MIX_CHANNELS2 ENDP
;-----------------------------------------------------------------------------
MIX_CHANNELS3 PROC NEAR
	CMP     SAM_SEG3,0
	JE      GO_BACKS3
	CALL    EMS_SAVE
	PUSH    EAX
	MOV     EAX,SAM_OFS3
	CALL    EMS_PAGING
	POP     EAX
	MOV     SI,DI                   ;GET OFFSET IN SAMPLE (START ALWAYS= 0)
	MOV     DX,SAM_FRQ3             ;OFF ADD AFTER FIXED POINT (X/256)
	MOVZX   BP,DH                   ;OFF ADD BEFORE FIXED POINT
	MOV     DH,SAM_OFL3             ;ACTUAL AFTER FIXED POINT VALUE
	MOV     BX,SAM_MAX3             ;COUNTER FOR SAMPLE ENDING
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG              ;DS:DI IS DMA-BUFFER POINTER
	PUSH    CX SI
MIX_LOOPS3:
	MOV     AL,ES:[SI]
	ADD     DH,DL
	ADC     SI,BP
	SUB     DH,DL
	ADD     DH,DL
	SBB     BX,BP
	JC      SHORT MIX_ENDS3
	JZ      SHORT MIX_ENDS3
	MOV     AH,ES:[SI]
	ADD     DH,DL
	ADC     SI,BP
	ADD     [DI],AL
	JNO     SHORT MIX_OS31
	SHR     AL,7
	ADD     AL,7FH
	MOV     [DI],AL
MIX_OS31:
	ADD     [DI+1],AH
	JNO     SHORT MIX_OS32
	SHR     AH,7
	ADD     AH,7FH
	MOV     [DI+1],AH
MIX_OS32:
	ADD     DI,4
	SUB     DH,DL
	ADD     DH,DL
	SBB     BX,BP
	JC      SHORT MIX_ENDS3
	JZ      SHORT MIX_ENDS3
	LOOP    MIX_LOOPS3
MIX_REST3:
	MOV     AX,CS
	MOV     DS,AX
	MOV     SAM_OFL3,DH
	POP     AX CX
	SUB     SI,AX
	PUSH    EAX
	MOVZX   EAX,SI
	ADD     SAM_OFS3,EAX
	POP     EAX
	MOV     SAM_MAX3,BX
	CALL    EMS_RESTORE
GO_BACKS3:
	RET
MIX_ENDS3:
	MOV     CS:SAM_SEG3,0
	JMP     MIX_REST3
MIX_CHANNELS3 ENDP
;-----------------------------------------------------------------------------
MIX_CHANNELS4 PROC NEAR
	CMP     SAM_SEG4,0
	JE      GO_BACKS4
	CALL    EMS_SAVE
	PUSH    EAX
	MOV     EAX,SAM_OFS4
	CALL    EMS_PAGING
	POP     EAX
	MOV     SI,DI                   ;GET OFFSET IN SAMPLE (START ALWAYS= 0)
	MOV     DX,SAM_FRQ4             ;OFF ADD AFTER FIXED POINT (X/256)
	MOVZX   BP,DH                   ;OFF ADD BEFORE FIXED POINT
	MOV     DH,SAM_OFL4             ;ACTUAL AFTER FIXED POINT VALUE
	MOV     BX,SAM_MAX4             ;COUNTER FOR SAMPLE ENDING
	MOV     DI,DMA_PTR
	MOV     DS,DMA_SEG              ;DS:DI IS DMA-BUFFER POINTER
	PUSH    CX SI
MIX_LOOPS4:
	MOV     AL,ES:[SI]
	ADD     DH,DL
	ADC     SI,BP
	SUB     DH,DL
	ADD     DH,DL
	SBB     BX,BP
	JC      SHORT MIX_ENDS4
	JZ      SHORT MIX_ENDS4
	MOV     AH,ES:[SI]
	ADD     DH,DL
	ADC     SI,BP
	ADD     [DI],AL
	JNO     SHORT MIX_OS41
	SHR     AL,7
	ADD     AL,7FH
	MOV     [DI],AL
MIX_OS41:
	ADD     [DI+1],AH
	JNO     SHORT MIX_OS42
	SHR     AH,7
	ADD     AH,7FH
	MOV     [DI+1],AH
MIX_OS42:
	ADD     DI,4
	SUB     DH,DL
	ADD     DH,DL
	SBB     BX,BP
	JC      SHORT MIX_ENDS4
	JZ      SHORT MIX_ENDS4
	LOOP    MIX_LOOPS4
MIX_REST4:
	MOV     AX,CS
	MOV     DS,AX
	MOV     SAM_OFL4,DH
	POP     AX CX
	SUB     SI,AX
	PUSH    EAX
	MOVZX   EAX,SI
	ADD     SAM_OFS4,EAX
	POP     EAX
	MOV     SAM_MAX4,BX
	CALL    EMS_RESTORE
GO_BACKS4:
	RET
MIX_ENDS4:
	MOV     CS:SAM_SEG4,0
	JMP     MIX_REST4
MIX_CHANNELS4 ENDP
;-----------------------------------------------------------------------------
; SET EMS-PAGES
; IN:  EAX= EMS-OFFSET
; OUT: ES:DI= SEGMENT & OFFSET IN EMS PAGE
;-----------------------------------------------------------------------------
EMS_PAGING PROC NEAR
	MOV     DI,AX
	AND     DI,3FFFH
	MOV     ES,EMS_SEG
	PUSHA
	PUSH    EAX
	SHR     EAX,14
	MOV     BX,AX
	XOR     AL,AL
	MOV     DX,EMS_HANDLE
	MOV     AH,44H
	INT     67H
	INC     AL
	INC     BX
	MOV     AH,44H
	INT     67H
	INC     AL
	INC     BX
	MOV     AH,44H
	INT     67H
	INC     AL
	INC     BX
	MOV     AH,44H
	INT     67H
	POP     EAX
	POPA
	RET
EMS_PAGING ENDP
;-----------------------------------------------------------------------------
EMS_SAVE PROC NEAR
	PUSH    AX DX
	MOV     DX,EMS_HANDLE           ;EMS MAPPING SICHERN
	MOV     AH,47H
	INT     67H
	POP     DX AX
	RET
EMS_SAVE ENDP
;-----------------------------------------------------------------------------
EMS_RESTORE PROC NEAR
	PUSH    AX DX
	MOV     DX,EMS_HANDLE           ;EMS MAPPING ZURšCKSETZEN
	MOV     AH,48H
	INT     67H
	POP     DX AX
	RET
EMS_RESTORE ENDP
;ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¸
;³ DESCRIPTION: Calculates the values for the mixing multiplication table.   ³
;³              This table is used during 4/8-channel mixing to speed up the ³
;³              operation by avoiding 'mul' instructions.                    ³
;ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¾
MAKE_MIXMUL_VOLUMETABLE PROC NEAR
	MOV     ES,DMA_SEG
	MOV     DI,MIXMUL_OFFSET
	CLD
	XOR     BX,BX                   ; start with volume 0
	INC     BH
VOLUMELOOP:                             ; start with sample 0
SAMPLELOOP:
	MOV     AL,BL
	IMUL    BH
	SAL     AX,1
	OR      AH,AH                   ; ROUND UP
	JNS     SHORT GMK1
	OR      AL,AL
	JZ      SHORT GMK1
	INC     AH
GMK1:   CMP     BH,1
	JA      SHORT GMK2
	XOR     AX,AX
GMK2:   MOV     AL,AH
	STOSB
	INC     BL
	JNZ     SAMPLELOOP
	INC     BH
	CMP     BH,64
	JBE     VOLUMELOOP
	RET
MAKE_MIXMUL_VOLUMETABLE ENDP
;=============================================================================


;=============================================================================
;
; DOS ROUTINEN
;
;=============================================================================
;-----------------------------------------------------------------------------
; TIMER-IRQ-HANDLER: 1024 HZ CALLING FREQUENCE
;-----------------------------------------------------------------------------
TIMER_HANDLER PROC FAR
	PUSH    AX
	
		push	ax es di
		xor	ax,ax
		mov	es,ax
		mov	di,20
		mov	ax,word ptr cs:[Mt_PatternPos]
		stosw
		mov	al,byte ptr cs:[Mt_patternPos+2]
		stosb
		pop	di es ax


	CMP     CS:SYSTEM,0
	JNE     SHORT WT6
	MOV     AL,UHR_STATC
	OUT     UHR_INDEX,AL
	JMP     SHORT WT1
WT1:    JMP     SHORT WT2
WT2:    IN      AL,UHR_PORT
WT6:    MOV     AL,20H
	OUT     IRQ3,AL
	OUT     IRQ1,AL
	STI
	CMP     CS:MOD_STAT,0
	JE      SHORT WT3
	MOV     AX,WORD PTR CS:[BPM_SPEED+2]    ;1024/20.48 = 50 HZ
	ADD     WORD PTR CS:[BPM_COUNT+2],AX
	MOV     AX,WORD PTR CS:[BPM_SPEED]
	ADC     WORD PTR CS:[BPM_COUNT],AX
	JNC     SHORT WT3
	CMP     CS:IRQ_REENTER,0
	JNE     SHORT WT3
	MOV     CS:IRQ_REENTER,1
	PUSHA
	PUSH    DS ES CS
	POP     DS
	CALL    CONTROL_CHANNELS
;       MOV     AH,7
;       CALL    RASTER_COL
	CALL    MIXUP_CHANNELS
;       MOV     AH,0
;       CALL    RASTER_COL
	TEST    SB_MODUS,2
	JZ      SHORT WT5
	MOV     MOD_STAT,4
	JMP     SHORT WT4
WT5:    CMP     MOD_STAT,4
	JB      SHORT WT4
	MOV     MOD_STAT,2
WT4:    POP     ES DS
	POPA
	MOV     CS:IRQ_REENTER,0
WT3:    POP     AX
	CMP     CS:VAR_BUFSEG,0
	JNE     SHORT WT8
	CMP     CS:SYSTEM,0
	JE      SHORT WT7
	DEC     CS:IRQCOUNT
	JNZ     SHORT WT7
	MOV     CS:IRQCOUNT,10;56
WT8:    JMP     DWORD PTR CS:[HOLD70]
WT7:    IRET
TIMER_HANDLER ENDP
;-----------------------------------------------------------------------------
; SOUNDBLASTER-IRQ-HANDLER
;-----------------------------------------------------------------------------
SBIRQ_HANDLER PROC FAR
	PUSH    AX CX DX
	MOV     DX,CS:SB_RSTAT          ;CLEAR IRQ
	IN      AL,DX
	CMP     CS:SBPRO_FLAG,1
	JE      SHORT WUV4
	DEC     DX
	DEC     DX
	MOV     CX,1000H
WUV1:   IN      AL,DX
	OR      AL,AL
	JNS     SHORT WUW1
	LOOP    WUV1
WUW1:   MOV     AL,14H                  ;SB MONO
	OUT     DX,AL
	MOV     CX,1000H
WUV2:   IN      AL,DX                   ;WAIT UNTIL READY
	OR      AL,AL
	JNS     SHORT WUW2
	LOOP    WUV2
WUW2:   MOV     AL,0F0H                 ;SET MAX BLOCK SIZE
	OUT     DX,AL
	MOV     CX,1000H
WUV3:   IN      AL,DX                   ;WAIT UNTIL READY
	OR      AL,AL
	JNS     SHORT WUW3
	LOOP    WUV3
WUW3:   MOV     AL,0FFH
	OUT     DX,AL
WUV4:   MOV     AL,20H
	CMP     CS:IRQ_NUMBER,8
	JB      SHORT WUV5
	OUT     IRQ3,AL
WUV5:   OUT     IRQ1,AL
	POP     DX CX AX
	IRET
SBIRQ_HANDLER ENDP
;-----------------------------------------------------------------------------
; SERVICE IRQ UMLEITUNG; USES THE REAL-TIME-CLOCK IRQ
;-----------------------------------------------------------------------------
IRQ_INIT PROC NEAR
	CLI
	XOR     AX,AX
	MOV     ES,AX
	CMP     SYSTEM,0
	JNE     WU11
	MOV     AX,COMP_SPEED2          ;XCHANGE INIT & STOP DATA FOR DOS
	MOV     DX,COMP_SPEED3
	MOV     COMP_SPEED2,DX
	MOV     COMP_SPEED3,AX
	CMP     VAR_BUFSEG,0
	JNE     SHORT WU13
	MOV     AL,UHR_STATA            ;UHR-IRQ-RATE EINSTELLEN (1024 HZ)
	OUT     UHR_INDEX,AL
	JMP     SHORT WU1
WU1:    JMP     SHORT WU2
WU2:    XCHG    AL,AH
	IN      AL,UHR_PORT
	AND     AL,0F0H
	OR      AL,DL
	XCHG    AL,AH
	OUT     UHR_INDEX,AL
	JMP     SHORT WU3
WU3:    JMP     SHORT WU4
WU4:    XCHG    AL,AH
	OUT     UHR_PORT,AL
	JMP     SHORT WU5
WU5:    JMP     SHORT WU6
WU6:    MOV     AL,UHR_STATB            ;UHR-IRQ-MODUS EINSTELLEN
	OUT     UHR_INDEX,AL
	JMP     SHORT WU7
WU7:    JMP     SHORT WU8
WU8:    XCHG    AL,AH
	IN      AL,UHR_PORT
	AND     AL,08FH
	MOV     DL,DH
	AND     DL,40H
	OR      AL,DL
	XCHG    AL,AH
	OUT     UHR_INDEX,AL
	JMP     SHORT WU9
WU9:    JMP     SHORT WU10
WU10:   XCHG    AL,AH
	OUT     UHR_PORT,AL
	IN      AL,IRQ4                 ;IRQ8 DE-/MASKIEREN
	AND     AL,0FEH
	MOV     DL,DH
	AND     DL,1
	OR      AL,DL
	OUT     IRQ4,AL
WU13:   MOV     DL,DH
	AND     DL,1
	MOV     CL,IRQ_NUMBER
	CMP     CL,8
	JAE     SHORT WU20
	IN      AL,IRQ2                 ;SBIRQ 0-7 DE-/MASKIEREN
	SHL     DL,CL
	MOV     DH,0FEH
	ROL     DH,CL
	AND     AL,DH
	OR      AL,DL
	OUT     IRQ2,AL
	JMP     SHORT WU21
WU20:   SUB     CL,8                    ;SBIRQ 8-15 DE-/MASKIEREN
	IN      AL,IRQ4
	SHL     DL,CL
	MOV     DH,0FEH
	ROL     DH,CL
	AND     AL,DH
	OR      AL,DL
	OUT     IRQ4,AL
WU21:   MOV     BX,4*70H                ;UHR-IRQ VERBIEGEN
	MOV     EAX,ES:[BX]
	MOV     EDX,HOLD70
	MOV     ES:[BX],EDX
	MOV     HOLD70,EAX
	JMP     WU12
WU11:   CMP     VAR_BUFSEG,0
	JNE     SHORT WU14
	MOV     AX,COMP_SPEED4          ;FOR WINDOWS
	MOV     DX,COMP_SPEED5
	MOV     COMP_SPEED4,DX
	MOV     COMP_SPEED5,AX
	MOV     AL,00110110B            ;TIMER0 AUF 1.024 KHZ EINSTELLEN
	OUT     PIT1,AL                 ;TEILER=1193
	MOV     AL,DL
	OUT     TIMER0,AL
	JMP     SHORT OUT40
OUT40:  MOV     AL,DH
	OUT     TIMER0,AL
WU14:   MOV     AX,COMP_SPEED2          ;XCHANGE INIT & STOP DATA FOR DOS
	MOV     DX,COMP_SPEED3
	MOV     COMP_SPEED2,DX
	MOV     COMP_SPEED3,AX
	MOV     DL,DH
	AND     DL,1
	MOV     CL,IRQ_NUMBER
	CMP     CL,8
	JAE     SHORT WU30
	IN      AL,IRQ2                 ;SBIRQ 0-7 DE-/MASKIEREN
	SHL     DL,CL
	MOV     DH,0FEH
	ROL     DH,CL
	AND     AL,DH
	OR      AL,DL
	OUT     IRQ2,AL
	JMP     SHORT WU31
WU30:   SUB     CL,8
	IN      AL,IRQ4                 ;SBIRQ 8-15 DE-/MASKIEREN
	SHL     DL,CL
	MOV     DH,0FEH
	ROL     DH,CL
	AND     AL,DH
	OR      AL,DL
	OUT     IRQ4,AL
WU31:   MOV     BX,4*8H                 ;TIMEOUT-IRQ VERBIEGEN
	MOV     EAX,ES:[BX]
	MOV     EDX,HOLD70
	MOV     ES:[BX],EDX
	MOV     HOLD70,EAX
WU12:   MOVZX   BX,CL                   ;SOUNDBLASTER-IRQ VERBIEGEN
	ADD     BX,08H
	CMP     IRQ_NUMBER,8
	JB      SHORT WU40
	ADD     BX,68H
WU40:   SHL     BX,2
	MOV     EAX,ES:[BX]
	MOV     EDX,HOLDSB
	MOV     ES:[BX],EDX
	MOV     HOLDSB,EAX
	MOV     AL,20H
	OUT     IRQ3,AL
	OUT     IRQ1,AL
	STI
	RET
IRQ_INIT ENDP
;----------------------------------------------------------------------------
; RESERVIERT SPEICHER FšR TRACKS, CARRY-FLAG 0=OK 1=ABBRUCH
;----------------------------------------------------------------------------
SET_TMEM PROC NEAR
	MOV     AH,48H
	MOV     BX,1000H                ;64K TRACK BUFFER (WIRD RESIZED)
	INT     21H
	JC      SHORT STCM1
	MOV     TRACK_SEG,AX
	MOV     AH,48H
	MOV     BX,80H                  ;2K PATTERN BUFFER
	INT     21H
	JC      SHORT STCM1
	MOV     PATTERN_SEG,AX
STCM1:  RET
SET_TMEM ENDP
;----------------------------------------------------------------------------
; GIBT SPEICHER VON TRACKS WIEDER FREI
;----------------------------------------------------------------------------
FREE_TMEM PROC NEAR
	MOV     AX,SAMPLE_SEG
	MOV     ES,AX
	MOV     AH,49H
	INT     21H
	MOV     AX,TRACK_SEG
	MOV     ES,AX
	MOV     AH,49H
	INT     21H
	RET
FREE_TMEM ENDP
;----------------------------------------------------------------------------
; RESERVIERT SPEICHER FšR DMA_BUFFER & MIXMUL_TABLE, CARRY 0=OK 1=ABBRUCH
;----------------------------------------------------------------------------
SET_DMEM PROC NEAR
	MOV     AH,48H
	MOV     BX,0600H                ;24K BUFFER
	INT     21H
	JC      SHORT SDCM1
	MOV     DMA_SEG,AX
	MOV     DMA_OFFSET,0            ;DMA_BUFFER CA.  8K
	MOV     MIXMUL_OFFSET,2000H     ;MIXMUL_TAB CA. 16K
	AND     AX,0FFFH                ;ES IST DARAUF ZU ACHTEN, DASS
	CMP     AX,0E00H                ;DER DMA_BUFFER VOLLSTŽNDIG IN
	JB      SHORT SDCM2             ;EINER PAGE LIEGT
	MOV     DMA_OFFSET,4000H
	MOV     MIXMUL_OFFSET,0
SDCM2:  CLC
SDCM1:  RET
SET_DMEM ENDP
;----------------------------------------------------------------------------
; GIBT SPEICHER VON DMA & MIXMUL_VOLUMETABLE WIEDER FREI
;----------------------------------------------------------------------------
FREE_DMEM PROC NEAR
	MOV     AX,DMA_SEG
	MOV     ES,AX
	MOV     AH,49H
	INT     21H
	RET
FREE_DMEM ENDP
;-----------------------------------------------------------------------------
FREE_MEM PROC NEAR
	MOV     BX,PROG_END_SEG         ;SPEICHER FREI MACHEN
	SUB     BX,PROG_START_SEG
	MOV     ES,PROG_START_SEG
	MOV     AH,4AH                  ;SPEICHERBLOCKGR™SSE ŽNDERN
	INT     21H
	RET
FREE_MEM ENDP
;=============================================================================


;=============================================================================
;
; SOUNDBLASTER HARDWARE ROUTINEN
;
;=============================================================================
; SET MIXER IF PRESENT
;-----------------------------------------------------------------------------
MIXER_INIT PROC NEAR
	MOV     DX,SBP_MIXERI
	MOV     AL,22H
	OUT     DX,AL
	INC     DX
	MOV     AL,255                  ;MAX MASTERVOLUME
	OUT     DX,AL
	DEC     DX
	MOV     AL,4
	OUT     DX,AL
	INC     DX
	MOV     AL,255                  ;MAX DSPVOLUME
	OUT     DX,AL
	DEC     DX
	MOV     AL,0EH
	OUT     DX,AL
	INC     DX
	MOV     AL,0H                   ;FILTER & MONO
	MOV     SBPRO_FLAG,AL
	CMP     SB_TYP,1                ;SBPRO ENABLED?
	JE      SHORT GMIX1
	MOV     SBPRO_FLAG,1
	MOV     AL,2H                   ;FILTER & STEREO
GMIX1:  OUT     DX,AL
	RET
MIXER_INIT ENDP
;-----------------------------------------------------------------------------
; SET DMA READY FOR TRANSFER WITH AUTOINIT
; IN: DX:BX= BLOCKPOINTER, CX= SIZE
;-----------------------------------------------------------------------------
DMA_INIT PROC NEAR
	MOV     AX,DX                   ;ADRESSE IN PAGE UND OFFSET UMRECHNEN
	SHL     DX,4
	SHR     AH,4                    ;PAGE
	ADD     BX,DX                   ;OFFSET NEU
	ADC     AH,0
	MOV     DMA_PAGE,AH
	MOV     DMA_POFF,BX
	DEC     CX                      ;DMA SIZE= BLOCK SIZE -1
	MOV     AL,DMA_CHANNEL
	OR      AL,4
	OUT     0AH,AL                  ;DMA-KANAL MASKIEREN
	AND     AL,3
	OR      AL,01011000B
	OUT     0BH,AL                  ;DMA-MODUS FšR SB
	OUT     0CH,AL                  ;FLIP-FLOP L™SCHEN
	AND     AL,3
	MOVZX   DX,AL
	SHL     DL,1
	MOV     AL,BL                   ;DMA CHANNEL 1-4
	OUT     DX,AL                   ;OFFSET LOW
	MOV     AL,BH
	OUT     DX,AL                   ;OFFSET HIGH
	INC     DL
	MOV     AL,CL
	OUT     DX,AL                   ;SIZE LOW
	MOV     AL,CH
	OUT     DX,AL                   ;SIZE HIGH
	MOV     BX,DX
	SHR     BL,1
	MOV     DL,[DMA_DATA+BX]
	MOV     AL,AH
	OUT     DX,AL                   ;PAGE
	MOV     AL,BL
	OUT     0AH,AL                  ;DMA-KANAL DEMASKIEREN
	RET
DMA_INIT ENDP
;-----------------------------------------------------------------------------
; DSP SET SAMPLE RATE
; IN: AH= RATE (= 256-(1000000/FREQ))
;-----------------------------------------------------------------------------
DSP_RATE PROC NEAR
	CMP     SB_VERSION,4
	JAE     SHORT GDSPR1
	PUSH    AX
	MOV     AH,40H
	CALL    DSP_WRITE
	POP     AX
	CALL    DSP_WRITE
	RET
GDSPR1: MOV     AH,41H                  ;DSP 4.0 (SB16)
	CALL    DSP_WRITE
	MOV     AX,SAMPLE_RATE
	CALL    DSP_WRITE
	MOV     AX,SAMPLE_RATE
	MOV     AH,AL
	CALL    DSP_WRITE
	RET
DSP_RATE ENDP
;-----------------------------------------------------------------------------
; DSP OUT BLOCK
;-----------------------------------------------------------------------------
DSP_OUT PROC NEAR
	CMP     SBPRO_FLAG,1
	JE      SHORT GDSP1
	MOV     AH,14H                  ;MONO DMA-AUSGABE NEU STARTEN
	CALL    DSP_WRITE               ;ONE CYCLE= 14H, AUTOINIT= 48H,..,1CH
	MOV     AH,0F0H                 ;SIZE LOW
	CALL    DSP_WRITE
	MOV     AH,0FFH                 ;SIZE HIGH
	CALL    DSP_WRITE
	RET
GDSP1:  CMP     SB_VERSION,4
	JAE     SHORT GDSP2
	MOV     AH,48H                  ;STEREO DMA-AUSGABE NEU STARTEN
	CALL    DSP_WRITE
	MOV     AH,0F0H                 ;SIZE LOW
	CALL    DSP_WRITE
	MOV     AH,0FFH                 ;SIZE HIGH
	CALL    DSP_WRITE
	MOV     AH,90H                  ;START MIT AUTOINIT PCM= 90H
	CALL    DSP_WRITE               ;         ONE CYCLE PCM= 91H
	RET
GDSP2:  MOV     AH,0C6H                 ;8 BIT PCM, AUTOINIT FOR DSP 4.0
	CALL    DSP_WRITE
	MOV     AH,20H                  ;STEREO UNSIGNED
	CALL    DSP_WRITE
	MOV     AH,0F0H                 ;SIZE LOW
	CALL    DSP_WRITE
	MOV     AH,0FFH                 ;SIZE HIGH
	CALL    DSP_WRITE
	RET
DSP_OUT ENDP
;-----------------------------------------------------------------------------
; DSP RESET
; OUT: CARRY 1= FAILURE
;-----------------------------------------------------------------------------
DSP_RESET PROC NEAR
	CALL    DSP_OFF
	OUT     0DH,AL                  ;DMA MASTER CLEAR
	CALL    MIXER_INIT
	MOV     DX,SB_RESET
	MOV     AL,1
	OUT     DX,AL                   ;SEND RESET COMMAND
	MOV     CX,4
	CALL    WAIT_TIME               ;WAIT
	XOR     AL,AL
	OUT     DX,AL                   ;CLEAR RESET COMMAND
	MOV     CX,120
	CALL    WAIT_TIME               ;WAIT
	MOV     DX,SB_RSTAT
	IN      AL,DX                   ;CHECK IF SUCCESSFUL
	OR      AL,AL
	JNS     SHORT GDRES1
	MOV     DX,SB_READ
	IN      AL,DX
	CMP     AL,0AAH
	JNE     SHORT GDRES1
	MOV     AH,0E1H                 ;GET DSP VERSION
	CALL    DSP_WRITE
	CALL    DSP_READ
	MOV     SB_VERSION,AL
	CALL    DSP_READ
	CALL    DSP_ON
	CLC                             ;RESET OK
	RET
GDRES1: STC                             ;RESET FAILURE
	RET
DSP_RESET ENDP
;-----------------------------------------------------------------------------
; LAUTSPRECHER EIN
;-----------------------------------------------------------------------------
DSP_ON PROC NEAR
	MOV     AH,0D1H                 ;SPEAKER ON
	CALL    DSP_WRITE
	MOV     CX,120
	CALL    WAIT_TIME               ;WAIT
	RET
DSP_ON ENDP
;-----------------------------------------------------------------------------
; LAUTSPRECHER AUS
;-----------------------------------------------------------------------------
DSP_OFF PROC NEAR
	PUSH    CS
	POP     DS
	CMP     SB_TYP,1
	JNE     SHORT GDSPF1            ;SB
	MOV     AL,DMA_CHANNEL          ;DMA DEMASKIEREN
	OUT     0AH,AL
	MOV     AH,0D0H                 ;DMA AUSGABE STOPPEN
	CALL    DSP_WRITE
	MOV     AH,0D3H                 ;DSP OFF
	CALL    DSP_WRITE
	MOV     CX,240
	CALL    WAIT_TIME               ;WAIT
	RET
GDSPF1: MOV     DX,SBP_MIXERI           ;SBPRO
	CMP     LOADMOD_FLAG,0
	JNE     SHORT GDSPF2
	MOV     AL,22H                  ;AUSGEBAUT WEGEN CD UNTERBRECHUNG
	OUT     DX,AL
	INC     DX
	MOV     AL,0                    ;MIN MASTERVOLUME
	OUT     DX,AL
	DEC     DX
GDSPF2: MOV     AL,4
	OUT     DX,AL
	INC     DX
	MOV     AL,0                    ;MIN DSPVOLUME
	OUT     DX,AL
	MOV     DX,SB_RESET
	MOV     AL,1
	OUT     DX,AL                   ;SEND RESET COMMAND
	MOV     CX,4
	CALL    WAIT_TIME               ;WAIT
	XOR     AL,AL
	OUT     DX,AL                   ;CLEAR RESET COMMAND
	MOV     CX,120
	CALL    WAIT_TIME               ;WAIT
	MOV     AH,0D3H                 ;DSP OFF
	CALL    DSP_WRITE
	MOV     CX,240
	CALL    WAIT_TIME
	RET
DSP_OFF ENDP
;-----------------------------------------------------------------------------
; READ BYTE
; OUT: AL= BYTE
;-----------------------------------------------------------------------------
DSP_READ PROC NEAR
	MOV     DX,SB_READ
	MOV     CX,-1                   ;FAIL SAFE
LDRD1:  IN      AL,DX
	CMP     AL,0AAH
	JNE     SHORT LDRD2
	LOOP    LDRD1
LDRD2:  RET
DSP_READ ENDP
;-----------------------------------------------------------------------------
; WRITE BYTE
; IN: AH= BYTE
;-----------------------------------------------------------------------------
DSP_WRITE PROC NEAR
	MOV     DX,SB_WRITE
	MOV     CX,1000H                ;FAIL SAFE
LDWR1:  IN      AL,DX
	OR      AL,AL
	JNS     SHORT LDWR2
	LOOP    LDWR1
LDWR2:  MOV     AL,AH
	OUT     DX,AL
	RET
DSP_WRITE ENDP
;-----------------------------------------------------------------------------
; WAIT TIME
; CX = XXX MILLISECONDS
;-----------------------------------------------------------------------------
WAIT_TIME PROC NEAR
	PUSH    AX BX EDX
LWT1:   IN      AL,TIMER0
	MOV     BL,AL
	IN      AL,TIMER0
	MOV     BH,AL
	MOV     EDX,500000              ;FAIL SAFE
LWT2:   IN      AL,TIMER0               ;1 MILLISEC WARTEN
	XCHG    AL,AH
	IN      AL,TIMER0
	XCHG    AL,AH
	SUB     AX,BX
	NEG     AX
	DEC     EDX
	JZ      SHORT LWT3
	CMP     AX,1193
	JB      LWT2
LWT3:   LOOP    LWT1
	POP     EDX BX AX
	RET
WAIT_TIME ENDP
;=============================================================================


;=============================================================================
;
; MOD LADEROUTINEN
;
;=============================================================================
; LŽDT EIN MODFILE
; DS:DX= FILENAME
;-----------------------------------------------------------------------------
SegMod  dw      0
OffMod  dd      0
LOAD_MOD PROC NEAR
ifdef zpliku ;comment #
	MOV     AX,3D00H                ;OPEN MOD
	INT     21H
	JC      GLDM1
	PUSH    CS
	POP     DS
	MOV     GDDHANDLE,AX
else ;#
	mov     cs:[segMod],ds
	mov     cs:[offmod],edx
	push    cs
	pop     ds
endif
GLDM0:  CALL    SET_DMEM                ;ALLOCATE DMA-BUFFER
	CALL    SET_TMEM                ;ALLOCATE TRACK-BUFFER
	MOV     BX,GDDHANDLE
	MOV     GDDZEIG,0
	CMP     LOADMOD_FLAG,0
	JNE     GLDM99
	MOV     CX,10                   ;SONG-NAME HOLEN
LLDM1:  CALL    GET_QUEUE
	JC      GLDM2
	LOOP    LLDM1
	MOV     SAMPLE_SIZE,0
	XOR     SI,SI                   ;31 INSTRUMENTS
LLDM2:  MOV     AX,SAMPLE_SIZE
	MOV     [SAMPLE_SEG+SI],AX
	MOV     CX,11                   ;INSTRUMENT NAME
LLDM3:  CALL    GET_QUEUE
	JC      GLDM2
	LOOP    LLDM3
	XOR     EAX,EAX
	CALL    GET_QUEUE               ;INSTRUMENT SIZE
	XCHG    AL,AH
	CMP     AX,2
	JAE     SHORT GLDM20
	XOR     AX,AX
GLDM20: SHL     AX,1
	MOV     [ISIZE+SI],AX           ;H™CHSTENS 64K
	OR      EAX,EAX
	JZ      SHORT GLDM9
	SHR     EAX,4
	INC     AX
	ADD     SAMPLE_SIZE,AX
GLDM9:  CALL    GET_QUEUE               ;IVOLUME & FINETUNE
	XCHG    AL,AH
	MOV     [IVOL_FINETUNE+SI],AX
	CALL    GET_QUEUE               ;ILOOP_START
	XCHG    AL,AH
	SHL     AX,1
	MOV     [ILOOP_START+SI],AX
	CALL    GET_QUEUE               ;ILOOP_SIZE
	XCHG    AL,AH
	SHL     AX,1
	MOV     [ILOOP_SIZE+SI],AX
	INC     SI
	INC     SI
	CMP     SI,62
	JB      LLDM2
	CALL    GET_QUEUE               ;SONG_SIZE & LOOP_BYTE OR NOTHING
	JC      GLDM2
	MOV     SONG_SIZE,AL
	MOV     SONG_LOOP,AH
	XOR     DX,DX
	MOV     CX,64                   ;SONG_DATA
	MOV     DI,OFFSET SONG_DATA
LLDM4:  CALL    GET_QUEUE
	JC      GLDM2
	MOV     [DI],AX
	CMP     AL,DL                   ;FIND HIGHEST PATTERN NUMBER
	JBE     SHORT GLDM12
	MOV     DL,AL
GLDM12: CMP     AH,DL
	JBE     SHORT GLDM13
	MOV     DL,AH
GLDM13: INC     DI
	INC     DI
	LOOP    LLDM4
	INC     DL
	CLD
	MOV     PATTERN_NUMBER,DX
	CALL    GET_QUEUE
	PUSH    AX
	CALL    GET_QUEUE
	SHL     EAX,16
	POP     AX
	MOV     MOD_SIGN,EAX
	CMP     EAX,"NHC8"              ;8CHN-MOD
	JE      SHORT GLDM3
	CMP     EAX,"8TLF"              ;FLT8-MOD
	JE      SHORT GLDM3
	CMP     EAX,".K.M"              ;M.K.-MOD
	JE      SHORT GLDM10
	CMP     EAX,"4TLF"              ;FLT4-MOD
	JNE     GLDM2

GLDM10: MOV     CH_NUMB,4               ;4-CHANNEL-MOD
	MOV     PATTERN_SIZE,1024
	MOV     AH,0
	MOV     TRACK_INFO+4,AH
	MOV     TRACK_INFO+5,AH
	MOV     TRACK_INFO+6,AH
	MOV     TRACK_INFO+7,AH
	JMP     SHORT GLDM11
GLDM3:  MOV     CH_NUMB,8               ;8-CHANNEL-MOD: GET-PATTERNS
	MOV     PATTERN_SIZE,2048
GLDM11: MOV     PATTERN_CURRENT,0
	MOV     TRACK_NUMBER,0
LLDM7:  MOV     ES,PATTERN_SEG
	MOV     BX,GDDHANDLE
	XOR     DI,DI
LLDM6:  XOR     SI,SI
LLDM5:  CALL    GET_QUEUE               ;PATTERN HOLEN UND IN TRACKS AUFSPALTEN
	JC      GLDM2
	MOV     DX,AX
	CALL    GET_QUEUE
	JC      GLDM2
	ROL     AL,4                    ;MODIFY PATTERN DATA
	MOV     CL,AL                   ;LOOK AT PROTRACKER-CODE HEADER
	AND     AL,0FH
	AND     CL,0F0H
	MOV     CH,DL
	AND     DL,0FH
	AND     CH,0F0H
	OR      AL,CH
	OR      DL,CL
	XCHG    DL,DH
	PUSH    DI
	ADD     DI,SI
	SHL     EAX,16
	MOV     AX,DX
	STOSD
	POP     DI
	ADD     SI,256
	CMP     SI,PATTERN_SIZE         ;NEXT TRACK/CHANNEL
	JB      LLDM5
	ADD     DI,4                    ;NEXT NOTE
	CMP     DI,256
	JB      LLDM6
	CALL    SET_FREQUENCIES
	MOV     ES,TRACK_SEG            ;TRACK1-8 INTEGRIEREN
	MOV     DX,TRACK_NUMBER
	XCHG    DL,DH
	MOV     DS,PATTERN_SEG
	XOR     SI,SI
	XOR     BX,BX
LLDM8:  XOR     DI,DI
LLDM9:  CMP     DX,DI
	JBE     SHORT GLDM4
	PUSH    SI DI
	MOV     CX,256/4
	REPE CMPSD                      ;TRACK ALREADY EXISTS?
	POP     DI SI
	PUSHF
	ADD     DI,256
	POPF
	JNE     LLDM9
	JMP     SHORT GLDM5
GLDM4:  INC     DH                      ;NO, ADD TRACK TO BUFFER
	PUSH    SI
	MOV     CX,256/4
	REP MOVSD
	POP     SI
GLDM5:  MOV     AX,DI                   ;YES
	DEC     AH
	MOV     CS:[TRACK_INFO+BX],AH
	INC     BX
	ADD     SI,256
	CMP     BX,CS:CH_NUMB
	JB      LLDM8
	PUSH    CS
	POP     DS
	XCHG    DL,DH
	MOV     TRACK_NUMBER,DX
	XOR     BX,BX                   ;TRACKLISTE NACHFšHREN
	MOV     AX,PATTERN_CURRENT
LLDM10: CMP     [SONG_DATA+BX],AL
	JNE     SHORT GLDM6
	MOV     AH,TRACK_INFO
	MOV     [TRACK1_DATA+BX],AH
	MOV     AH,TRACK_INFO+1
	MOV     [TRACK2_DATA+BX],AH
	MOV     AH,TRACK_INFO+2
	MOV     [TRACK3_DATA+BX],AH
	MOV     AH,TRACK_INFO+3
	MOV     [TRACK4_DATA+BX],AH
	MOV     AH,TRACK_INFO+4
	MOV     [TRACK5_DATA+BX],AH
	MOV     AH,TRACK_INFO+5
	MOV     [TRACK6_DATA+BX],AH
	MOV     AH,TRACK_INFO+6
	MOV     [TRACK7_DATA+BX],AH
	MOV     AH,TRACK_INFO+7
	MOV     [TRACK8_DATA+BX],AH
GLDM6:  INC     BX
	CMP     BL,128
	JB      LLDM10
	INC     PATTERN_CURRENT         ;NŽCHSTES PATTERN HOLEN
	MOV     AX,PATTERN_CURRENT
	CMP     AX,PATTERN_NUMBER
	JB      LLDM7
	JMP     SHORT GLDM7

GLDM99: MOV     ES,TRACK_SEG            ;PATTERN SEGMENT WIEDER L™SCHEN
	MOV     AH,49H
	INT     21H
GLDM7:  MOV     ES,PATTERN_SEG          ;PATTERN SEGMENT WIEDER L™SCHEN
	MOV     AH,49H
	INT     21H
	CMP     LOADMOD_FLAG,0
	JNE     SHORT GLDM98
	MOV     BX,TRACK_NUMBER         ;TRACK SEGMENT REDUZIEREN
	SHL     BX,4
	MOV     ES,TRACK_SEG
	MOV     AH,4AH
	INT     21H
	MOV     BX,SAMPLE_SIZE          ;SAMPLE SEGMENT ALLOKIEREN
	MOV     AH,48H
	INT     21H
	XOR     BX,BX
LLDM11: ADD     [SAMPLE_SEG+BX],AX
	INC     BX
	INC     BX
	CMP     BX,62
	JB      LLDM11
	MOV     BX,GDDHANDLE
	XOR     SI,SI                   ;SAMPLES LADEN
LLDM12: MOV     CX,[ISIZE+SI]
	MOV     ES,[SAMPLE_SEG+SI]
	XOR     DI,DI
	SHR     CX,1
	JCXZ    SHORT GLDM8
LLDM13: CALL    GET_QUEUE
	STOSW
	LOOP    LLDM13
GLDM8:  INC     SI
	INC     SI
	CMP     SI,62
	JB      LLDM12
GLDM98: CLC
	JMP     SHORT GLDM15
GLDM2:  STC
GLDM15: PUSHF
	CMP     VAR_BUFSEG,0
	JNE     SHORT GLDM16
ifdef zpliku;comment #
	MOV     AH,3EH
	INT     21H
endif;#
GLDM16: POPF
GLDM1:  RET
LOAD_MOD ENDP
;-----------------------------------------------------------------------------
; ERSETZT DIE MEISTEN FREQUENZ-PERIODEN DURCH DEN TABELLEN-INDEX
;-----------------------------------------------------------------------------
SET_FREQUENCIES PROC NEAR
	XOR     DI,DI
SET_FREQ1:
	MOV     AX,ES:[DI]              ;get fx
	MOV     DX,AX
	SHR     AH,4
	CMP     AH,3
	JE      SHORT SET_FREQ4
	CMP     AH,5
	JE      SHORT SET_FREQ4
	MOV     AX,DX
	AND     AX,0FFFH                ; Mask out unwanted bits.
	JZ      SHORT SET_FREQ4
	XOR     BX,BX
	MOV     CX,48                   ; 36 periods to cycle through.
SET_FREQ2:
	CMP     AX,[MT_PERIODTABLE+BX]  ; Check the note against the period.
	JAE     SHORT SET_FREQ3         ; We found it!
	INC     BX                      ; Otherwise, update the pointer and
	INC     BX
	LOOP    SET_FREQ2               ; keep looping.
SET_FREQ3:
	MOV     AX,DX                   ;recall the Note Value
	AND     AX,0F000H               ;just keep fx
	INC     BX
	OR      AX,BX                   ;put in the new offset
	STOSW                           ;store it
	DEC     DI
	DEC     DI
SET_FREQ4:
	ADD     DI,4                    ;and go to next channel
	CMP     DI,PATTERN_SIZE
	JB      SET_FREQ1
	RET
SET_FREQUENCIES ENDP
;-----------------------------------------------------------------------------
; HOLT EIN WORD AUS DEM BUFFER
; IN: AX= WORD, BX= HANDLE
;-----------------------------------------------------------------------------
GET_QUEUE PROC NEAR
	CMP     GDDZEIG,0
	JNE     SHORT GTQ1
ifdef zpliku;comment #
	PUSH    CX DX
	MOV     DX,OFFSET QUEUE_BUFFER
	MOV     CX,256
	MOV     AH,3FH
	INT     21H
	MOV     GDDREST,AX
	POP     DX CX
else;#
	pushf
	cld
	pushad
	push    es
	MOV     edi,OFFSET QUEUE_BUFFER
	MOV     ecx,256
	push    ds
	pop     es
	mov     ds,cs:[SegMod]
	mov     esi,cs:[OffMod]
	rep
	db      67h
	movsb
	push    es
	pop     ds
	mov     cs:[offmod],esi
	MOV     GDDREST,256
	pop     es
	popad
	popf
endif
GTQ1:   PUSH    BX
	MOV     BL,GDDZEIG
	XOR     BH,BH
	CMP     BX,GDDREST
	JAE     SHORT GTQ2
	MOV     AX,[QUEUE_BUFFER+BX]
	ADD     GDDZEIG,2
	POP     BX
	CLC
	RET
GTQ2:   POP     BX
	STC
	RET
GET_QUEUE ENDP
;=============================================================================
; LOAD CONFIG DATA (PARSER)
; IN: CX=0C242H, DS:BX= POINTER TO PARAM-BLOCK
;
; PARAM-BLOCK:  + 0 BASE PORT           210H-280H, 388H, ETC.
;               + 2 DMA NUMBER          0-7
;               + 3 IRQ NUMBER          0-15
;               + 4 SAMPLE RATE         10000-44100
;               + 6 INTERNAL TYPE       0,1,2,3,... (if necessary);1=SB,2=SBPRO,3=GUS,4=AWE32
;               + 7 INTERRUPT TYPE      0,1 (realtime clock, timer);timer
;               + 8 STARTING POSITION   0-127
;               + 9 LOOP POSITION       0-127,128
;               +10 SONG MODUS          0-3             ;to znaczy na 1 bo tylkko muzyka
;               +11 START MASTER VOLUME 0-255
;               +12 START MUSIC VOLUME  0-255
;               +13 START FX VOLUME     0-255
;-----------------------------------------------------------------------------
CONFIG_INIT PROC NEAR
	MOV     DX,DS
	MOV     AX,CS
	MOV     DS,AX
	MOV     WORD PTR HOLD70+2,AX
	MOV     WORD PTR HOLDSB+2,AX
	CMP     CX,0C242H
	JNE     SHORT NORMAL_CONFIG
	MOV     ES,DX
	MOV     AX,ES:[BX]
	ADD     AL,4
	MOV     SBP_MIXERI,AX
	INC     AX
	MOV     SBP_MIXERD,AX
	INC     AX
	MOV     SB_RESET,AX
	ADD     AX,4
	MOV     SB_READ,AX
	ADD     AX,2
	MOV     SB_WRITE,AX
	ADD     AX,2
	MOV     SB_RSTAT,AX
	MOV     AL,ES:[BX+2]
	AND     AL,7
	MOV     DMA_CHANNEL,AL
	MOV     AL,ES:[BX+3]
	AND     AL,15
	MOV     IRQ_NUMBER,AL
	MOV     AX,ES:[BX+4]
	MOV     SAMPLE_RATE,AX
	MOV     AL,ES:[BX+6]
	AND     AL,1
	INC     AL
	MOV     SB_TYP,AL
	MOV     AL,ES:[BX+7]
	AND     AL,1
	MOV     SYSTEM,AL
	MOV     AL,ES:[BX+8]
	AND     AL,127
	MOV     SONG_START,AL
	MOV     AL,ES:[BX+9]
	MOV     SONG_LOOP,AL
	MOV     AL,ES:[BX+10]
	AND     AL,3
	MOV     SB_MODUS,AL
	MOV     AL,ES:[BX+11]
	MOV     BX,ES:[BX+12]
	CALL    SET_VOLUME
	JMP     CONT_CONFIG
NORMAL_CONFIG:
CONT_CONFIG:
	RET
CONFIG_INIT ENDP

;=============================================================================
PLAY_MUSIC PROC NEAR
	PUSH    CS
	POP     DS
	MOV     MOD_STAT,0              ;DEACTIVATE IRQ-HANDLING
	CALL    DSP_RESET
	JC      GPM1
	CALL    MAKE_MIXMUL_VOLUMETABLE
	CALL    IRQ_INIT
	XOR     EDX,EDX
	MOV     EAX,1000000
	MOVZX   EBX,SAMPLE_RATE
	MOV     CL,SBPRO_FLAG
	DIV     EBX
	SHR     AL,CL
	NEG     AL
	MOV     DMA_RATE,AL
	XOR     EDX,EDX
	MOV     EAX,369E9400H           ;1,193,180 * 300H FOR FREQ CALCS
	DIV     EBX
	MOV     MAINFREQ,EAX
	MOV     AX,BX
	XOR     DX,DX
	MOV     BX,50                   ;AMIGA TIMING IS 50HZ (SCREEN-REFRESH)
	DIV     BX
	SHL     AX,CL
	MOV     DMA_CX,AX               ;# OF BYTE/CYCLE (434 FOR 22222 HZ)
	SHL     AX,2                    ;4 TIMES FORWARD
	MOV     DMA_MORE,AX
	SHL     AX,2                    ;16 TIMES MAXIMUM (6944 FOR 22222 HZ)
	SHR     AX,CL
	SUB     AH,CL
	SUB     AH,CL
	MOV     DMA_MAX,AX
	MOV     AX,DMA_OFFSET
	MOV     DMA_PTR,AX
	MOV     DMA_NEWPTR,AX
	MOV     AL,125
	CALL    Go_SetBPM
	MOV     BPM_COUNT,0
	MOV     MT_SPEED,6              ;DEFAULT PROTRACKER SPEED
	XOR     AX,AX
	MOV     MT_COUNTER,AL           ;RESET PROTRACKER VARIABLES
	MOV     MT_PATTERNPOS,AX
	MOV     DL,SONG_START
	MOV     MT_SONGPOS,DL
	MOV     MT_PATTDELAYTIME2,AL
	MOV     MT_PATTDELAYTIME,AL
	MOV     MT_PBREAKFLAG,AL
	MOV     MT_PBREAKPOS,AL
	MOV     MT_POSJUMPFLAG,AL
	MOV     MT_LOWMASK,0FFH
	MOV     CX,43*8/2
	CLD
	PUSH    DS
	POP     ES
	MOV     DI,OFFSET NOTE
	REP STOSW
	INC     AL
	MOV     CX,MAX_CHAN_NUMB
	MOV     DI,OFFSET TONEPORTDIREC
	REP STOSB
	MOV     BYTE PTR SELFN1+2,2
	MOV     BYTE PTR SELFN2+2,2
	MOV     BYTE PTR SELFN3+2,2
	MOV     BYTE PTR SELFN4+2,2
	TEST    SBPRO_FLAG,1
	JZ      SHORT GPM2
	MOV     BYTE PTR SELFN1+2,4
	MOV     BYTE PTR SELFN2+2,4
	MOV     BYTE PTR SELFN3+2,4
	MOV     BYTE PTR SELFN4+2,4
GPM2:   MOV     CX,3                    ;PRECALCULATE SAMPLE DATA FOR INIT
LPM1:   PUSH    CX
	CALL    CONTROL_CHANNELS
	CALL    MIXUP_CHANNELS
	POP     CX
	LOOP    LPM1
	MOV     AH,DMA_RATE             ;SET SB-SAMPLERATE
	CALL    DSP_RATE
	MOV     DX,DMA_SEG              ;INITIALIZE DMA
	MOV     BX,DMA_OFFSET
	MOV     CX,DMA_MAX
	CALL    DMA_INIT
	MOV     MOD_STAT,1              ;ACTIVATE IRQ-HANDLING
	CLC
GPM1:   RET
PLAY_MUSIC ENDP
;-----------------------------------------------------------------------------
STOP_MUSIC PROC NEAR
	PUSH    CS
	POP     DS
	MOV     MOD_STAT,0
	CALL    DSP_RESET
	CALL    IRQ_INIT
	MOV     IRQCOUNT,10;56
	RET
STOP_MUSIC ENDP
;-----------------------------------------------------------------------------
END_MUSIC PROC NEAR
	PUSH    CS
	POP     DS
	CMP     LOADMOD_FLAG,0
	JNE     SHORT GENM1
	CALL    FREE_TMEM
GENM1:  CALL    FREE_DMEM
	RET
END_MUSIC ENDP
comment #
;-----------------------------------------------------------------------------
GET_SONGMOD PROC NEAR
	MOV     AL,CS:SB_MODUS
	RET
GET_SONGMOD ENDP
;-----------------------------------------------------------------------------
SET_SONGMOD PROC NEAR
	AND     AL,3
	MOV     CS:SB_MODUS,AL
	CMP     CS:SBPRO_FLAG,1
	JNE     SHORT GSNG1
	CMP     CS:CD_MIXER,0
	JE      SHORT GSNG1
	PUSH    AX DX
	XOR     AH,AH
	TEST    AL,2
	JNZ     SHORT GSNG2
	MOV     AH,CS:MUSIC_VOL
GSNG2:  MOV     DX,CS:SBP_MIXERI
	MOV     AL,28H
	OUT     DX,AL
	INC     DX
	MOV     AL,AH                   ;SET CD VOLUME LEFT
	AND     AL,0F0H
	SHR     AH,4
	OR      AL,AH                   ;SET CD VOLUME RIGHT
	OUT     DX,AL
	POP     DX AX
GSNG1:  RET
SET_SONGMOD ENDP
#
;-----------------------------------------------------------------------------
GET_SONGPOSITION PROC NEAR
	mov     ax,WORd Ptr cs:[Mt_PatternPos]
	shr     ax,2
	mov	ah,byte ptr cs:[Mt_SongPos]
	RET
GET_SONGPOSITION ENDP
;-----------------------------------------------------------------------------
comment #
SET_SONGPOSITION PROC NEAR
	PUSH    BX
	AND     AL,7FH
	MOV     CS:MT_SONGPOS,AL
	MOV     CS:MT_PATTERNPOS,0
	XOR     BX,BX
LSET1:  MOV     CS:[MSEG+BX],0
	INC     BL
	INC     BL
	CMP     BL,2*MAX_CHAN_NUMB
	JB      LSET1
	POP     BX
	RET
SET_SONGPOSITION ENDP
;-----------------------------------------------------------------------------
SET_SONGLOOP PROC NEAR
	MOV     CS:SONG_LOOP,AL
	RET
SET_SONGLOOP ENDP
#
;-----------------------------------------------------------------------------
Comment @
GET_VOLUME PROC NEAR
	MOV     AL,CS:MASTER_VOLUME     ;0= MIN VOLUME, 255= MAX VOLUME
	MOV     BL,CS:MUSIC_VOLUME      ;0= MIN VOLUME, 255= MAX VOLUME
	MOV     BH,CS:FX_VOLUME         ;0= MIN VOLUME, 255= MAX VOLUME
	RET
GET_VOLUME ENDP
@
;-----------------------------------------------------------------------------
SET_VOLUME PROC NEAR
	MOV     CS:MASTER_VOLUME,AL     ;0= MIN VOLUME, 255= MAX VOLUME
	MOV     CS:MUSIC_VOLUME,BL      ;0= MIN VOLUME, 255= MAX VOLUME
	MOV     CS:FX_VOLUME,BH         ;0= MIN VOLUME, 255= MAX VOLUME
	PUSH    AX DX
	MOVZX   DX,AL
	INC     DX
	PUSH    DX
	MOVZX   AX,BL
	MUL     DX
	MOV     CS:MUSIC_VOL,AH
	CMP     CS:SBPRO_FLAG,1
	JNE     SHORT GSTV1
	CMP     CS:CD_MIXER,0
	JE      SHORT GSTV1
	MOV     DX,CS:SBP_MIXERI
	MOV     AL,28H
	OUT     DX,AL
	INC     DX
	MOV     AL,AH                   ;SET CD VOLUME LEFT
	AND     AL,0F0H
	SHR     AH,4
	OR      AL,AH                   ;SET CD VOLUME RIGHT
	OUT     DX,AL
GSTV1:  POP     DX
	MOVZX   AX,BH
	MUL     DX
	MOV     CS:FX_VOL,AH
	POP     DX AX
	RET
SET_VOLUME ENDP
;-----------------------------------------------------------------------------
SET_LOADMOD_FLAG PROC NEAR
	AND     AL,1
	MOV     CS:LOADMOD_FLAG,AL      ;0= NORMAL, 1= CD PLAYER MODUS
	RET
SET_LOADMOD_FLAG ENDP
;-----------------------------------------------------------------------------
comment #
SET_SAMPLERATE PROC NEAR
	CMP     AX,10000
	JAE     SHORT GSSR1
	MOV     AX,10000
GSSR1:  CMP     AX,22222
	JBE     SHORT GSSR2
	MOV     AX,22222
GSSR2:  MOV     CS:SAMPLE_RATE,AX       ;BEST BETWEEN 10000 - 22222 Hz
	RET
SET_SAMPLERATE ENDP
#
;-----------------------------------------------------------------------------
SET_IRQ_RATE PROC NEAR
	PUSH    CS
	POP     DS
	MOV     BPM_RATE,AX
	MOV     AX,BPM_VALUE
	CALL    Go_SetBPM
	RET
SET_IRQ_RATE ENDP
;=============================================================================
CODE_SEG1 ENDS

END _MAIN1
