zpliku=1
;
;       ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
;       º                             º
TITLE   º GRAVIS ULTRASOUND MODPLAYER º
;       º                             º
;       ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
;
; THIS MODULE PLAYER WAS CODED IN EARLY 1994
;
;                        BY SILVIO TURELLO (FRONTMAN/CREW242)
;
; IT IS A COMPLETELY REVISED VERSION OF GUSPLAY 1.5
;
;                        BY ROBERT ADOLFSSON (CASCADA)
;
; FEATURES: 4/6/8-CHANNEL-MODS (M.K./FLT4/FLT8/OCTA/8CHN/6CHN)
;
;           16-FX-CHANNELS, FULL MOD-FX SUPPORT, FULL 8/16-BIT DMA SUPPORT
;
;           1 MB GUS SUPPORT, PANNING COMMAND E8x, OF COURSE VERY FAST
;
; MEMORY:   13K CODE, 0-64K TRACKBUF
;
.ALPHA
.MODEL MEDIUM
COM_OR_OBJ	= 4
STACKLENGTH     = 0100H
UGROUP4 GROUP CODE_SEG4, DATA_SEG4
ASSUME CS:UGROUP4, DS:UGROUP4, SS:UGROUP4
;=============================================================================
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
;-----------------------------------------------------------------------------
NumVoices	= 25		; Number of voices to use
StatusPort	= 6h		; UltraSound Ports
TimerCtrlPort	= 8h
TimerDataPort	= 9h
DMASetPort	= 0Bh
MidiCtrlPort	= 100h
MidiDataPort	= 101h
ActiveVoicePort	= 102h
CommandPort	= 103h
DataLowPort	= 104h
DataHighPort	= 105h
DRAMIOPort	= 107h
GUS_VERSION	= 506h
ICMIX_SEL	= 506h
ICMIX_DATA	= 106h
CODEC_BASE	= 10Ch

WriteVoiceMode	= 00h		; UltraSound Commands
SetVoiceFreq	= 01h		; Value=Freq/Divisor
LoopStartLo	= 02h
LoopStartHi	= 03h
SampleEndLo	= 04h
SampleEndHi	= 05h
VolRampRate	= 06h
VolRampStart	= 07h
VolRampEnd	= 08h
SetVolume	= 09h
SampleStartLo	= 0Ah
SampleStartHi	= 0Bh
VoiceBalance	= 0Ch
VolumeCtrl	= 0Dh
VoicesActive	= 0Eh
DMACtrl		= 41h
DMAAddr		= 42h
DRAMAddrLo	= 43h
DRAMAddrHi	= 44h
Initialize	= 4Ch
ReadVolume	= 89h
VoicePosLo	= 8Ah
VoicePosHi	= 8Bh
ReadVolCtrl	= 8Dh

Voices14	= 4300		; Divisors
Voices15	= 4000
Voices16	= 3700
Voices17	= 3500
Voices18	= 3300
Voices19	= 3100
Voices20	= 3030
Voices21	= 2800
Voices22	= 2700
Voices23	= 2600
Voices24	= 2500
Voices25	= 2400
Voices26	= 2300
Voices27	= 2200
Voices28	= 2100
Voices29	= 2000
Voices30	= 2000
Voices31	= 1900
Voices32	= 1800
;-----------------------------------------------------------------------------
CHAN_SIZE	= 52
CHAN_INFO STRUC
SAMP_OFF	DD 0
FREQ_VAL 	DW 0
VOL 		DW 0
OLD_VOL		DW 0
FINE 		DW 0
REPEAT 		DW 0
REPLEN 		DW 0
LEN 		DW 0
AMIGA 		DW 0
EFFECT 		DW 0
VIBRATO_POINT 	DW 0
OLD_VIBRATO 	DW 0
PORT_TO		DW 0
OLD_PORT_TO 	DW 0
EFFECT_TIME	DW 0
CURR_SAMP	DW 0
OLD_SAMP	DW 0
ARP 		DW 0,0,0
ARP_COUNTER 	DW 0
INST_SET	DB 0
BALANCE		DB 0
LOOP_ONOFF	DW 0
OFFSET_ADD	DW 0
TRACK_OFF	DW 0
CHAN_INFO ENDS
;=============================================================================

DATA_SEG4 SEGMENT 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
GDDLENGTH	DD 0
GDDREST		DW 0
GDDHANDLE	DW 0
GDDSEG		DW 0
BUFSEG		DW 0
GDDZEIG		DB 0
SAM_CH		DB 8
MOD_STAT	DB 0
US_MODUS	DB 0			;0=MUSIC&FX, 1=MUSIC, 2=FX, 3=OFF
CD_MIXER	DB 0			;0=MODULES ONLY, 1=CD MIXED
LOADMOD_FLAG	DB 0
SYSTEM		DB 0
IRQCOUNT	DB 56
COMP_SPEED2     DW 0106H
COMP_SPEED3     DW 4006H
COMP_SPEED4     DW 0
COMP_SPEED5     DW 1165
HOLD70  LABEL   DWORD
		DW OFFSET CONTROL_CHANNELS, 0
PAN_REGS	DB 3,12,12,3,3,12,12,3
		DB 2,13,2,13,2,13,2,13
		DB 2,13,2,13,2,13,2,13
		DB 2,13,2,13,2,13,2,13
PAN_FX		DB 0
SONG_START	DB 0
comment	#
MOD_NAME	DB 88 DUP(0)
;-----------------------------------------------------------------------------
ERROR1_TEXT	DB "MOD ERROR",13,10,"$"
ERROR2_TEXT	DB "FX ERROR",13,10,"$"
OUT_TEXT	DB "+/- VOLUME",13,10
		DB "1   PLAY SAMPLE",13,10
		DB "9   INIT REPEAT",13,10
		DB "0   MUSIC MODE",13,10,"$"
SAMPLE_NAME	DB "SAMPLE1.SAM",0
CONFIG_NAME     DB "SS3.CFG",0
CFG_TEXT2       DB "DEFAULT MUSIC MODE = ",0
CFG_TEXT3       DB "SOUNDCARD BASE PORT = ",0
CFG_TEXT5       DB "SOUNDCARD DMA NUMBER = ",0
CFG_TEXT7       DB "SYSTEM COMPATIBILITY = ",0
#
DMA_ADR		DB 0,2,4,6,0C0H,0C4H,0C8H,0CCH
DMA_CNT		DB 1,3,5,7,0C2H,0C6H,0CAH,0CEH
DMA_PAGE	DB 87H,83H,81H,82H,8FH,8BH,89H,8AH
DMA_STAT	DB 08H,08H,08H,08H,0D0H,0D0H,0D0H,0D0H
DMA_BITS	DB 1,2,4,8,1,2,4,8
DMA_MASK	DB 0AH,0AH,0AH,0AH,0D4H,0D4H,0D4H,0D4H
DMA_MOD		DB 0BH,0BH,0BH,0BH,0D6H,0D6H,0D6H,0D6H
DMA_FLIP	DB 0CH,0CH,0CH,0CH,0D8H,0D8H,0D8H,0D8H
DMA_RESET	DB 0DH,0DH,0DH,0DH,0DAH,0DAH,0DAH,0DAH
DMA_SET_DATA	DB 0,1,0,2,0,3,4,5
;-----------------------------------------------------------------------------
; PROTRACKER VARIABLEN
;-----------------------------------------------------------------------------
ALIGN 2
ULTRA16		DW 0
CODEC_PORT	DW 32CH
BASE_PORT	DW 220H
DMA_CHANNEL	DW 1			;DMA 0 IS NO DMA BYTE-PUSHING
MASTER_VOLUME	DW 255
MUSIC_VOLUME	DW 255
FX_VOLUME	DW 255
MUSIC_VOL	DW 255
FX_VOL		DW 255
BPM_RATE	DW 1024
BPM_VALUE	DW 125
BPM_COUNT	DD 0
BPM_SPEED	DD 0
COUNTER		DW 0
CH_NUMB		DW 4
PATT_SPEED	DW 0
PATT_COUNT	DW 0
PATT_ROW	DW 0
PATT_CURRENT	DW 0
PATT_BREAK	DW 0
;-----------------------------------------------------------------------------
; 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
PATTERN_SIZE	DW 0
PATTERN_SEG	DW 0
PATTERN_NUMBER	DW 0
IOFFSET		DD 31 DUP(0)
ISIZE		DW 31 DUP(0)
IVOLUME		DW 31 DUP(0)
IFINETUNE	DW 31 DUP(0)
ILOOP_START	DW 31 DUP(0)
ILOOP_SIZE	DW 31 DUP(0)
SONG_SIZE	DB 0
SONG_LOOP	DB 0
;-----------------------------------------------------------------------------
; PLAYER - KONTROLLSTRUKTUREN
;-----------------------------------------------------------------------------
ALIGN 2
SONG_DATA	LABEL	BYTE
FREQ_TABLE	DW 780 DUP(0)	;908
QUEUE_BUFFER	DW 128 DUP(0)
SAMP_CHANS	CHAN_INFO 8 DUP(<>)
SAMPLE_CHAN	CHAN_INFO <>
;-----------------------------------------------------------------------------
; SINGLE SAMPLE VARIABLES
;-----------------------------------------------------------------------------
GUS_MEM		DD 0
SAMPLE_ZEIG	DW 0
SAMPLE_MEM	DD 64 DUP(0)
SAMPLE_BIG	DW 64 DUP(0)
SAM_COUNT	DW 32 DUP(0)
;-----------------------------------------------------------------------------
ALIGN 2
PattJumps	DW OFFSET ARPeggioFix	; 0
		DW OFFSET NoPattEFFECT	; 1
		DW OFFSET NoPattEFFECT	; 2
		DW OFFSET PORT_TOFix	; 3
		DW OFFSET VibratoFix	; 4
		DW OFFSET NoPattEFFECT	; 5
		DW OFFSET NoPattEFFECT	; 6
		DW OFFSET NoPattEFFECT	; 7
		DW OFFSET NoPattEFFECT	; 8
		DW OFFSET SampleOff	; 9
		DW OFFSET NoPattEFFECT	; A
		DW OFFSET PosJump	; B
		DW OFFSET VOLume	; C
		DW OFFSET BreakPatt	; D
		DW OFFSET NoPattEFFECT	; E
		DW OFFSET SpeedSet	; F

EPattJumps	DW OFFSET NoPattEFFECT	; 0
		DW OFFSET FINEPortUp	; 1
		DW OFFSET FINEPortDown	; 2
		DW OFFSET NoPattEFFECT	; 3
		DW OFFSET NoPattEFFECT	; 4
		DW OFFSET NoPattEFFECT	; 5
		DW OFFSET NoPattEFFECT	; 6
		DW OFFSET NoPattEFFECT	; 7
		DW OFFSET PANNING	; 8
		DW OFFSET NoPattEFFECT	; 9
		DW OFFSET FINEVOLUP	; A
		DW OFFSET FINEVOLDown	; B
		DW OFFSET NoPattEFFECT	; C
		DW OFFSET NoPattEFFECT	; D
		DW OFFSET NoPattEFFECT	; E
		DW OFFSET NoPattEFFECT	; F

EFFECTJumps	DW OFFSET ARPeggio	; 0
		DW OFFSET PortUp	; 1
		DW OFFSET PortDown	; 2
		DW OFFSET PORT_TOTone	; 3
		DW OFFSET Vibrato	; 4
		DW OFFSET PORT_TOVSlide	; 5
		DW OFFSET VibratoVSlide	; 6
		DW OFFSET NoEFFECT	; 7
		DW OFFSET NoEFFECT	; 8
		DW OFFSET NoEFFECT	; 9
		DW OFFSET VOLSlide	; A
		DW OFFSET NoEFFECT	; B
		DW OFFSET NoEFFECT	; C
		DW OFFSET NoEFFECT	; D
		DW OFFSET NoEFFECT	; E
		DW OFFSET NoEFFECT	; F

EEFFECTJumps	DW OFFSET NoEFFECT	; 0
		DW OFFSET NoEFFECT	; 1
		DW OFFSET NoEFFECT	; 2
		DW OFFSET NoEFFECT	; 3
		DW OFFSET NoEFFECT	; 4
		DW OFFSET NoEFFECT	; 5
		DW OFFSET NoEFFECT	; 6
		DW OFFSET NoEFFECT	; 7
		DW OFFSET NoEFFECT	; 8
		DW OFFSET RetrigNote	; 9
		DW OFFSET NoEFFECT	; A
		DW OFFSET NoEFFECT	; B
		DW OFFSET CutNote	; C
		DW OFFSET DelayNote	; D
		DW OFFSET NoEFFECT	; E
		DW OFFSET NoEFFECT	; F

SIN_TAB		DB 0,25,50,74,98,120,142,162,180,197,212,225,236
		DB 244,250,254,255,254,250,244,236,225,212,197,180
		DB 162,142,120,98,74,50,25

PERIOD_TABLE	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.

GUS_VOL		DW 01000H,08FF0H,09FF0H,0A800H,0AFF0H,0B400H,0B800H,0BC00H
		DW 0BFF0H,0C200H,0C400H,0C600H,0C800H,0CA00H,0CC00H,0CE00H
		DW 0CFF0H,0D100H,0D200H,0D300H,0D400H,0D500H,0D600H,0D700H
		DW 0D800H,0D900H,0DA00H,0DB00H,0DC00H,0DD00H,0DE00H,0DF00H
		DW 0DFF0H,0E080H,0E100H,0E180H,0E200H,0E280H,0E300H,0E380H
		DW 0E400H,0E480H,0E500H,0E580H,0E600H,0E680H,0E700H,0E780H
		DW 0E800H,0E880H,0E900H,0E980H,0EA00H,0EA80H,0EB00H,0EB80H
		DW 0EC00H,0EC80H,0ED00H,0ED80H,0EE00H,0EE80H,0EF00H,0EF80H
		DW 0F800H	;SINGLE SAMPLE MAX VOL > SONG MAX VOL
;-----------------------------------------------------------------------------
PROG_END        LABEL   BYTE    ;MUSS LETZE ZEILE IM DATENSEGMENT SEIN!
;-----------------------------------------------------------------------------
DATA_SEG4 ENDS



.386
CODE_SEG4 SEGMENT	PAGE USE16
;=============================================================================
	ORG	100H
PUBLIC _MAIN4_g
PUBLIC configinit_g
PUBLIC loadmod_g
PUBLIC playmusic_g
PUBLIC stopmusic_g
PUBLIC endmusic_g

_MAIN4_G PROC FAR
	JMP	MAIN_CONT		;0100
	RETF
CONFIGINIT_G:		;0104
	CALL	CONFIG_INIT		;0104
	RETF
LOADMOD_G:		;0108
	CALL	LOAD_MOD		;0108
	RETF
PLAYMUSIC_G:		;010C
	CALL	PLAY_MUSIC		;010C
	RETF
STOPMUSIC_G:		;0110
	CALL	STOP_MUSIC		;0110
	RETF
ENDMUSIC_G:		;0114
	CALL	END_MUSIC		;0114
	RETF
getSONGPOSITION_g:	;24d
	CALL	get_SONGPOSITION	;24
	RETF
GETVOLUME_G:		;0128
	CALL	GET_VOLUME		;0128
	RETF
SETVOLUME_G:		;012C
	CALL	SET_VOLUME		;012C
	RETF
SETSONGLOOP_G:		;0130
	CALL	SET_SONGLOOP		;0130
	RETF
SETSONGPOSITION_g:	;0138
	CALL	SET_SONGPOSITION	;0138
	RETF
GETSONGMOD_G:		;013C
	CALL	GET_SONGMOD		;013C
	RETF
SETSONGMOD_G:		;0140
	CALL	SET_SONGMOD		;0140
	RETF
USOFF_G:			;0144
	CALL	US_OFF			;0144
	RETF
INITDEVICE_G:		;0148
	CALL	INIT_DEVICE		;0148
	RETF
_MAIN4_G ENDP
;=============================================================================


;=============================================================================
ALIGN 2
CONTROL_CHANNELS PROC NEAR

		push	ax es di
		xor	ax,ax
		mov	es,ax
		mov	di,20
		movzx	ax,byte ptr cs:[patt_row]
		shl	ax,2
		stosw
		mov	al,byte ptr cs:[patt_current]
		dec	al
;		mov	al,cs:[patt_row]
		stosb
		pop	di es ax


	PUSH	EAX EBX ECX EDX ESI EDI EBP
	PUSH	DS ES CS
	POP	DS
	CMP	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	LOADMOD_FLAG,0
	JNE	EndPattern
	INC	COUNTER
	MOV	AX,WORD PTR [BPM_SPEED+2]
	ADD	WORD PTR [BPM_COUNT+2],AX
	MOV	AX,WORD PTR [BPM_SPEED]
	ADC	WORD PTR [BPM_COUNT],AX
	JC	JumpPattern
	CMP	BPM_RATE,512
	JB	EndPattern
	CMP	COUNTER,3
	JE	SHORT ClearNotes
	CMP	COUNTER,6
	JE	SetNotes
	JMP	EndPattern
;-----------------------------------------------------------------------------
ClearNotes:
	CMP	MOD_STAT,0
	JE	SHORT NOT_FINISHED
	MOV	PATT_CURRENT,0
	MOV	DI,OFFSET SAMP_CHANS
	MOV	CX,CH_NUMB
FINISH:	MOV	[DI.OLD_VOL],0
	MOV	[DI.VOL],0
	MOV	[DI.AMIGA],0
	MOV	[DI.FREQ_VAL],0
	ADD	DI,CHAN_SIZE
	LOOP	FINISH
NOT_FINISHED:
	MOV	DI,OFFSET SAMP_CHANS
	MOV	CX,CH_NUMB
	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
StopVoices:
	DEC	DX
	MOV	AL,BYTE PTR CH_NUMB
	SUB	AL,CL
	OUT	DX,AL
	INC	DX
	CMP	[DI.INST_SET],2
	JE	SHORT VoiceOff1
	CMP	[DI.INST_SET],1
	JE	SHORT VoiceOff2
	CMP	[DI.OFFSET_ADD],0
	JNE	SHORT VoiceOff1
	JMP	SHORT NoVoiceOff
VoiceOff2:
	MOV	AX,[DI.CURR_SAMP]
	CMP	AX,[DI.OLD_SAMP]
	JNE	SHORT VoiceOff1
	JMP	SHORT NoVoiceOff
VoiceOff1:
	MOV	AX,[DI.OLD_VOL]
	MOV	[DI.OLD_VOL],0
	MOV	BP,GUS_VOL
	MOV	BX,MUSIC_VOL
	MUL	BL
	MOVZX	BX,AH
	SHL	BX,1
	MOV	BX,[GUS_VOL+BX]
	TEST	US_MODUS,2
	JZ	SHORT WITH_SOUND1
	MOV	BX,1000H
	MOV	BP,BX
WITH_SOUND1:
	CALL	SEND_RAMP
NoVoiceOff:
	ADD	DI,CHAN_SIZE
	LOOP	StopVoices
	CMP	BPM_RATE,512
	JAE	EndPattern
;-----------------------------------------------------------------------------
SetNotes:
	MOV	COUNTER,1
	MOV	DI,OFFSET SAMP_CHANS
	MOV	CX,CH_NUMB
	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
ChangeSamps:
	DEC	DX
	MOV	AL,BYTE PTR CH_NUMB
	SUB	AL,CL
	OUT	DX,AL
	INC	DX
	MOV	AL,[DI.BALANCE]		;PANNING
	MOV	AH,AL
	SHR	AL,4
	AND	AH,0FH
	CMP	AL,AH
	JE	SHORT NO_PANNING
	MOV	AL,AH
	SHL	AL,4
	OR	AL,AH
	MOV	[DI.BALANCE],AL
	MOV	AL,VoiceBalance
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,AH
	OUT	DX,AL
	SUB	DX,2
NO_PANNING:
	CMP	[DI.INST_SET],2
	JE	SHORT SampChange1
	CMP	[DI.INST_SET],1
	JE	SHORT SampChange2
	CMP	[DI.OFFSET_ADD],0
	JNE	SHORT ChangeOffset
	JMP	SHORT NoChangeSamp
ChangeOffset:
	CALL	SEND_SAMPLE_START
	JMP	SHORT NoChangeSamp
SampChange1:
	MOV	AH,3
	CALL	SEND_WRITE_VOICE
	CALL	WAIT_PORT
	CALL	SEND_SAMPLE_START
	MOV	AX,[DI.OLD_SAMP]
	CMP	AX,[DI.CURR_SAMP]
	JE	SHORT NoChangeSamp
	CALL	SEND_SAMPLE_END
	CALL	SEND_SAMPLE_LOOP
	MOV	AH,3
	CALL	SEND_WRITE_VOICE
	JMP	SHORT NoChangeSamp
SampChange2:
	MOV	AX,[DI.OLD_SAMP]
	CMP	AX,[DI.CURR_SAMP]
	JE	SHORT NoChangeSamp
	MOV	AL,VoicePosLo
	OUT	DX,AL
	INC	DX
	IN	AX,DX
	MOV	BX,AX
	DEC	DX
	MOV	AL,VoicePosHi
	OUT	DX,AL
	INC	DX
	IN	AX,DX
	DEC	DX
	XCHG	AX,BX
	SHL	AX,7
	SHR	BX,9
	AND	BX,7FH
	OR	AX,BX
	MOV	BX,[DI.OLD_SAMP]
	DEC	BX
	SHL	BX,2
	SUB	AX,WORD PTR [IOFFSET+BX]
	MOV	BX,AX
	CMP	BX,[DI.LEN]
	JB	SHORT NoFixStart
	MOV	BX,[DI.LEN]
	DEC	BX
NoFixStart:
	CMP	[DI.OFFSET_ADD],0
	JNE	SHORT NoOffsetEff
	MOV	[DI.OFFSET_ADD],BX
NoOffsetEff:
	CALL	SEND_SAMPLE_START
	CALL	SEND_SAMPLE_END
	CALL	SEND_SAMPLE_LOOP
	MOV	AH,BYTE PTR [DI.LOOP_ONOFF]
	CALL	SEND_WRITE_VOICE
	CALL	WAIT_PORT
NoChangeSamp:
	MOV	AX,[DI.OLD_VOL]
	MOV	BX,MUSIC_VOL
	MUL	BL
	MOVZX	BX,AH
	SHL	BX,1
	MOV	BX,[GUS_VOL+BX]
	MOV	AX,[DI.VOL]
	MOV	BP,MUSIC_VOL
	MUL	BP
	MOVZX	BP,AH
	SHL	BP,1
	MOV	BP,CS:[GUS_VOL+BP]
	TEST	US_MODUS,2
	JZ	SHORT WITH_SOUND2
	MOV	BX,1000H
	MOV	BP,BX
WITH_SOUND2:
	MOV	DX,BP
	MOV	DL,BH
	CMP	DL,DH
	JNE	SHORT SetVOL
	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
	MOV	AL,VOLumeCtrl
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,3
	OUT	DX,AL
	SUB	DX,2
	MOV	AL,SetVOLume
	OUT	DX,AL
	MOV	AX,BP
	INC	DX
	OUT	DX,AX
	DEC	DX
	JMP	SHORT NoSetVOL
SetVOL:	CALL	SEND_RAMP
NoSetVOL:
	MOV	AL,SetVoiceFreq
	OUT	DX,AL
	INC	DX
	MOV	AX,[DI.FREQ_VAL]
	OUT	DX,AX
	DEC	DX
	SHL	COUNTER,1
	ADD	DI,CHAN_SIZE
	DEC	CX
	JNZ	ChangeSamps
	MOV	DI,OFFSET SAMP_CHANS
	MOV	CX,CH_NUMB
StartVoices:
	DEC	DX
	MOV	AL,BYTE PTR CH_NUMB
	SUB	AL,CL
	OUT	DX,AL
	INC	DX
	CMP	[DI.INST_SET],2
	JNE	SHORT NoVoiceStart
	MOV	AH,BYTE PTR [DI.LOOP_ONOFF]
	CALL	SEND_WRITE_VOICE
	CALL	WAIT_PORT
NoVoiceStart:
	MOV	[DI.INST_SET],0
	MOV	[DI.OFFSET_ADD],0
	ADD	DI,CHAN_SIZE
	LOOP	StartVoices
	JMP	EndPattern
;-----------------------------------------------------------------------------
JumpPattern:
	MOV	COUNTER,0
	DEC	PATT_COUNT
	JZ	DoPattern
	MOV	DI,OFFSET SAMP_CHANS
	MOV	CX,CH_NUMB
EFFECTLoop:
	MOV	AX,[DI.VOL]
	MOV	[DI.OLD_VOL],AX
	INC	[DI.EFFECT_TIME]
	ADD	[DI.ARP_COUNTER],2
	CMP	[DI.ARP_COUNTER],6
	JB	SHORT NoWrapARP
	MOV	[DI.ARP_COUNTER],0
NoWrapARP:
	MOV	AX,[DI.EFFECT]
	OR	AX,AX
	JZ	NoEFFECT
	MOVZX	BX,AL
	CMP	BL,0EH
	JE	SHORT DoEEFFECTs
	SHL	BX,1
	JMP	[EFFECTJumps+BX]
DoEEFFECTs:
	MOV	BL,AH
	AND	AH,0FH
	SHR	BL,4
	SHL	BX,1
	JMP	[EEFFECTJumps+BX]
ARPeggio:
	MOV	BX,[DI.ARP_COUNTER]
	MOV	BX,[DI.ARP+BX]
	SHL	BX,1
	MOV	AX,[FREQ_TABLE+BX]
	MOV	[DI.FREQ_VAL],AX
	JMP	NoEFFECT
PortUp:	XCHG	AL,AH
	XOR	AH,AH
	MOV	SI,[DI.FINE]
	MOV	BP,[PERIOD_TABLE+47*2+SI]	;35
	MOV	BX,[DI.AMIGA]
	SUB	BX,AX
	JNC	SHORT NoFix1
	MOV	BX,BP
NoFix1:	CMP	BX,BP
	JAE	SHORT NotSmall1
	MOV	BX,BP
NotSmall1:
	MOV	[DI.AMIGA],BX
	SHL	BX,1
	MOV	AX,[FREQ_TABLE+BX]
	MOV	[DI.FREQ_VAL],AX
	JMP	NoEFFECT
PortDown:
	XCHG	AL,AH
	XOR	AH,AH
	MOV	SI,[DI.FINE]
	MOV	BP,[PERIOD_TABLE+SI]
	MOV	BX,[DI.AMIGA]
	ADD	BX,AX
	CMP	BX,BP
	JBE	SHORT NotBig1
	MOV	BX,BP
NotBig1:
	MOV	[DI.AMIGA],BX
	SHL	BX,1
	MOV	AX,[FREQ_TABLE+BX]
	MOV	[DI.FREQ_VAL],AX
	JMP	NoEFFECT
PORT_TOTone:
	XCHG	AL,AH
	XOR	AH,AH
GOTO_PORT_TO:
	MOV	DX,[DI.PORT_TO]
	MOV	BX,[DI.AMIGA]
	CMP	BX,DX
	JAE	SHORT NoPORT_TOUp
	ADD	BX,AX
	CMP	BX,DX
	JBE	SHORT NoPORT_TOUp
	MOV	[DI.AMIGA],DX
NoPORT_TOUp:
	CMP	BX,DX
	JBE	SHORT NoPORT_TODown
	SUB	BX,AX
	JNC	SHORT NoPORT_TOError
	MOV	BX,DX
NoPORT_TOError:
	CMP	BX,DX
	JAE	SHORT NoPORT_TODown
	MOV	BX,DX
NoPORT_TODown:
	MOV	[DI.AMIGA],BX
	SHL	BX,1
	MOV	AX,[FREQ_TABLE+BX]
	MOV	[DI.FREQ_VAL],AX
	JMP	NoEFFECT
Vibrato:
	MOV	SI,[DI.FINE]
	MOV	BP,[PERIOD_TABLE+47*2+SI]	;35
	MOV	SI,[PERIOD_TABLE+SI]
	MOV	DL,AH
	AND	AH,0F0H
	SHR	AH,2
	AND	DL,0FH
	MOV	BL,BYTE PTR [DI.VIBRATO_POINT]
	ADD	BL,AH
	MOV	BYTE PTR [DI.VIBRATO_POINT],BL
	SHR	BL,2
	AND	BX,1Fh
	MOV	AL,[SIN_TAB+BX]
	MUL	DL
	ROL	AX,1
	XCHG	AL,AH
	AND	AH,1
	TEST	BYTE PTR [DI.VIBRATO_POINT],80H
	JNE	SHORT VibUp1
	NEG	AX
VibUp1:	ADD	AX,[DI.AMIGA]
	CMP	AX,BP
	JAE	SHORT NoHighVibrato1
	MOV	AX,BP
NoHighVibrato1:
	CMP	AX,SI
	JBE	SHORT NoLowVibrato1
	MOV	AX,SI
NoLowVibrato1:
	SHL	AX,1
	MOV	BX,AX
	MOV	AX,[FREQ_TABLE+BX]
	MOV	[DI.FREQ_VAL],AX
	JMP	NoEFFECT
PORT_TOVSlide:
	MOV	AL,AH
	AND	AH,0FH
	SHR	AL,4
	SUB	AH,AL
	MOV	AL,BYTE PTR [DI.VOL]
	SUB	AL,AH
	JNS	SHORT NoSlideLow2
	XOR	AL,AL
NoSlideLow2:
	CMP	AL,40H
	JBE	SHORT NoSlideHigh2
	MOV	AL,40H
NoSlideHigh2:
	MOV	BYTE PTR [DI.VOL],AL
	MOV	AX,[DI.OLD_PORT_TO]
	JMP	GOTO_PORT_TO
VibratoVSlide:
	MOV	AL,AH
	AND	AH,0FH
	SHR	AL,4
	SUB	AH,AL
	MOV	AL,BYTE PTR [DI.VOL]
	SUB	AL,AH
	JNS	SHORT NoSlideLow3
	XOR	AL,AL
NoSlideLow3:
	CMP	AL,40H
	JBE	SHORT NoSlideHigh3
	MOV	AL,40H
NoSlideHigh3:
	MOV	BYTE PTR [DI.VOL],AL
	JMP	Vibrato
VOLSlide:
	MOV	AL,AH
	AND	AH,0FH
	SHR	AL,4
	OR	AL,AL
	JZ	SHORT NoVOLSlideUp
	NEG	AL
	MOV	AH,AL
NoVOLSlideUp:
	MOV	AL,BYTE PTR [DI.VOL]
	SUB	AL,AH
	JNS	SHORT NoSlideLow1
	XOR	AL,AL
NoSlideLow1:
	CMP	AL,40H
	JBE	SHORT NoSlideHigh1
	MOV	AL,40H
NoSlideHigh1:
	MOV	BYTE PTR [DI.VOL],AL
	JMP	SHORT NoEFFECT
RetrigNote:
	CMP	AH,BYTE PTR [DI.EFFECT_TIME]
	JNE	SHORT NoRetrig
	MOV	[DI.EFFECT_TIME],0
	MOV	[DI.INST_SET],2
NoRetrig:
	JMP	SHORT NoEFFECT
CutNote:
	CMP	AH,BYTE PTR [DI.EFFECT_TIME]
	JNE	SHORT NoCutNote
	MOV	[DI.AMIGA],0
	MOV	[DI.FREQ_VAL],0
NoCutNote:
	JMP	SHORT NoEFFECT
DelayNote:
	CMP	AH,BYTE PTR [DI.EFFECT_TIME]
	JNE	SHORT NoDelayNote
	MOV	[DI.INST_SET],2
	MOV	[DI.VIBRATO_POINT],0
	MOV	BX,[DI.PORT_TO]
	MOV	[DI.AMIGA],BX
	SHL	BX,1
	MOV	BX,[FREQ_TABLE+BX]
	MOV	[DI.FREQ_VAL],BX
NoDelayNote:
	JMP	SHORT NoEFFECT
NoEFFECT:
	ADD	DI,CHAN_SIZE
	DEC	CX
	JNZ	EFFECTLoop
	JMP	EndPattern2
;-----------------------------------------------------------------------------
DoPattern:
	MOV	AX,PATT_SPEED
	MOV	PATT_COUNT,AX
	CMP	PATT_ROW,64
	JB	SHORT NoPatternWrap
	MOV	AX,PATT_CURRENT
	CMP	AL,SONG_SIZE
	JB	SHORT NoTrackWrap
	MOV	AL,SONG_LOOP
	CMP	AL,SONG_SIZE
	JB	SHORT NoRestart
	MOV	MOD_STAT,3
	XOR	AL,AL
NoRestart:
	MOV	PATT_CURRENT,AX
	MOV	PATT_SPEED,6
	MOV	PATT_COUNT,1
	MOV	AL,125
	CALL	GO_SETBPM
	MOV	BPM_COUNT,0
NoTrackWrap:
	MOV	BX,PATT_CURRENT
	INC	PATT_CURRENT
	MOV	DI,OFFSET SAMP_CHANS
	XOR	SI,SI
NewTracks:
	PUSH	SI
	SHL	SI,1
	MOV	SI,[TRACKS_OFFSET+SI]
	MOV	AX,PATT_BREAK
	MOV	PATT_ROW,AX
	SHL	AX,2
	ADD	AH,[SI+BX]
	MOV	[DI.TRACK_OFF],AX
	POP	SI
	ADD	DI,CHAN_SIZE
	INC	SI
	CMP	SI,CH_NUMB
	JB	NewTracks
	MOV	PATT_BREAK,0
NoPatternWrap:
	MOV	ES,TRACK_SEG
	MOV	DI,OFFSET SAMP_CHANS
	MOV	CX,CH_NUMB
PattLoop:
	MOV	SI,[DI.TRACK_OFF]
	MOV	AX,[DI.VOL]
	MOV	[DI.OLD_VOL],AX
	MOV	BH,ES:[SI]		; New Sample
	MOV	BL,ES:[SI+2]
	AND	BH,0F0H
	SHR	BL,4
	ADD	BL,BH
	JZ	SHORT NoNewSample
	MOV	BH,BYTE PTR [DI.CURR_SAMP]
	MOV	BYTE PTR [DI.OLD_SAMP],BH
	MOV	BYTE PTR [DI.CURR_SAMP],BL
	XOR	BH,BH
	DEC	BX
	SHL	BX,1
	MOV	AX,[IVOLUME+BX]
	MOV	[DI.VOL],AX
	MOV	[DI.INST_SET],1
	SHL	BX,1
	MOV	EAX,[IOFFSET+BX]
	MOV	[DI.SAMP_OFF],EAX
	SHR	BX,1
	MOV	AX,[IFINETUNE+BX]
	SHL	AX,5
	MOV	[DI.FINE],AX
	SHL	AX,1
	ADD	[DI.FINE],AX
	MOV	[DI.LOOP_ONOFF],0
	MOV	AX,[ISIZE+BX]
	MOV	[DI.LEN],AX
	MOV	AX,[ILOOP_START+BX]
	MOV	[DI.REPEAT],AX
	MOV	AX,[ILOOP_SIZE+BX]
	MOV	[DI.REPLEN],AX
	CMP	AX,2
	JBE	SHORT NoNewSample
	MOV	[DI.LOOP_ONOFF],8
	MOV	AX,[DI.REPEAT]
	ADD	AX,[DI.REPLEN]
	CMP	AX,[DI.LEN]
	JA	SHORT NoNewSample
	MOV	[DI.LEN],AX
NoNewSample:
	MOV	BX,ES:[SI]
	XCHG	BL,BH
	AND	BX,0FFFH
	JZ	SHORT NoNewNote
	CALL	GET_PERIOD_INDEX
	ADD	BX,[DI.FINE]
	MOV	BX,[PERIOD_TABLE+BX]
	MOV	[DI.PORT_TO],BX
	MOV	AX,ES:[SI+2]
	AND	AL,0FH
	AND	AH,0F0H
	CMP	AL,3
	JE	SHORT NoNewNote
	CMP	AL,5
	JE	SHORT NoNewNote
	CMP	AX,0D00EH
	JNE	SHORT NewNote
	MOV	AL,ES:[SI+2]
	OR	AL,AL
	JZ	SHORT NewNote
	MOV	[DI.INST_SET],0
	JMP	SHORT NoNewNote
NewNote:
	MOV	[DI.INST_SET],2
	MOV	[DI.VIBRATO_POINT],0
	MOV	[DI.AMIGA],BX
	SHL	BX,1
	MOV	BX,[FREQ_TABLE+BX]
	MOV	[DI.FREQ_VAL],BX
NoNewNote:
	MOV	[DI.ARP_COUNTER],0
	MOV	AX,ES:[SI+2]
	AND	AL,0FH
	MOV	[DI.EFFECT],AX
	CMP	AL,7
	JB	SHORT NoSetOldFreq
	MOV	BX,AX
	AND	BH,0F0H
	CMP	BX,0C00EH
	JE	SHORT NoSetOldFreq
	CMP	BX,0D00EH
	JE	SHORT NoSetOldFreq
	MOV	BX,[DI.AMIGA]
	SHL	BX,1
	MOV	BX,[FREQ_TABLE+BX]
	MOV	[DI.FREQ_VAL],BX
NoSetOldFreq:
	MOVZX	BX,AL
	CMP	BL,0EH
	JE	SHORT DoEPattEFFECTs
	SHL	BX,1
	JMP	[PattJumps+BX]
DoEPattEFFECTs:
	MOV	BL,AH
	AND	AH,0FH
	SHR	BL,4
	SHL	BX,1
	JMP	[EPattJumps+BX]
ARPeggioFix:
	MOV	BX,[DI.AMIGA]
	CALL	GET_PERIOD_INDEX
	MOV	BP,BX
	ADD	BX,[DI.FINE]
	MOV	DX,[PERIOD_TABLE+BX]
	MOV	[DI.ARP],DX
	XCHG	AL,AH
	XOR	AH,AH
	MOV	DX,AX
	SHR	DX,4
	AND	AX,0FH
	SHL	DX,1
	SHL	AX,1
	MOV	BX,BP
	ADD	BX,DX
	CMP	BX,94
	JBE	SHORT NoWrapARP1
	MOV	BX,94
NoWrapARP1:
	ADD	BX,[DI.FINE]
	MOV	DX,[PERIOD_TABLE+BX]
	MOV	[DI.ARP+2],DX
	MOV	BX,BP
	ADD	BX,AX
	CMP	BX,94
	JBE	SHORT NoWrapARP2
	MOV	BX,94
NoWrapARP2:
	ADD	BX,[DI.FINE]
	MOV	DX,[PERIOD_TABLE+BX]
	MOV	[DI.ARP+4],DX
	JMP	NoPattEFFECT
PORT_TOFix:
	OR	AH,AH
	JNZ	SHORT NoPortPekFix
	MOV	AH,BYTE PTR [DI.OLD_PORT_TO]
NoPortPekFix:
	MOV	BYTE PTR [DI.OLD_PORT_TO],AH
	MOV	BYTE PTR [DI.EFFECT+1],AH
	JMP	NoPattEFFECT
VibratoFix:
	MOV	AL,AH
	AND	AL,0FH
	AND	AH,0F0H
	OR	AL,AL
	JNZ	SHORT NoVibratoFix1
	MOV	AL,BYTE PTR [DI.OLD_VIBRATO]
NoVibratoFix1:
	OR	AH,AH
	JNZ	SHORT NoVibratoFix2
	MOV	AH,BYTE PTR [DI.OLD_VIBRATO+1]
NoVibratoFix2:
	MOV	BYTE PTR [DI.OLD_VIBRATO],AL
	MOV	BYTE PTR [DI.OLD_VIBRATO+1],AH
	OR	AL,AH
	MOV	BYTE PTR [DI.EFFECT+1],AL
	JMP	NoPattEFFECT
SampleOff:
	XOR	AL,AL
	CMP	AX,[DI.LEN]
	JB	SHORT NoFixOffset
	MOV	AX,[DI.LEN]
	DEC	AX
NoFixOffset:
	MOV	[DI.OFFSET_ADD],AX
	JMP	NoPattEFFECT
PosJump:
	MOV	[PATT_ROW],63
	MOV	BYTE PTR [PATT_CURRENT],AH
	JMP	NoPattEFFECT
VOLume:
	CMP	AH,40H
	JBE	SHORT NoFixVOL1
	MOV	AH,40H
NoFixVOL1:
	MOV	BYTE PTR [DI.VOL],AH
	JMP	NoPattEFFECT
BreakPatt:
	MOV	[PATT_ROW],63
	CMP	AH,64H
	JB	SHORT NoFixBreak
	MOV	AH,63H
NoFixBreak:
	MOV	AL,AH
	AND	AL,0FH
	SHR	AH,4
	SHL	AH,1
	MOV	BYTE PTR [PATT_BREAK],AL
	ADD	BYTE PTR [PATT_BREAK],AH
	SHL	AH,2
	ADD	BYTE PTR [PATT_BREAK],AH
	JMP	NoPattEFFECT
SpeedSet:
	OR	AH,AH
	JZ	NoPattEFFECT
	CMP	AH,1FH
	JBE	SHORT UsualSpeed
	XCHG	AL,AH
	CALL	GO_SETBPM
	JMP	SHORT NoPattEFFECT
UsualSpeed:
	MOV	BYTE PTR [PATT_SPEED],AH
	MOV	BYTE PTR [PATT_COUNT],AH
	JMP	SHORT NoPattEFFECT
FINEPortUp:
	XCHG	AL,AH
	XOR	AH,AH
	SUB	[DI.AMIGA],AX
	MOV	BX,[DI.FINE]
	MOV	BX,[PERIOD_TABLE+47*2+BX] ;35
	CMP	[DI.AMIGA],BX
	JAE	SHORT NoFixFINEUp
	MOV	[DI.AMIGA],BX
NoFixFINEUp:
	JMP	SHORT NoPattEFFECT
FINEPortDown:
	XCHG	AL,AH
	XOR	AH,AH
	ADD	[DI.AMIGA],AX
	MOV	BX,[DI.FINE]
	MOV	BX,[PERIOD_TABLE+BX]
	CMP	[DI.AMIGA],BX
	JBE	SHORT NoFixFINEDown
	MOV	[DI.AMIGA],BX
NoFixFINEDown:
	JMP	SHORT NoPattEFFECT
PANNING:
	AND	[DI.BALANCE],0F0H
	OR	[DI.BALANCE],AH
	JMP	SHORT NoPattEFFECT
FINEVOLUP:
	ADD	BYTE PTR [DI.VOL],AH
	CMP	BYTE PTR [DI.VOL],40H
	JBE	SHORT NoFixFINEVOLUp
	MOV	BYTE PTR [DI.VOL],40H
NoFixFINEVOLUp:
	JMP	SHORT NoPattEFFECT
FINEVOLDown:
	SUB	BYTE PTR [DI.VOL],AH
	JNC	SHORT NoFixFINEVOLDown
	MOV	BYTE PTR [DI.VOL],0
NoFixFINEVOLDown:
	JMP	SHORT NoPattEFFECT
NoPattEFFECT:
	ADD	[DI.TRACK_OFF],4
	MOV	[DI.EFFECT_TIME],0
	ADD	DI,CHAN_SIZE
	DEC	CX
	JNZ	PattLoop
	INC	PATT_ROW
EndPattern2:
	CMP	BPM_RATE,512
	JB	ClearNotes
EndPattern:
	CALL	CONTROL_SAMPLE
	POP	ES DS
	POP	EBP EDI ESI EDX ECX EBX EAX
	CMP	CS:VAR_BUFSEG,0
	JNE	SHORT WT8
	CMP	CS:SYSTEM,0
	JE	SHORT WT7
	DEC	CS:IRQCOUNT
	JNZ	SHORT WT7
	MOV	CS:IRQCOUNT,56
WT8:	JMP	DWORD PTR CS:[HOLD70]
WT7:	IRET
CONTROL_CHANNELS ENDP
;-----------------------------------------------------------------------------
GET_PERIOD_INDEX PROC NEAR
	MOV	BP,BX
	XOR	BH,BH
	MOV	DX,6000H		;BINAERSUCHE
LGP1:	MOV	BL,DL
	ADD	BL,DH
	SHR	BL,1
	AND	BL,0FEH
	JZ	SHORT GGP2
	CMP	BL,94
	JE	SHORT GGP2
	CMP	BP,[PERIOD_TABLE+BX]
	JAE	SHORT GGP1
	MOV	DL,BL
	JMP	LGP1
GGP1:	MOV	DH,BL
	CMP	BP,[PERIOD_TABLE-2+BX]
	JAE	LGP1			;GEFUNDEN
	MOV	DX,[PERIOD_TABLE-2+BX]	;GET NEAREST PERIOD
	SUB	DX,BP
	SUB	BP,[PERIOD_TABLE+BX]
	CMP	DX,BP
	JAE	SHORT GGP2
	SUB	BX,2
GGP2:	RET
GET_PERIOD_INDEX ENDP
;-----------------------------------------------------------------------------
GO_SETBPM PROC NEAR
	XOR	AH,AH
	MOV	BPM_VALUE,AX
	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
	CMP	BX,DX
	JA	SHORT GOSBPM
	MOV	BX,DX
	INC	BX
GOSBPM:	DIV	BX
	MOV	WORD PTR BPM_SPEED,AX
	XOR	AX,AX
	DIV	BX
	MOV	WORD PTR BPM_SPEED+2,AX
	RET
GO_SETBPM ENDP
;-----------------------------------------------------------------------------
CONTROL_SAMPLE PROC NEAR
	MOV	CL,8
	XOR	SI,SI
LCS1:	CMP	[SAM_COUNT+SI],0
	JE	SHORT GCS1
	JL	SHORT GCS2
	DEC	[SAM_COUNT+SI]
	JNZ	SHORT GCS1
	MOV	[SAM_COUNT+SI],-256	;RAMP DOWN SAMPLE
	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
	DEC	DX
	MOV	AL,CL
	OUT	DX,AL
	INC	DX
	MOV	BP,GUS_VOL
	MOV	BX,FX_VOL
	INC	BX
	SHR	BX,2
	CMP	BL,40H
	JBE	SHORT FIXVOL
	MOV	BL,40H
FIXVOL:	SHL	BX,1
	MOV	BX,[GUS_VOL+BX]
	CALL	SEND_RAMP
	JMP	SHORT GCS1
GCS2:	INC	[SAM_COUNT+SI]		;STOP SAMPLE
	JNZ	SHORT GCS1
	MOV	DX,BASE_PORT
	ADD	DX,ActiveVoicePort
	MOV	AL,CL
	OUT	DX,AL
	INC	DX
	MOV	AL,WriteVoiceMode
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,3			;Voice Off
	OUT	DX,AL
	SUB	DX,2
	MOV	AL,VolumeCtrl
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,3			;Ramp Off
	OUT	DX,AL
	SUB	DX,3
GCS1:	INC	SI
	INC	SI
	INC	CL
	CMP	CL,NumVoices-1
	JB	LCS1
	RET
CONTROL_SAMPLE ENDP
;=============================================================================


;=============================================================================
;
; ULTRASOUND INIT
;
;=============================================================================
INIT_DEVICE PROC NEAR
	PUSH	CS
	POP	DS
	CLI
	MOV	BX,BASE_PORT		;Init the UltraSound
	MOV	CX,BX
	ADD	BX,CommandPort
	ADD	CX,DataHighPort
	MOV	DX,BX
	MOV	AL,Initialize
	OUT	DX,AL
	MOV	DX,CX
	MOV	AL,0
	OUT	DX,AL
	MOV	DX,BASE_PORT
	MOV	AH,10
LID1:	IN	AL,DX
	DEC	AH
	JNZ	LID1
	MOV	DX,BX
	MOV	AL,Initialize
	OUT	DX,AL
	MOV	DX,CX
	MOV	AL,1
	OUT	DX,AL
	MOV	DX,BASE_PORT
	MOV	AH,10
LID2:	IN	AL,DX
	DEC	AH
	JNZ	LID2
	MOV	DX,BX
	MOV	AL,DMACtrl
	OUT	DX,AL
	MOV	DX,CX
	MOV	AL,0
	OUT	DX,AL
	MOV	DX,BX
	MOV	AL,45H
	OUT	DX,AL
	MOV	DX,CX
	MOV	AL,0
	OUT	DX,AL
	MOV	DX,BX
	MOV	AL,49H
	OUT	DX,AL
	MOV	DX,CX
	MOV	AL,0
	OUT	DX,AL

	MOV	DX,BX
	MOV	AL,VoicesActive
	OUT	DX,AL
	MOV	DX,CX
	MOV	AL,NumVoices
	DEC	AL
	OR	AL,0C0H
	OUT	DX,AL

	MOV	DX,BASE_PORT		;Clear IRQs
	ADD	DX,StatusPort
	IN	AL,DX
	MOV	DX,BX
	MOV	AL,DMACtrl
	OUT	DX,AL
	MOV	DX,CX
	IN	AL,DX
	MOV	DX,BX
	MOV	AL,49H
	OUT	DX,AL
	MOV	DX,CX
	IN	AL,DX
	MOV	DX,BX
	MOV	AL,8FH
	OUT	DX,AL
	MOV	DX,CX
	IN	AL,DX

	PUSH	CX
	MOV	CX,32
VoiceClearLoop:
	MOV	DX,BASE_PORT
	ADD	DX,ActiveVoicePort
	MOV	AL,CL
	DEC	AL
	OUT	DX,AL
	INC	DX
	MOV	AL,0
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,3			;Voice Off
	OUT	DX,AL
	SUB	DX,2
	MOV	AL,0DH
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,3			;Ramp Off
	OUT	DX,AL
	MOV	DX,BASE_PORT
	MOV	AH,10
LID3:	IN	AL,DX
	DEC	AH
	JNZ	LID3
	LOOP	VoiceClearLoop
	POP	CX

	CMP	DMA_CHANNEL,0		;NO DMA
	JE	SHORT LID5
	MOV	DX,BASE_PORT		;SETUP FOR DIGITAL ASIC
	ADD	DX,0FH
	MOV	AL,5
	OUT	DX,AL
	SUB	DX,0FH
	MOV	AL,3
	OUT	DX,AL
	ADD	DX,DMASetPort
	MOV	AL,0
	OUT	DX,AL
	ADD	DX,0FH-DMASetPort
	OUT	DX,AL
	SUB	DX,0FH
	MOV	AL,3			;SET DMA CHANNEL
	OUT	DX,AL
	ADD	DX,DMASetPort
	PUSH	BX
	MOV	BX,DMA_CHANNEL
	MOV	AL,[DMA_SET_DATA+BX]
	POP	BX
	OR	AL,0C0H			;SET DMA
	OUT	DX,AL
	SUB	DX,DMASetPort
	PUSH	AX
	MOV	AL,43H
	OUT	DX,AL
	ADD	DX,DMASetPort
	MOV	AL,45H			;SET IRQ11
	OUT	DX,AL
	SUB	DX,DMASetPort
	MOV	AL,3
	OUT	DX,AL
	ADD	DX,DMASetPort
	POP	AX
	AND	AL,7FH			;SET DMA
	OUT	DX,AL
	SUB	DX,DMASetPort
	MOV	AL,43H
	OUT	DX,AL
	ADD	DX,DMASetPort
	MOV	AL,45H			;SET IRQ11
	OUT	DX,AL
	ADD	DX,ActiveVoicePort-DMASetPort
	MOV	AL,0
	OUT	DX,AL
	SUB	DX,ActiveVoicePort
	MOV	AL,8			;SETUP DMA LATCH
	OUT	DX,AL
	ADD	DX,ActiveVoicePort
	MOV	AL,0
	OUT	DX,AL
LID5:
	MOV	DX,BX			;Clear IRQs
	MOV	AL,DMACtrl
	OUT	DX,AL
	MOV	DX,CX
	IN	AL,DX
	MOV	DX,BX
	MOV	AL,49H
	OUT	DX,AL
	MOV	DX,CX
	IN	AL,DX
	MOV	DX,BX
	MOV	AL,8FH
	OUT	DX,AL
	MOV	DX,CX
	IN	AL,DX

	MOV	DX,BX
	MOV	AL,Initialize
	OUT	DX,AL
	MOV	DX,CX
	MOV	AL,3
	OUT	DX,AL

	MOV	CX,NumVoices
SetRampRateLoop:
	MOV	DX,BASE_PORT
	ADD	DX,ActiveVoicePort
	MOV	AL,NumVoices
	SUB	AL,CL
	OUT	DX,AL

	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
	MOV	AL,VOLRampRate
	OUT	DX,AL
	MOV	AL,00111111B
	MOV	DX,BASE_PORT
	ADD	DX,DataHighPort
	OUT	DX,AL

	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
	MOV	AL,SetVOLume
	OUT	DX,AL
	MOV	AX,GUS_VOL
	MOV	DX,BASE_PORT
	ADD	DX,DataLowPort
	OUT	DX,AX
	MOV	DX,BASE_PORT
	MOV	AH,10
LID4:	IN	AL,DX
	DEC	AH
	JNZ	LID4
	LOOP	SetRampRateLoop

	MOV	DX,BASE_PORT		;DETECT GUS VERSION
	ADD	DX,GUS_VERSION
	IN	AL,DX
	CMP	ULTRA16,0		;IST ULTRA16 BOARD ANGEGEBEN?
	JNE	SHORT LID9
	CMP	AL,5			;GUS BEFORE 3.7 NO MIXER
	JL	SHORT LID6
	CMP	AL,10
	JB	SHORT LID7		;NON GUS MAX
LID9:	CMP	AL,10
	JB	SHORT LID8
	ADD	DX,ICMIX_DATA-ICMIX_SEL	;ACTIVATE GUS MAX MIXER OUTPUT
	MOV	AX,CODEC_PORT
	SHR	AL,4
	OR	AL,40H
	OUT	DX,AL
LID8:	MOV	DX,CODEC_PORT		;CODEC MIXER ON GUS MAX 31-0
	MOV	AH,8			;NO GAIN, KEINE VERSTAERKUNG
	MOV	AL,2			;GF1 LEFT CHANNEL
	OUT	DX,AL
	INC	DX
	MOV	AL,AH
	OUT	DX,AL
	DEC	DX
	MOV	AL,3			;GF1 RIGHT CHANNEL
	OUT	DX,AL
	INC	DX
	MOV	AL,AH
	OUT	DX,AL
	DEC	DX
	XOR	AH,AH
	MOV	AL,6			;OUT LEFT CHANNEL
	OUT	DX,AL
	INC	DX
	MOV	AL,AH
	OUT	DX,AL
	DEC	DX
	MOV	AL,7			;OUT RIGHT CHANNEL
	OUT	DX,AL
	INC	DX
	MOV	AL,AH
	OUT	DX,AL
LID7:	MOV	AH,BYTE PTR MUSIC_VOL
	CALL	SET_CDMIXER
LID6:	STI
	RET
INIT_DEVICE ENDP
;-----------------------------------------------------------------------------
SEND_SAMPLE_START PROC NEAR
	MOV	AL,SampleStartLo
	OUT	DX,AL
	INC	DX
	MOV	AX,WORD PTR [DI.SAMP_OFF]
	MOV	BP,WORD PTR [DI.SAMP_OFF+2]
	ADD	AX,[DI.OFFSET_ADD]
	ADC	BP,0
	SHR	AX,7
	SHL	BP,9
	OR	AX,BP
	OUT	DX,AX
	DEC	DX
	MOV	AL,SampleStartHi
	OUT	DX,AL
	INC	DX
	MOV	AX,WORD PTR [DI.SAMP_OFF]
	ADD	AX,[DI.OFFSET_ADD]
	SHL	AX,9
	OUT	DX,AX
	DEC	DX
	SUB	DX,CommandPort
	Rept	6
	IN	AL,DX
	EndM
	ADD	DX,CommandPort
	RET
SEND_SAMPLE_START ENDP
;-----------------------------------------------------------------------------
SEND_SAMPLE_END PROC NEAR
	MOV	AL,SampleEndLo
	OUT	DX,AL
	INC	DX
	MOV	AX,WORD PTR [DI.SAMP_OFF]
	MOV	BP,WORD PTR [DI.SAMP_OFF+2]
	ADD	AX,[DI.LEN]
	ADC	BP,0
	SHR	AX,7
	SHL	BP,9
	OR	AX,BP
	OUT	DX,AX
	DEC	DX
	MOV	AL,SampleEndHi
	OUT	DX,AL
	INC	DX
	MOV	AX,WORD PTR [DI.SAMP_OFF]
	ADD	AX,[DI.LEN]
	SHL	AX,9
	OUT	DX,AX
	DEC	DX
	RET
SEND_SAMPLE_END ENDP
;-----------------------------------------------------------------------------
SEND_SAMPLE_LOOP PROC NEAR
	MOV	AL,LoopStartLo
	OUT	DX,AL
	INC	DX
	MOV	AX,WORD PTR [DI.SAMP_OFF]
	MOV	BP,WORD PTR [DI.SAMP_OFF+2]
	ADD	AX,[DI.REPEAT]
	ADC	BP,0
	SHR	AX,7
	SHL	BP,9
	OR	AX,BP
	OUT	DX,AX
	DEC	DX
	MOV	AL,LoopStartHi
	OUT	DX,AL
	INC	DX
	MOV	AX,WORD PTR [DI.SAMP_OFF]
	ADD	AX,[DI.REPEAT]
	SHL	AX,9
	OUT	DX,AX
	DEC	DX
	RET
SEND_SAMPLE_LOOP ENDP
;-----------------------------------------------------------------------------
SEND_WRITE_VOICE PROC NEAR
	MOV	AL,WriteVoiceMode
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,AH
	OUT	DX,AL
	SUB	DX,2
	RET
SEND_WRITE_VOICE ENDP
;-----------------------------------------------------------------------------
WAIT_PORT PROC NEAR
	SUB	DX,CommandPort
	Rept	6
	IN	AL,DX
	EndM
	ADD	DX,CommandPort
	RET
WAIT_PORT ENDP
;-----------------------------------------------------------------------------
SEND_RAMP PROC NEAR
	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
	MOV	AL,VOLumeCtrl
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,3
	OUT	DX,AL
	SUB	DX,2
	MOV	AH,0
	CMP	BX,BP
	JB	SHORT NoFixVOLDir
	MOV	AH,01000000B
	XCHG	BX,BP
NoFixVOLDir:
	MOV	AL,VOLRampStart
	OUT	DX,AL
	XCHG	AX,BX
	INC	DX
	OUT	DX,AX
	DEC	DX
	MOV	AL,VOLRampEnd
	OUT	DX,AL
	MOV	AX,BP
	INC	DX
	OUT	DX,AX
	DEC	DX
	MOV	AL,VOLumeCtrl
	OUT	DX,AL
	MOV	AL,BH
	ADD	DX,2
	OUT	DX,AL
	SUB	DX,2
	RET
SEND_RAMP ENDP
;-----------------------------------------------------------------------------
; CX= ANZAHL WORDS, EDI= GUSMEM ZEIGER, BX= 0000H AMIGA, 8080H PC SAMPLE
; DS:SI= ZEIGER AUF SAMPLE-DATEN
;-----------------------------------------------------------------------------
SEND_SAMPLE_DATA PROC NEAR
	CMP	CS:DMA_CHANNEL,0
	JNE	DMA_INIT
	MOV	DX,CS:BASE_PORT
	ADD	DX,CommandPort
LHP1:	LODSW
	CLI
	XOR	AX,BX
	MOV	BP,AX
	MOV	AL,DRAMAddrLo
	OUT	DX,AL
	INC	DX
	MOV	AX,DI
	OUT	DX,AX
	DEC	DX
	MOV	AL,DRAMAddrHi
	OUT	DX,AL
	ADD	DX,2
	MOV	EAX,EDI
	SHR	EAX,16
	OUT	DX,AL
	ADD	DX,2
	MOV	AX,BP
	OUT	DX,AL
	SUB	DX,4
	INC	EDI
	MOV	AL,DRAMAddrLo
	OUT	DX,AL
	INC	DX
	MOV	AX,DI
	OUT	DX,AX
	DEC	DX
	MOV	AL,DRAMAddrHi
	OUT	DX,AL
	ADD	DX,2
	MOV	EAX,EDI
	SHR	EAX,16
	OUT	DX,AL
	ADD	DX,2
	MOV	AX,BP
	MOV	AL,AH
	OUT	DX,AL
	SUB	DX,4
	INC	EDI
	STI
	LOOP	LHP1
	CLI
	MOV	AL,DRAMAddrLo		;SAMPLE UM EIN WORD VERLŽNGERN
	OUT	DX,AL
	INC	DX
	MOV	AX,DI
	OUT	DX,AX
	DEC	DX
	MOV	AL,DRAMAddrHi
	OUT	DX,AL
	ADD	DX,2
	MOV	EAX,EDI
	SHR	EAX,16
	OUT	DX,AL
	ADD	DX,2
	MOV	AX,BP
	MOV	AL,AH
	OUT	DX,AL
	SUB	DX,4
	INC	EDI
	MOV	CS:GUS_MEM,EDI
	STI
	RET
SEND_SAMPLE_DATA ENDP
;-----------------------------------------------------------------------------
; SET DMA READY FOR TRANSFER WITH AUTOINIT
; IN: DS:SI= BLOCKPOINTER, CX= SIZE IN WORDS, EDI, BX WIE OBEN
;-----------------------------------------------------------------------------
DMA_INIT PROC NEAR
	MOV	DX,CS:BASE_PORT		;STOP GUS DMA & CLEAR ALL PENDING IRQs
	ADD	DX,CommandPort
	MOV	AL,DMACtrl
	OUT	DX,AL
	INC	DX
	INC	DX
	IN	AL,DX			;CLEAR IRQ, BUT MASTER IRQ IS DISABLED
	MOV	DX,CS:BASE_PORT		;THERE HAPPENED NO IRQ
	ADD	DX,StatusPort
	IN	AL,DX
	MOV	BP,CS:DMA_CHANNEL
;	MOVZX	DX,CS:[DMA_RESET+BP]	;CASCADED DMA2 (MASTER) RESET
;	OUT	DX,AL			;RESET AUF MASTER DMA LOESCHT CASCADE
	CMP	BP,4
	JAE	SHORT NO_RESET1
	MOVZX	DX,CS:[DMA_RESET]	;DMA1 (SLAVE) MASTER CLEAR
	OUT	DX,AL
NO_RESET1:
	MOV	BP,BX
	MOVZX	EAX,CX			;CHECK 256K GUS DRAM BOUNDARY
	SHL	EAX,1			;BECAUSE DMA IS NOT ABLE TO CROSS
	INC	EAX			;1 WORD LŽNGER-1 BYTE IST LETZTES BYTE
	ADD	EAX,EDI
	SHR	EAX,18
	MOV	EDX,EDI
	SHR	EDX,18
	CMP	EAX,EDX
	JE	SHORT DMA_NORMAL
	PUSH	SI CX
	SHL	EAX,18
	SUB	EAX,EDI
	MOV	CX,AX
	SHR	CX,1
	PUSH	CX
	DEC	CX
	CALL	DMA_PORTION		;FIRST PORTION
	POP	AX CX SI
	SUB	CX,AX
	ADD	SI,AX
	ADD	SI,AX			;REST: CORRECT OFFSET & SIZE
DMA_NORMAL:
	MOV	BX,CX			;SAMPLE UM EIN WORD VERLŽNGERN
	SHL	BX,1
	DEC	BX
	MOV	AL,[SI+BX]
	MOV	AH,AL
	INC	BX
	MOV	[SI+BX],AX
DMA_PORTION:
	CLI
	MOV	BX,SI			;SETUP PC DMA CONTROLLER
	MOV	DX,DS
	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	AL,AH
	MOV	SI,CS:DMA_CHANNEL
	CMP	SI,4
	JB	SHORT GDMI1
	SHRD	BX,AX,1			;ADRESSE FšR 16-BIT DMA
	JMP	SHORT GDMI2
GDMI1:	SHL	CX,1			;ZAEHLER FšR 8-BIT DMA
	INC	CX			;SAMPLE ABSCHLUSS MIT EINEM WORD MEHR
GDMI2:	MOVZX	DX,CS:[DMA_MASK+SI]
	MOV	AL,BYTE PTR CS:DMA_CHANNEL
	OR	AL,4
	OUT	DX,AL			;DMA-KANAL MASKIEREN
	MOVZX	DX,CS:[DMA_MOD+SI]
	AND	AL,3
	OR	AL,01001000B
	OUT	DX,AL			;DMA-MODUS FšR GUS
	MOVZX	DX,CS:[DMA_FLIP+SI]
	OUT	DX,AL			;FLIP-FLOP CLEAR
	MOVZX	DX,CS:[DMA_ADR+SI]
	MOV	AL,BL			;DMA CHANNEL 1-4
	OUT	DX,AL			;OFFSET LOW
	MOV	AL,BH
	OUT	DX,AL			;OFFSET HIGH
	MOVZX	DX,CS:[DMA_CNT+SI]
	MOV	AL,CL
	OUT	DX,AL			;SIZE LOW
	MOV	AL,CH
	OUT	DX,AL			;SIZE HIGH
	MOVZX	DX,CS:[DMA_PAGE+SI]
	MOV	AL,AH
	OUT	DX,AL			;PAGE
	MOVZX	DX,CS:[DMA_MASK+SI]
	MOV	AX,SI
	AND	AL,3
	OUT	DX,AL			;DMA-KANAL DEMASKIEREN

	MOV	DX,CS:BASE_PORT		;SETUP GUS FOR DMA TRANSFER
	ADD	DX,CommandPort
	MOV	AL,DMAAddr		;SET DMA ADDRESS
	OUT	DX,AL
	MOV	EAX,EDI
	SHR	EAX,4
	CMP	SI,4
	JB	SHORT GDMI3
	MOV	BX,AX			;CONVERT FOR 16-BIT TRANSFER
	AND	AX,03FFFH
	SHR	AX,1
	AND	BX,0C000H
	OR	AX,BX
GDMI3:	INC	DX	
	OUT	DX,AX
	DEC	DX
	MOV	AL,DMACtrl
	OUT	DX,AL
	INC	DX
	INC	DX
	MOV	AX,SI
	AND	AL,4			;SELECT 8/16-BIT CHANNEL
	OR	AX,BP			;SELECT AMIGA/PC
	OR	AL,00100001B		;START DMA TRANSFER
	OUT	DX,AL
	STI
	MOVZX	DX,CS:[DMA_STAT+SI]
	MOV	AH,CS:[DMA_BITS+SI]
	MOV	EBX,800000H		;TIMEOUT
GDMI4:	DEC	EBX
	JZ	SHORT GDMI5
	OR	BL,BL
	JNZ	GDMI4
	IN	AL,DX			;WAIT FOR TRANSFER END
	TEST	AL,AH
	JZ	GDMI4
GDMI5:	MOV	DX,CS:BASE_PORT		;STOP GUS DMA
	ADD	DX,CommandPort
	MOV	AL,DMACtrl
	OUT	DX,AL
	INC	DX
	INC	DX
	IN	AL,DX			;CLEAR IRQ, BUT MASTER IRQ IS DISABLED
	MOV	DX,CS:BASE_PORT		;THERE HAPPENED NO IRQ
	ADD	DX,StatusPort
	IN	AL,DX
;	MOVZX	DX,CS:[DMA_RESET+SI]	;CASCADED DMA2 (MASTER) RESET
;	OUT	DX,AL			;RESET AUF MASTER DMA LOESCHT CASCADE
	CMP	SI,4
	JAE	SHORT NO_RESET2
	MOVZX	DX,CS:[DMA_RESET]	;DMA1 (SLAVE) MASTER CLEAR
	OUT	DX,AL
NO_RESET2:
	AND	ECX,0FFFFH		;INCREASE GUSMEM-POINTER
	INC	CX
	CMP	SI,4
	JB	SHORT GDMI6
	SHL	CX,1
GDMI6:	ADD	EDI,ECX
	MOV	CS:GUS_MEM,EDI
	RET
DMA_INIT ENDP
;=============================================================================


;=============================================================================
PLAY_MUSIC PROC NEAR
	PUSH	CS
	POP	DS
	CLI
	MOV	SI,54*2
	MOV	EBP,54
	MOV	CX,908-54+1
CountLoop:
	XOR	EDX,EDX
	MOV	EAX,369DE4H
	DIV	EBP
	MOV	EDX,100
	MUL	EDX
	MOV	EBX,Voices25
	DIV	EBX
	SHR	BX,1
	ADC	BX,0
	CMP	DX,BX
	JB	SHORT NoHigherFreq
	INC	AX
NoHigherFreq:
	MOV	[FREQ_TABLE+SI],AX
	INC	BP
	ADD	SI,2
	LOOP	CountLoop
	MOV	SAM_CH,8
	MOV	MOD_STAT,0
	MOV	PATT_ROW,64
	MOVZX	AX,SONG_START
	MOV	PATT_CURRENT,AX
	MOV	PATT_SPEED,6
	MOV	PATT_COUNT,1
	MOV	DI,OFFSET SAMP_CHANS
	XOR	BX,BX
	MOV	CX,CH_NUMB
ClearVarLoop:
	MOV	[DI.FREQ_VAL],0
	MOV	[DI.VOL],0
	MOV	AL,[PAN_REGS+BX]
	SHL	AL,4
	OR	AL,[PAN_REGS+BX]
	MOV	[DI.BALANCE],AL
	INC	BX
	ADD	DI,CHAN_SIZE
	LOOP	ClearVarLoop

	XOR	BX,BX			;Set Pan Regs!!
	MOV	CX,NumVoices
LLDM14:	MOV	DX,BASE_PORT
	ADD	DX,ActiveVoicePort
	MOV	AL,NumVoices
	SUB	AL,CL
	OUT	DX,AL
	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
	MOV	AL,VoiceBalance
	OUT	DX,AL
	MOV	DX,BASE_PORT
	ADD	DX,DataHighPort
	MOV	AL,[PAN_REGS+BX]
	OUT	DX,AL
	INC	BX
	LOOP	LLDM14

	MOV	AL,125
	CALL	GO_SETBPM
	MOV	BPM_COUNT,0
	MOV	COUNTER,20
	MOV	DX,BASE_PORT		;Speaker On!!!
	MOV	AL,00000001B
	OUT	DX,AL
	STI
	CALL	IRQ_INIT
	RET
PLAY_MUSIC ENDP
;-----------------------------------------------------------------------------
STOP_MUSIC PROC NEAR
	PUSH	CS
	POP	DS
	CALL	IRQ_INIT
US_OFF:	PUSH	CS
	POP	DS
	MOV	DX,BASE_PORT		;Speaker Off!!!
	MOV	AL,00000011B
	OUT	DX,AL
	MOV	DX,BASE_PORT
	ADD	DX,ActiveVoicePort
	MOV	CX,NumVoices
VoiceClearL:
	MOV	AL,CL
	DEC	AL
	OUT	DX,AL
	INC	DX
	MOV	AL,WriteVoiceMode
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,3			;Voice Off
	OUT	DX,AL
	SUB	DX,2
	MOV	AL,VolumeCtrl
	OUT	DX,AL
	ADD	DX,2
	MOV	AL,3			;Ramp Off
	OUT	DX,AL
	SUB	DX,3
	LOOP	VoiceClearL
	RET
STOP_MUSIC 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	SHORT WU11
	CMP	VAR_BUFSEG,0
	JNE	SHORT WU13
	MOV     AX,COMP_SPEED2		;XCHANGE INIT & STOP DATA FOR DOS
	MOV     DX,COMP_SPEED3
	MOV     COMP_SPEED2,DX
	MOV     COMP_SPEED3,AX
	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     BX,4*70H                ;UHR-IRQ VERBIEGEN
	MOV     EAX,ES:[BX]
	MOV     EDX,HOLD70
	MOV     ES:[BX],EDX
	MOV     HOLD70,EAX
	JMP	SHORT 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     BX,4*8H                 ;TIMEOUT-IRQ VERBIEGEN
	MOV     EAX,ES:[BX]
	MOV     EDX,HOLD70
	MOV     ES:[BX],EDX
	MOV     HOLD70,EAX
WU12:	MOV	AL,20H
	OUT	IRQ3,AL
	OUT	IRQ1,AL
	STI
	RET
IRQ_INIT ENDP
;-----------------------------------------------------------------------------
GET_SONGMOD PROC NEAR
	MOV	AL,CS:US_MODUS
	RET
GET_SONGMOD ENDP
;-----------------------------------------------------------------------------
SET_SONGMOD PROC NEAR
	AND	AL,3
	MOV	CS:US_MODUS,AL
	PUSH	AX
	XOR	AH,AH
	TEST	AL,2
	JNZ	SHORT GSNG2
	MOV	AH,BYTE PTR CS:MUSIC_VOL
GSNG2:	CALL	SET_CDMIXER
	POP	AX
GSNG1:	RET
SET_SONGMOD ENDP

GET_SONGPOSITION PROC NEAR
	MOV	ah,BYTE PTR CS:PATT_CURRENT
	dec	ah
	MOV	al,byte ptr cs:[PATT_ROW]
	ret
GET_SONGPOSITION ENDP

SET_SONGPOSITION PROC NEAR
	PUSH	CX DI
	AND	AL,7FH
	MOV	BYTE PTR CS:PATT_CURRENT,AL
	MOV	CS:PATT_ROW,64
	MOV	DI,OFFSET SAMP_CHANS
	MOV	CX,CS:CH_NUMB
LSET1:	MOV	CS:[DI.VOL],0
	MOV	CS:[DI.INST_SET],0
	ADD	DI,CHAN_SIZE
	LOOP	LSET1
	POP	DI CX
	RET
SET_SONGPOSITION ENDP
;-----------------------------------------------------------------------------
SET_SONGLOOP PROC NEAR
	MOV	CS:SONG_LOOP,AL
	RET
SET_SONGLOOP ENDP
;-----------------------------------------------------------------------------
GET_VOLUME PROC NEAR
	MOV	AL,BYTE PTR CS:MASTER_VOLUME	;0= MIN VOLUME,255= MAX VOLUME
	MOV	BL,BYTE PTR CS:MUSIC_VOLUME	;0= MIN VOLUME,255= MAX VOLUME
	MOV	BH,BYTE PTR CS:FX_VOLUME	;0= MIN VOLUME,255= MAX VOLUME
	RET
GET_VOLUME ENDP
;-----------------------------------------------------------------------------
SET_VOLUME PROC NEAR
	MOV	BYTE PTR CS:MASTER_VOLUME,AL	;0= MIN VOLUME,255= MAX VOLUME
	MOV	BYTE PTR CS:MUSIC_VOLUME,BL	;0= MIN VOLUME,255= MAX VOLUME
	MOV	BYTE PTR 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	BYTE PTR CS:MUSIC_VOL,AH
	CALL	SET_CDMIXER
	POP	DX
	MOVZX	AX,BH
	MUL	DX
	MOV	BYTE PTR CS:FX_VOL,AH
	POP	DX AX
	RET
SET_VOLUME ENDP
;-----------------------------------------------------------------------------
SET_CDMIXER PROC NEAR
	CMP	CS:CD_MIXER,0
	JE	GCD1
	PUSH	AX DX
	MOV	DX,CS:BASE_PORT		;DETECT GUS VERSION
	ADD	DX,GUS_VERSION		;GLEICH WIE ICMIX_SEL
	IN	AL,DX
	CMP	CS:ULTRA16,0		;IST ULTRA16 ANGEGEBEN?
	JNE	SHORT GCD3
	CMP	AL,5			;GUS BEFORE 3.7 NO MIXER
	JL	SHORT GCD2
	CMP	AL,10
	JAE	SHORT GCD3
	SHR	AH,1			;ICS MIXER ON GUS 0-127
	MOV	AL,18			;CD LINE LEFT CHANNEL
	OUT	DX,AL
	ADD	DX,ICMIX_DATA-ICMIX_SEL
	MOV	AL,AH
	OUT	DX,AL
	ADD	DX,ICMIX_SEL-ICMIX_DATA
	MOV	AL,19			;CD LINE RIGHT CHANNEL
	OUT	DX,AL
	ADD	DX,ICMIX_DATA-ICMIX_SEL
	MOV	AL,AH
	OUT	DX,AL
	ADD	DX,ICMIX_SEL-ICMIX_DATA
	MOV	AL,10			;LINE IN LEFT CHANNEL
	OUT	DX,AL
	ADD	DX,ICMIX_DATA-ICMIX_SEL
	MOV	AL,AH
	OUT	DX,AL
	ADD	DX,ICMIX_SEL-ICMIX_DATA
	MOV	AL,11			;LINE IN RIGHT CHANNEL
	OUT	DX,AL
	ADD	DX,ICMIX_DATA-ICMIX_SEL
	MOV	AL,AH
	OUT	DX,AL
	JMP	SHORT GCD2
GCD3:	MOV	DX,CS:CODEC_PORT	;CODEC MIXER ON GUS MAX 31-0
	SHR	AH,3
	JZ	SHORT GCD4
	XOR	AH,80H
GCD4:	XOR	AH,9FH
	MOV	AL,4			;CD LEFT CHANNEL
	OUT	DX,AL
	INC	DX
	MOV	AL,AH
	OUT	DX,AL
	DEC	DX
	MOV	AL,5			;CD RIGHT CHANNEL
	OUT	DX,AL
	INC	DX
	MOV	AL,AH
	OUT	DX,AL
	DEC	DX
	MOV	AL,12H			;LINE IN LEFT CHANNEL
	OUT	DX,AL
	INC	DX
	MOV	AL,AH
	OUT	DX,AL
	DEC	DX
	MOV	AL,13H			;LINE IN RIGHT CHANNEL
	OUT	DX,AL
	INC	DX
	MOV	AL,AH
	OUT	DX,AL
GCD2:	POP	DX AX
GCD1:	RET
SET_CDMIXER 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
;-----------------------------------------------------------------------------
SET_IRQ_RATE PROC NEAR
	PUSH	CS
	POP	DS
	MOV	BPM_RATE,AX
	MOV	AX,BPM_VALUE
	CALL	Go_SetBPM
	MOV	CL,8
	XOR	SI,SI
SIR1:	CMP	BPM_RATE,512
	JB	SHORT SIR2
	SHL	[SAM_COUNT+SI],4
	OR	[SAM_COUNT+SI],8
	JMP	SHORT SIR3
SIR2:	CMP	[SAM_COUNT+SI],16
	JB	SHORT SIR3
	SHR	[SAM_COUNT+SI],4
SIR3:	INC	SI
	INC	SI
	INC	CL
	CMP	CL,NumVoices-1
	JB	SIR1
	RET
SET_IRQ_RATE 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)
;		+ 7 INTERRUPT TYPE      0,1 (realtime clock, timer)
;               + 8 STARTING POSITION   0-127
;               + 9 LOOP POSITION	0-127,128
;               +10 SONG MODUS		0-3
;               +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
	CMP	CX,0C242H
	JNE	SHORT NORMAL_CONFIG
	MOV	ES,DX
	MOV	AX,ES:[BX]
	MOV	BASE_PORT,AX
	ADD	AX,CODEC_BASE
	MOV	CODEC_PORT,AX
	MOV	AL,ES:[BX+2]
	AND	AX,7
	MOV	DMA_CHANNEL,AX
	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	US_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
;-----------------------------------------------------------------------------
comment	#
SEEK_LINE PROC NEAR
	CLD
	MOV     SI,OFFSET QUEUE_BUFFER
LSKL1:  PUSH    BX
LSKL2:  CMP     BYTE PTR [BX],0
	JE      SHORT GSKL1
	CMP     SI,DX
	JAE     SHORT GSKL2
	LODSB
	CMP     AL,[BX]
	JNE     SHORT GSKL3
	INC     BX      
	JMP     LSKL2
GSKL3:  POP     BX
	JMP     LSKL1
GSKL2:  POP     BX
	CLC
	RET
GSKL1:  POP     BX
	STC
	RET
SEEK_LINE 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
endif
	push	cs
	pop	ds
GLDM0:	CALL	SET_TMEM		;ALLOCATE TRACK-BUFFER
ifdef zpliku
	MOV	BX,GDDHANDLE
endif
	MOV	GDDZEIG,0
	CMP	LOADMOD_FLAG,0
	JNE	GLDM99
	MOV	CX,10			;SONG-NAME HOLEN
LLDM1:	CALL	GET_QUEUE
	JC	GLDM2
	LOOP	LLDM1
	XOR	SI,SI			;31 INSTRUMENTS
LLDM2:	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
	CALL	GET_QUEUE		;IVOLUME & FINETUNE
	PUSH	AX
	XOR	AH,AH
	MOV	[IFINETUNE+SI],AX
	POP	AX
	SHR	AX,8
	CMP	AX,40H
	JBE	SHORT GLDM9
	MOV	AX,40H
GLDM9:	MOV	[IVOLUME+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
	CMP	EAX,"NHC8"		;8CHN-MOD
	JE	SHORT GLDM3
	CMP	EAX,"8TLF"		;FLT8-MOD
	JE	SHORT GLDM3
	CMP	EAX,"ATCO"		;OCTA-MOD
	JE	SHORT GLDM3
	CMP	EAX,"NHC6"		;6CHN-MOD
	JE	SHORT GLDM16
	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
GLDM16:	MOV	CH_NUMB,6		;6-CHANNEL-MOD
	MOV	PATTERN_SIZE,1536
	MOV	AH,0
	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	PATT_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
	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
	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,PATT_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	PATT_CURRENT		;NŽCHSTES PATTERN HOLEN
	MOV	AX,PATT_CURRENT
	CMP	AX,PATTERN_NUMBER
	JB	LLDM7
	JMP	SHORT GLDM7

GLDM99:	MOV	ES,TRACK_SEG		;TRACK SEGMENT WIEDER L™SCHEN
	MOV	AH,49H
	INT	21H
	MOV	GUS_MEM,0
GLDM7:	MOV	ES,PATTERN_SEG		;PATTERN SEGMENT WIEDER L™SCHEN
	MOV	AH,49H
	INT	21H
	MOV	PATTERN_SEG,0
	CALL	INIT_DEVICE		;IS PROBABLY THE FIRST INIT
	CMP	LOADMOD_FLAG,0
	JNE	GLDM98
	MOV	BX,TRACK_NUMBER		;TRACK SEGMENT REDUZIEREN
	SHL	BX,4
	MOV	ES,TRACK_SEG
	MOV	AH,4AH
	INT	21H

	MOVZX	AX,GDDZEIG		;FILEZEIGER KORRIGIEREN
	OR	AX,AX			;BUFFER ABHŽNGEN
	JZ	SHORT GLDM30
	MOV	DX,GDDREST
	SUB	DX,AX
	JZ	SHORT GLDM30
	XOR	CX,CX
	MOV	GDDZEIG,CL
	MOV	BX,GDDHANDLE
	NEG	DX
	DEC	CX
ifdef zpliku;comment	#
	MOV	AX,4201H		;DATEIZEIGER ZURšCKBEWEGEN
	INT	21H
else;#
	add	word ptr cs:[offMod],dx
	adc	word ptr cs:[offMod][2],cx
endif
GLDM30:	MOV	AH,48H			;SAMPLE BUFFER BEREIT
	MOV	BX,2000H		;128K WEGEN 64K DMA FENSTER
	INT	21H
	MOV	GDDSEG,AX
	TEST	AX,0FFFH
	JZ	SHORT GLDM31
	AND	AX,0F000H
	ADD	AX,1000H
GLDM31:	MOV	BUFSEG,AX
	XOR	EDI,EDI			;SAMPLES LADEN
	MOV	GUS_MEM,EDI
	XOR	SI,SI
LLDM12:	PUSH	SI
	MOV	CX,[ISIZE+SI]
	JCXZ	SHORT GLDM8
	SHL	SI,1
	TEST	EDI,31
	JZ	SHORT GLDM32
	AND	EDI,-32			;32 BYTE BOUND FOR DMA
	ADD	EDI,32
GLDM32:	MOV	[IOFFSET+SI],EDI
	MOV	BX,GDDHANDLE		;SAMPLE IN BUFFER LADEN
	PUSH	DS
	XOR	DX,DX
	MOV	SI,DX
	MOV	DS,BUFSEG
ifdef zpliku;comment	#
	MOV     AH,3FH
	INT     21H
else;#
	pushf
	pushad
	push	es
	push	ds
	pop	es
	mov	ds,cs:[SegMod]
	movzx	edi,dx
	mov	esi,cs:[offmod]
	rep
	db	67h
	movsb
	mov	cs:[offmod],esi
	push	es
	pop	ds
	pop	es
	popad
	popf

endif

	SHR	CX,1
	XOR	BX,BX			;AMIGA-SAMPLE
	CALL	SEND_SAMPLE_DATA
	POP	DS
GLDM8:	POP	SI
	INC	SI
	INC	SI
	CMP	SI,62
	JB	LLDM12
	MOV	ES,GDDSEG		;SAMPLE BUFFER FREIGEBEN
	MOV	AH,49H
	INT	21H
	MOV	GDDSEG,0
GLDM98:	CLC
	JMP	SHORT GLDM15
GLDM2:	STC
GLDM15:	PUSHF
	CMP	VAR_BUFSEG,0
	JNE	SHORT GLDM97
ifdef zpliku;comment	#
	MOV	AH,3EH
	MOV	BX,GDDHANDLE
	INT	21H
endif;#
GLDM97:	POPF
GLDM1:	RET
LOAD_MOD 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
;----------------------------------------------------------------------------
; 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
;----------------------------------------------------------------------------
END_MUSIC PROC NEAR
	CALL	INIT_DEVICE
	CMP	LOADMOD_FLAG,0
	JNE	SHORT LEM3
	MOV     AH,49H
	MOV     ES,TRACK_SEG
	INT     21H
	CMP	PATTERN_SEG,0
	JE	SHORT LEM3
	MOV     AH,49H
	MOV     ES,PATTERN_SEG
	INT     21H
	MOV	PATTERN_SEG,0
LEM3:	CMP	GDDSEG,0
	JE	SHORT LEM4
	MOV     AH,49H
	MOV     ES,GDDSEG
	INT     21H
	MOV	GDDSEG,0
LEM4:	XOR	EAX,EAX
	MOV	GDDLENGTH,EAX
	MOV	GDDREST,AX
	MOV	GDDHANDLE,AX
	MOV	GDDSEG,AX
	MOV	BUFSEG,AX
	MOV	GDDZEIG,AL		;RESET VARIABLES
	MOV	SAM_CH,8
	MOV	MOD_STAT,AL
	XOR	BX,BX
	MOV	CX,11
LEM1:	MOV	WORD PTR [BPM_COUNT+BX],AX
	ADD	BX,2
	LOOP	LEM1
	MOV	CH_NUMB,4
	MOV	TRACK_NUMBER,AX
	MOV	DWORD PTR TRACK_INFO,EAX
	MOV	DWORD PTR TRACK_INFO+4,EAX
	MOV	TRACK_SEG,AX
	MOV	BX,OFFSET TRACK1_DATA
LEM2:	MOV	[BX],AL
	INC	BX
	CMP	BX,OFFSET PATTJUMPS
	JB	LEM2
	MOV	IRQCOUNT,56
	RET
END_MUSIC ENDP

IF COM_OR_OBJ
;=============================================================================
MAIN_CONT PROC NEAR
	PUSH	BP DS CS ES
	POP	DS
	SHL	DI,2
	ADD	DI,0100H
	CALL	DI			;FAR CALL
	SETC	DL
	XOR	DH,DH
	POP	DS BP			;BP IS ABSOLUTELY IMPORTANT FOR C
	RETF
MAIN_CONT ENDP
;=============================================================================
endif

CODE_SEG4 ENDS

END _MAIN4_G