Metropoli BBS
VIEWER: usmod.asm MODE: TEXT (CP437)
;
;       ╔═════════════════════════════╗
;       ║                             ║
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)
;
;           5-FX-CHANNELS, FULL MOD-FX SUPPORT, FULL 8/16-BIT DMA SUPPORT
;
DOSSEG
.MODEL TINY
STACKLENGTH     = 0100H
ASSUME CS:DGROUP, DS:DGROUP; SS:DGROUP
;=============================================================================
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	= 14		; 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

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
;=============================================================================
PROG_START_SEG  DW 0
PROG_END_SEG    DW 0
GDDLENGTH	DD 0
GDDREST		DW 0
GDDHANDLE	DW 0
;GDDMIN		DW -1
;GDDNEW		DW 0
;GDDPOSL	DW 0
;GDDPOSH	DW 0
GDDSEG		DW 0
BUFSEG		DW 0
GDDZEIG		DB 0
SAM_CH		DB 8
MOD_STAT	DB 0
US_MODUS	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,3,12,5,10,7,8
;-----------------------------------------------------------------------------
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 "FD.CFG",0
VOL_NAME	DB "FM.VOL",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
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_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 716 DUP(0)	;908
QUEUE_BUFFER	DW 128 DUP(0)
MOD_NAME	DB 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 48 DUP(0)
SAMPLE_BIG	DW 48 DUP(0)
SAM_COUNT	DW 5 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 05000H,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    ;MUST BE LAST ROW IN DATA SEGMENT!
;-----------------------------------------------------------------------------

.386
.CODE 
ORG 100H
;=============================================================================
MAIN PROC NEAR
	JMP	MAIN_CONT		;0100
	RETF
	CALL	CONFIG_INIT		;0104
	RETF
	CALL	LOAD_MOD		;0108
	RETF
	CALL	PLAY_MUSIC		;010C
	RETF
	CALL	STOP_MUSIC		;0110
	RETF
	CALL	END_MUSIC		;0114
	RETF
	CALL	LOAD_SAMPLE		;0118
	RETF
	CALL	PLAY_SAMPLE		;011C
	RETF
	CALL	END_SAMPLE		;0120
	RETF
	JMP	NOFUNC			;0124
NOFUNC:	RETF
	CALL	GET_VOLUME		;0128
	RETF
	CALL	SET_VOLUME		;012C
	RETF
	CALL	SET_SONGLOOP		;0130
	RETF
	CALL	GET_SONGPOSITION	;0134
	RETF
	CALL	SET_SONGPOSITION	;0138
	RETF
	CALL	GET_SONGMOD		;013C
	RETF
	CALL	SET_SONGMOD		;0140
	RETF
	CALL	US_OFF			;0144
	RETF
	CALL	INIT_DEVICE		;0148
	RETF
	CALL	LOAD_MOD_FROM_VOL	;014C
	RETF
	CALL	LOAD_SAMPLE_FROM_VOL	;0150
	RETF
MAIN ENDP
;=============================================================================
MAIN_CONT:
	MOV	AX,CS			;DS SET
	MOV	DS,AX
	MOV     PROG_START_SEG,ES       ;PROGRAMM START
	MOV     AX,SS                   ;AND -END SET
	MOV     BX,OFFSET PROG_END
	ADD     BX,STACKLENGTH
	MOV     SP,BX
	SHR     BX,4
	INC     BX
	ADD     AX,BX
	MOV     PROG_END_SEG,AX
	XOR	BX,BX
GL1:	MOV	AL,ES:[82H+BX]
	OR	AL,AL
	JZ	SHORT GL2
	CMP	AL,20H
	JE	SHORT GL2
	CMP	AL,0DH
	JE	SHORT GL2
	MOV	[MOD_NAME+BX],AL
	INC	BX
	CMP	BX,40H
	JB	GL1
GL2:	OR	BX,BX
	JZ	GMEND
	XOR	AL,AL
	MOV	[MOD_NAME+BX],0
	MOV     BX,PROG_END_SEG         ;RESIZE OWN ALLOCATION
	SUB     BX,PROG_START_SEG
	MOV     ES,PROG_START_SEG
	MOV     AH,4AH
	INT     21H
;-----------------------------------------------------------------------------
; INITIALIZING & STARTING
;	MOV	AL,255			;SET MAXIMUM VOLUME
;	MOV	BL,AL
;	MOV	BH,AL
;	CALL	SET_VOLUME
	CALL	CONFIG_INIT		;GET CONFIG
	MOV	DX,OFFSET MOD_NAME	;FIRST, TRY LOADING
	CALL	LOAD_MOD
	JNC	SHORT GM1
	MOV	AH,9
	MOV	DX,OFFSET ERROR1_TEXT
	INT	21H
	JMP	SHORT GM4
GM1:	MOV	DX,OFFSET SAMPLE_NAME	;GET SAMPLE
	MOV	CL,80H			;PC-SAMPLE
	CALL	LOAD_SAMPLE
	JNC	SHORT GM2
	MOV	AH,9
	MOV	DX,OFFSET ERROR2_TEXT
	INT	21H
GM2:	CALL	PLAY_MUSIC		;TRY STARTING
;-----------------------------------------------------------------------------
; THIS COULD BE THE MAIN ROUTINE
	MOV	AH,9
	MOV	DX,OFFSET OUT_TEXT
	INT	21H
LM1:	XOR	AH,AH
	INT	16H
	CMP	AL,27
	JE	SHORT GM5
	CMP	AL,"+"
	JNE	SHORT G1
	CALL	GET_VOLUME
	INC	AL
	CALL	SET_VOLUME
	JMP	LM1
G1:	CMP	AL,"-"
	JNE	SHORT G2
	CALL	GET_VOLUME
	DEC	AL
	CALL	SET_VOLUME
	JMP	LM1
G2:	CMP	AL,"9"
	JNE	SHORT G3
	MOV	AL,0
	CALL	SET_SONGLOOP
	JMP	LM1
G3:	CMP	AL,"0"
	JNE	SHORT G4
	INC	US_MODUS
	AND	US_MODUS,3
	JMP	LM1
G4:	CMP	AL,"1"
	JNE	LM1
	XOR	BX,BX			;HANDLE
	MOV	CX,22222		;FREQUENCE
	CALL	PLAY_SAMPLE
	JMP	LM1
;-----------------------------------------------------------------------------
; CUTTING OFF
GM5:	CALL	STOP_MUSIC		;STOP MUSIC
	CALL	END_SAMPLE		;UNLOAD SAMPLES
GM4:	CALL	END_MUSIC		;UNLOAD MUSIC
GMEND:	MOV     AX,4C00H                ;DOS
	INT     21H
;=============================================================================


;=============================================================================
ALIGN 2
CONTROL_CHANNELS PROC NEAR
	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
	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	COUNTER,4
	JE	SHORT ClearNotes
	CMP	COUNTER,5
	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,10000
	MOV	BP,BX
WITH_SOUND1:
	CALL	SEND_RAMP
NoVoiceOff:
	ADD	DI,CHAN_SIZE
	LOOP	StopVoices
	JMP	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,10000
	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	EndPattern
;-----------------------------------------------------------------------------
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
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
	XOR	AH,AH
	SHL	AX,1
	MOV	BL,5
	DIV	BL			; EFFECTS 50Hz
	MOV	DL,AL
	XOR	DH,DH			; PATT_SPEED Hz=2*BPM/5
	XOR	AX,AX
	MOV	BX,1024
	DIV	BX
	MOV	WORD PTR BPM_SPEED,AX
	XOR	AX,AX
	DIV	BX
	MOV	WORD PTR BPM_SPEED+2,AX
	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
EndPattern:
	CALL	CONTROL_SAMPLE
	POP	ES DS
	POP	EBP EDI ESI EDX ECX EBX EAX
	CMP	CS:SYSTEM,0
	JE	SHORT WT7
	DEC	CS:IRQCOUNT
	JNZ	SHORT WT7
	MOV	CS:IRQCOUNT,56
	JMP	DWORD PTR CS:[HOLD70]
WT7:	IRET
CONTROL_CHANNELS ENDP
;-----------------------------------------------------------------------------
GET_PERIOD_INDEX PROC NEAR
	MOV	BP,BX
	XOR	BH,BH
	MOV	DX,6000H		;BINARY SEARCH
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			;FOUND
	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
;-----------------------------------------------------------------------------
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,13
	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,9			;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
	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= NUMBER OF WORDS, EDI= GUSMEM POINTER, BX= 0000H AMIGA, 8080H PC SAMPLE
; DS:SI= POINTER TO SAMPLE DATA
;-----------------------------------------------------------------------------
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		;MAKE SAMPLE 1 WORD LONGER
	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]
	OUT	DX,AL			;DMA MASTER CLEAR

	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 LONGER-1 BYTE IS LAST 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			;MAKE SAMPLE 1 WORD LONGER
	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			;CONVERT ADDRESS TO PAGE AND OFFSET
	SHL	DX,4
	SHR	AH,4			;PAGE
	ADD	BX,DX			;OFFSET NEW
	ADC	AH,0
	MOV	AL,AH
	MOV	SI,CS:DMA_CHANNEL
	CMP	SI,4
	JB	SHORT GDMI1
	SHRD	BX,AX,1			;ADDRESS FOR 16-BIT DMA
	JMP	SHORT GDMI2
GDMI1:	SHL	CX,1			;COUNTER FOR 8-BIT DMA
	INC	CX			;SAMPLE IS 1 WORD LONGER
GDMI2:	MOVZX	DX,CS:[DMA_MASK+SI]
	MOV	AL,BYTE PTR CS:DMA_CHANNEL
	OR	AL,4
	OUT	DX,AL			;MASK DMA-CHANNEL
	MOVZX	DX,CS:[DMA_MOD+SI]
	AND	AL,3
	OR	AL,01001000B
	OUT	DX,AL			;DMA-MODUS FOR 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			;DEMASK DMA-KANAL

	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]
	OUT	DX,AL			;DMA MASTER CLEAR
	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,Voices14
	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
	MOV	PATT_CURRENT,0
	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

	XOR	AX,AX
	MOV	DX,50
	MOV	BX,1024
	DIV	BX
	MOV	WORD PTR BPM_SPEED,AX
	XOR	AX,AX
	DIV	BX
	MOV	WORD PTR BPM_SPEED+2,AX
	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 SWAPPING; USES THE REAL-TIME-CLOCK OR TIMER IRQ
;-----------------------------------------------------------------------------
IRQ_INIT PROC NEAR
	CLI
	XOR     AX,AX
	MOV     ES,AX
	CMP	SYSTEM,0
	JNE	SHORT WU11
	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		;CLOCK-IRQ-RATE (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		;CLOCK-IRQ-MODUS
	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-/MASK
	AND	AL,0FEH
	MOV	DL,DH
	AND	DL,1
	OR	AL,DL
	OUT	IRQ4,AL
	MOV     BX,4*70H                ;UHR-IRQ DETOUR
	MOV     EAX,ES:[BX]
	MOV     EDX,HOLD70
	MOV     ES:[BX],EDX
	MOV     HOLD70,EAX
	JMP	SHORT WU12
WU11:	MOV     AX,COMP_SPEED4		;FOR WINDOWS
	MOV     DX,COMP_SPEED5
	MOV     COMP_SPEED4,DX
	MOV     COMP_SPEED5,AX
	MOV     AL,00110110B            ;SET TIMER0 TO 1.024 KHZ
	OUT     PIT1,AL                 ;DIVIDER =1193
	MOV     AL,DL
	OUT     TIMER0,AL
	JMP     SHORT OUT40
OUT40:  MOV     AL,DH
	OUT     TIMER0,AL
	MOV     BX,4*8H                 ;TIMEOUT-IRQ DETOUR
	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
	RET
SET_SONGMOD ENDP
;-----------------------------------------------------------------------------
GET_SONGPOSITION PROC NEAR
	MOV	AL,BYTE PTR CS:PATT_CURRENT
	RET
GET_SONGPOSITION ENDP
;-----------------------------------------------------------------------------
SET_SONGPOSITION PROC NEAR
	AND	AL,7FH
	MOV	BYTE PTR CS:PATT_CURRENT,AL
	MOV	CS:PATT_ROW,64
	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
	POP	DX
	MOVZX	AX,BH
	MUL	DX
	MOV	BYTE PTR CS:FX_VOL,AH
	POP	DX AX
	RET
SET_VOLUME ENDP
;-----------------------------------------------------------------------------
; START FX SAMPLE
; BX= SAMPLE-HANDLE, CX= FREQUENCE (HZ)
;-----------------------------------------------------------------------------
PLAY_SAMPLE PROC NEAR
	PUSH	CS
	POP	DS
	TEST	US_MODUS,1
	JNZ	GPSMP1
	CLI
	MOV	DI,OFFSET SAMPLE_CHAN
	MOV	[DI.OFFSET_ADD],0
	MOV	[DI.REPEAT],0
	MOV	AX,[SAMPLE_BIG+BX]
	MOV	[DI.LEN],AX
	MOV	DX,1024
	MUL	DX
	DIV	CX
	SUB	AX,64
	JNC	SHORT LOW_COUNT
	MOV	AX,1
LOW_COUNT:
	MOVZX	SI,SAM_CH
	SUB	SI,8
	SHL	SI,1
	MOV	[SAM_COUNT+SI],AX
	MOV	AX,100
	MUL	CX
	MOV	BP,Voices14
	DIV	BP
	SHR	BP,1
	ADC	BP,0
	CMP	DX,BP
	JB	SHORT NoHigherFreq2
	INC	AX
NoHigherFreq2:
	MOV	[DI.FREQ_VAL],AX
	SHL	BX,1
	MOV	EAX,[SAMPLE_MEM+BX]
	MOV	[DI.SAMP_OFF],EAX
	MOV	DX,BASE_PORT
	ADD	DX,CommandPort
	DEC	DX
	MOV	AL,SAM_CH
	OUT	DX,AL
	INC	DX
	MOV	AH,3
	CALL	SEND_WRITE_VOICE
	CALL	WAIT_PORT
	CALL	SEND_SAMPLE_START
	CALL	SEND_SAMPLE_END
	CALL	SEND_SAMPLE_LOOP
	MOV	AH,3
	CALL	SEND_WRITE_VOICE
	MOV	BP,GUS_VOL		;SET VOLUME
	MOV	BX,FX_VOL
	INC	BX
	SHR	BX,2
	CMP	BL,40H
	JBE	SHORT FIXVL
	MOV	BL,40H
FIXVL:	SHL	BX,1
	MOV	BX,[GUS_VOL+BX]
	XCHG	BX,BP
	CALL	SEND_RAMP
	MOV	AL,SetVoiceFreq		;SET FREQUENCE
	OUT	DX,AL
	INC	DX
	MOV	AX,[DI.FREQ_VAL]
	OUT	DX,AX
	DEC	DX
	DEC	DX			;START VOICE
	MOV	AL,SAM_CH
	OUT	DX,AL
	INC	DX
	MOV	AH,0			;NO LOOP
	CALL	SEND_WRITE_VOICE
	CALL	WAIT_PORT
	STI
	INC	SAM_CH
	CMP	SAM_CH,13
	JB	SHORT GPSMP1
	MOV	SAM_CH,8
GPSMP1:	RET
PLAY_SAMPLE ENDP
;-----------------------------------------------------------------------------
END_SAMPLE PROC NEAR
	MOV	CS:SAMPLE_ZEIG,0
	RET
END_SAMPLE ENDP
;=============================================================================


;=============================================================================
; LOAD CONFIG DATA (PARSER)
;-----------------------------------------------------------------------------
CONFIG_INIT PROC NEAR
	MOV	AX,CS			;SAVE SEGMENT OF CODE
	MOV	DS,AX
	MOV	WORD PTR HOLD70+2,AX	;THIS LINE IS IMPORTANT
	MOV     DX,OFFSET CONFIG_NAME
	MOV     AH,3DH
	MOV     AL,80H
	INT     21H
	JC      SHORT GCFG1
	MOV     GDDHANDLE,AX
LCFG1:  XOR     SI,SI
	MOV     DX,OFFSET QUEUE_BUFFER
LCFG2:  MOV     AH,3FH
	MOV     BX,GDDHANDLE
	MOV     CX,1
	INT     21H
	JC      SHORT GCFG2
	OR      AX,AX
	JZ      SHORT GCFG2
	MOV     DI,DX
	CMP     BYTE PTR [DI],0AH
	JE      SHORT GCFG6
	INC     DX
	INC     SI
	CMP     SI,256
	JB      LCFG2
GCFG6:  MOV     BX,OFFSET CFG_TEXT2
	CALL    SEEK_LINE
	JNC     SHORT GCFG4
	LODSB
	AND     AL,3
	MOV	US_MODUS,AL
	JMP     LCFG1
GCFG4:  MOV     BX,OFFSET CFG_TEXT3
	CALL    SEEK_LINE
	JNC     SHORT GCFG5
	INC	SI
	LODSB
	DEC	AL
	AND	AL,7
	INC	AL
	SHL	AL,4
	MOV	AH,2
	MOV	BASE_PORT,AX
	JMP     LCFG1
GCFG5:  MOV     BX,OFFSET CFG_TEXT5
	CALL    SEEK_LINE
	JNC     SHORT GCFG7
	LODSB
	AND	AX,7
	MOV	DMA_CHANNEL,AX
	JMP	LCFG1
GCFG7:	MOV     BX,OFFSET CFG_TEXT7
	CALL    SEEK_LINE
	JNC     LCFG1
	LODSB
	AND     AL,1
	MOV     SYSTEM,AL
	JMP     LCFG1
GCFG2:  MOV     BX,GDDHANDLE
	MOV     AH,3EH
	INT     21H
GCFG1:  RET
CONFIG_INIT ENDP
;-----------------------------------------------------------------------------
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 LOAD ROUTINES
;
;=============================================================================
LOAD_MOD_FROM_VOL PROC NEAR
	CALL	SET_VOLUME_POINTER
	JMP	SHORT GLDM0
LOAD_MOD_FROM_VOL ENDP
;-----------------------------------------------------------------------------
; LOAD A MODFILE
; DS:DX= FILENAME
;-----------------------------------------------------------------------------
LOAD_MOD PROC NEAR
	MOV	AX,3D00H		;OPEN MOD
	INT	21H
	JC	GLDM1
	PUSH	CS
	POP	DS
	MOV	GDDHANDLE,AX
GLDM0:	CALL	SET_TMEM		;ALLOCATE TRACK-BUFFER
	MOV	BX,GDDHANDLE
	MOV	GDDZEIG,0
	MOV	CX,10			;GET SONG-NAME
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		;NO MORE THAN 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		;GET PATTERNS AND SPLIT INTO TRACKS 
	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		;INTEGRATE TRACK1-8
	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			;MAKE TRACKLIST
	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		;GET NEXT PATTERN
	MOV	AX,PATT_CURRENT
	CMP	AX,PATTERN_NUMBER
	JB	LLDM7
GLDM7:	MOV	ES,PATTERN_SEG		;CLEAR PATTERN SEGMENT
	MOV	AH,49H
	INT	21H
	MOV	PATTERN_SEG,0
	MOV	BX,TRACK_NUMBER		;RESIZE TRACK SEGMENT
	SHL	BX,4
	MOV	ES,TRACK_SEG
	MOV	AH,4AH
	INT	21H

	MOVZX	AX,GDDZEIG		;SET FILEPOINTER BACK
	OR	AX,AX			;BUFFER QUIT
	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
	MOV	AX,4201H
	INT	21H
GLDM30:	MOV	AH,48H			;SAMPLE BUFFER READY
	MOV	BX,2000H		;128K BECAUSE OF 64K DMA PAGE
	INT	21H
	MOV	GDDSEG,AX
	TEST	AX,0FFFH
	JZ	SHORT GLDM31
	AND	AX,0F000H
	ADD	AX,1000H
GLDM31:	MOV	BUFSEG,AX
	CALL	INIT_DEVICE		;IS PROBABLY THE FIRST INIT
	XOR	EDI,EDI			;LOAD SAMPLES
	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
	PUSH	DS
	XOR	DX,DX
	MOV	SI,DX
	MOV	DS,BUFSEG
	MOV     AH,3FH
	INT     21H
	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		;CLEAR SAMPLE BUFFER
	MOV	AH,49H
	INT	21H
	MOV	GDDSEG,0
	CLC
	JMP	SHORT GLDM15
GLDM2:	STC
GLDM15:	PUSHF
	MOV	AH,3EH
	MOV	BX,GDDHANDLE
	INT	21H
	POPF
GLDM1:	RET
LOAD_MOD ENDP
;-----------------------------------------------------------------------------
; GET A WORD FROM BUFFER
; IN: AX= WORD, BX= HANDLE
;-----------------------------------------------------------------------------
GET_QUEUE PROC NEAR
	CMP     GDDZEIG,0
	JNE     SHORT GTQ1
	PUSH	CX DX
	MOV     DX,OFFSET QUEUE_BUFFER
	MOV     CX,256
	MOV     AH,3FH
	INT     21H
	MOV	GDDREST,AX
	POP	DX CX
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
;----------------------------------------------------------------------------
; MEMORY FOR TRACKS, CARRY-FLAG 0=OK 1=ERROR
;----------------------------------------------------------------------------
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
	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
;=============================================================================
; LOAD A SAMPLE
; INPUT: DS:DX= FILENAME, CL= 00H AMIGA-SAMPLE, 80H PC-SAMPLE
; OUTPUT: AX= SAMPLE-HANDLE FOR PLAYING
;-----------------------------------------------------------------------------
LOAD_SAMPLE_FROM_VOL PROC NEAR
	PUSH	CX
	CALL	SET_VOLUME_POINTER
	POP	CX
	MOV	AX,WORD PTR GDDLENGTH
	JMP	SHORT GSMP0
LOAD_SAMPLE_FROM_VOL ENDP
;-----------------------------------------------------------------------------
LOAD_SAMPLE PROC NEAR
	MOV	AX,3D00H		;OPEN SAMPLE
	INT	21H
	JC	GSMP1
	PUSH	CS
	POP	DS
	MOV	GDDHANDLE,AX
	MOV	BX,AX
	PUSH	CX
	CALL	GET_FILESIZE
	POP	CX
GSMP0:	AND	CL,80H
	MOV	CH,CL
	PUSH	DS CX
	MOV	GDDZEIG,0
	MOV	CX,AX
	AND	CX,0FFFEH
	MOV	AH,48H			;SAMPLE BUFFER READY
	MOV	BX,2000H		;128K BECAUSE OF 64K DMA PAGE
	INT	21H
	MOV	GDDSEG,AX
	TEST	AX,0FFFH
	JZ	SHORT GSMP2
	AND	AX,0F000H
	ADD	AX,1000H
GSMP2:	MOV	BUFSEG,AX
	MOV	EDI,GUS_MEM
	TEST	EDI,31
	JZ	SHORT GSMP3
	AND	EDI,-32			;32 BYTE BOUND FOR DMA
	ADD	EDI,32
GSMP3:	MOV	SI,SAMPLE_ZEIG
	MOV	[SAMPLE_BIG+SI],CX
	SHL	SI,1
	MOV	[SAMPLE_MEM+SI],EDI
	MOV	BX,GDDHANDLE		;SAMPLE IN BUFFER
	XOR	DX,DX
	MOV	SI,DX
	MOV	DS,BUFSEG
	MOV     AH,3FH
	INT     21H
	SHR	CX,1
	POP	BX
	CLD
	CALL	SEND_SAMPLE_DATA
	POP	DS
	MOV	ES,GDDSEG		;CLEAR SAMPLE BUFFER
	MOV	AH,49H
	INT	21H
	MOV	GDDSEG,0
	MOV	BX,GDDHANDLE
	MOV	AH,3EH
	INT	21H
	MOV	AX,SAMPLE_ZEIG
	ADD	SAMPLE_ZEIG,2
	CLC
GSMP1:	RET
LOAD_SAMPLE ENDP
;-----------------------------------------------------------------------------
GET_FILESIZE PROC NEAR
	MOV	AX,4202H
	XOR	CX,CX
	XOR	DX,DX
	INT	21H
	PUSH	AX
	MOV	AX,4200H
	XOR	CX,CX
	XOR	DX,DX
	INT	21H
	POP	AX
	RET
GET_FILESIZE ENDP
;-----------------------------------------------------------------------------
SET_VOLUME_POINTER PROC NEAR
	PUSH	CS
	POP	DS
	MOV	BP,AX
	MOV     DX,OFFSET VOL_NAME
	MOV     AX,3D80H
	INT     21H
	JC      GLDM1
	MOV     GDDHANDLE,AX
	MOV	BX,AX
;	CMP	BP,GDDMIN
;	JAE	SHORT LGDM3
;	MOV	GDDNEW,1
;	MOV	GDDMIN,BP
;	JMP	SHORT LGDM1
;LGDM3:	SUB	BP,GDDMIN
;	INC	BP
;	MOV     DX,GDDPOSL
;	MOV     CX,GDDPOSH
;	MOV     AX,4200H
;	INT     21H
LGDM1:  MOV     DX,OFFSET GDDLENGTH
	MOV     CX,4
	MOV     AH,3FH
	INT     21H
	DEC     BP
	JZ      SHORT LGDM2
	MOV     DX,WORD PTR GDDLENGTH
	MOV     CX,WORD PTR GDDLENGTH+2
	MOV	AX,4201H
	INT     21H
;	CMP	BP,1
;	JNE	LGDM1
;	CMP	GDDNEW,1
;	JNE	LGDM1
;	MOV	GDDNEW,0
;	MOV	GDDPOSL,AX	
;	MOV	GDDPOSH,DX
	JMP     LGDM1
LGDM2:	RET
SET_VOLUME_POINTER ENDP
;=============================================================================

END MAIN
[ RETURN TO DIRECTORY ]