;ﾚﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄｿ
;ｳ  FILENAME: PPSTRACK.ASM   Version 1.10				     ｳ
;ｳ									     ｳ
;ｳ  DATE    : July 15, 1992						     ｳ
;ｳ                                                                           ｳ
;ｳ  Ideal Mode -- Turbo Assembler v2.01 and above			     ｳ
;ｳ                                                                           ｳ
;ｳ  DESCRIPTION: This file includes all routines for "tracking" music        ｳ
;ｳ		 modules.						     ｳ
;ﾀﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾙ

	ideal				; Use TASM's Ideal mode.
	model	Small,Pascal		; Define the memory model.
	P286				; Set up for 286 instructions.
	jumps				; Have TASM automatically resolve out-
					; of-range jumps.

	include "pps.inc"

dataseg

;ﾚﾄｿ Protracker specific
;ﾀﾄﾙ variables.
mt_speed                db      0
mt_counter              db      0
mt_PatternPos           dw      0
mt_SongPos              db      0
mt_PattDelayTime2       db      0
mt_PattDelayTime        db      0
mt_PBreakFlag           db      0
mt_PBreakPos            db      0
mt_PosJumpFlag          db      0
mt_LowMask              db      0FFh

mt_FunkTable            db      0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128
 
mt_VibratoTable:        db        0, 24, 49, 74, 97,120,141,161
                        db      180,197,212,224,235,244,250,253
                        db      255,253,250,244,235,224,212,197
                        db      180,161,141,120, 97, 74, 49, 24
 
mt_PeriodTable:
; Tuning 0, Normal
        dw    856,808,762,720,678,640,604,570,538,508,480,453
        dw    428,404,381,360,339,320,302,285,269,254,240,226
        dw    214,202,190,180,170,160,151,143,135,127,120,113
; Tuning 1
        dw    850,802,757,715,674,637,601,567,535,505,477,450
        dw    425,401,379,357,337,318,300,284,268,253,239,225
        dw    213,201,189,179,169,159,150,142,134,126,119,113
; Tuning 2
        dw    844,796,752,709,670,632,597,563,532,502,474,447
        dw    422,398,376,355,335,316,298,282,266,251,237,224
        dw    211,199,188,177,167,158,149,141,133,125,118,112
; Tuning 3
        dw    838,791,746,704,665,628,592,559,528,498,470,444
        dw    419,395,373,352,332,314,296,280,264,249,235,222
        dw    209,198,187,176,166,157,148,140,132,125,118,111
; Tuning 4
        dw    832,785,741,699,660,623,588,555,524,495,467,441
        dw    416,392,370,350,330,312,294,278,262,247,233,220
        dw    208,196,185,175,165,156,147,139,131,124,117,110
; Tuning 5
        dw    826,779,736,694,655,619,584,551,520,491,463,437
        dw    413,390,368,347,328,309,292,276,260,245,232,219
        dw    206,195,184,174,164,155,146,138,130,123,116,109
; Tuning 6
        dw    820,774,730,689,651,614,580,547,516,487,460,434
        dw    410,387,365,345,325,307,290,274,258,244,230,217
        dw    205,193,183,172,163,154,145,137,129,122,115,109
; Tuning 7
        dw    814,768,725,684,646,610,575,543,513,484,457,431
        dw    407,384,363,342,323,305,288,272,256,242,228,216
        dw    204,192,181,171,161,152,144,136,128,121,114,108
; Tuning -8
        dw    907,856,808,762,720,678,640,604,570,538,508,480
        dw    453,428,404,381,360,339,320,302,285,269,254,240
        dw    226,214,202,190,180,170,160,151,143,135,127,120
; Tuning -7
        dw    900,850,802,757,715,675,636,601,567,535,505,477
        dw    450,425,401,379,357,337,318,300,284,268,253,238
        dw    225,212,200,189,179,169,159,150,142,134,126,119
; Tuning -6
        dw    894,844,796,752,709,670,632,597,563,532,502,474
        dw    447,422,398,376,355,335,316,298,282,266,251,237
        dw    223,211,199,188,177,167,158,149,141,133,125,118
; Tuning -5
        dw    887,838,791,746,704,665,628,592,559,528,498,470
        dw    444,419,395,373,352,332,314,296,280,264,249,235
        dw    222,209,198,187,176,166,157,148,140,132,125,118
; Tuning -4
        dw    881,832,785,741,699,660,623,588,555,524,494,467
        dw    441,416,392,370,350,330,312,294,278,262,247,233
        dw    220,208,196,185,175,165,156,147,139,131,123,117
; Tuning -3
        dw    875,826,779,736,694,655,619,584,551,520,491,463
        dw    437,413,390,368,347,328,309,292,276,260,245,232
        dw    219,206,195,184,174,164,155,146,138,130,123,116
; Tuning -2
        dw    868,820,774,730,689,651,614,580,547,516,487,460
        dw    434,410,387,365,345,325,307,290,274,258,244,230
        dw    217,205,193,183,172,163,154,145,137,129,122,115
; Tuning -1
        dw    862,814,768,725,684,646,610,575,543,513,484,457
        dw    431,407,384,363,342,323,305,288,272,256,242,228
        dw    216,203,192,181,171,161,152,144,136,128,121,114
 


codeseg

;---------------------------------------------------
; Format of a note:
;
;                   00           00           00           00
;                   ||           ||           ||           ||
;                   /\           //           /\           \\
;	  MSB of Ins.	  Note	      LSB Ins. Spec. Com.   Data for special
;

;ﾕﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍｸ
;ｳ NAME       : sd_UpdateChannels					     ｳ
;ｳ									     ｳ
;ｳ ENTRY      : None							     ｳ
;ｳ									     ｳ
;ｳ RETURN     : None							     ｳ
;ｳ									     ｳ
;ｳ DESCRIPTION: This procedure shouldn't need to be called by anything else  ｳ
;ｳ		but the interrupt (ever).  It handles all note updating,     ｳ
;ｳ		special effects, pointers, etc. 			     ｳ
;ｳ									     ｳ
;ｳ		*** This code came directly from the Amiga Protracker	     ｳ
;ｳ		    playback code, written by Lars "Zap" Hamre.  Give this   ｳ
;ｳ		    guy a pat on the back for such excellent code.	     ｳ
;ｳ									     ｳ
;ｳ		*** Converted by Joshua C. Jensen.			     ｳ
;ｳ									     ｳ
;ｳ BUGS       : Or rather, non-implementations.  Command EF - Funk it is     ｳ
;ｳ		not all the way implemented.  Command E0 - Filter is not     ｳ
;ｳ		implemented at all.  It is Amiga-specific, directly with     ｳ
;ｳ		the Paula chip. 					     ｳ
;ｳ                                                                           ｳ
;ｳ		For some reason, Porta Up has problems every so often.	     ｳ
;ｳ                                                                           ｳ
;ｳ		All commands have been tested fully except for Command 7,    ｳ
;ｳ		Tremolo.  But, since it is an exact duplicate of the	     ｳ
;ｳ		Protracker code, it should work.			     ｳ
;ﾔﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍﾍｾ
proc    sd_UpdateChannels near
	mov	ax,@data		; Put the pointer to the @code segment
	mov	ds,ax			; into the data segment
	mov	es,ax			; and extra segment
	cmp	[Byte MStatus],1	; Are we done yet???
	jnz	mt_ContinueUpdate	; Nope.
	ret				; Yes, don't update anything.

mt_ContinueUpdate:
	inc	[Byte mt_counter]	; Increment our counter.
	mov	al,[mt_counter] 	; Load it into AL.
	cmp	al,[mt_speed]		; Does it match the current speed?
	jb	mt_NoNewNote		; No, just do fx.
	mov	[Byte mt_counter],0
	cmp	[Byte mt_PattDelayTime2],0
	jz	mt_GetNewNote
	call	mt_NoNewAllChannels	; Otherwise, just do fx only.
	jmp	mt_dskip		; Then, jump to update block values.

mt_NoNewNote:
	call	mt_NoNewAllChannels	; Do fx.
	jmp	mt_NoNewPosYet		; We don't update block values when we are just doing fx.

mt_NoNewAllChannels:
	mov	si,offset Channel1	; Do Channel 1
	mov	bp,offset Channel1Seg
	call	mt_CheckEfx		; Check the fx for this channel.
	mov	si,offset Channel2	; Do Channel 2
	mov	bp,offset Channel2Seg
	call	mt_CheckEfx		; Check the fx for this channel.
	mov	si,offset Channel3	; Do Channel 3
	mov	bp,offset Channel3Seg
	call	mt_CheckEfx		; Check the fx for this channel.
	mov	si,offset Channel4	; Do Channel 4
	mov	bp,offset Channel4Seg
	jmp	mt_CheckEfx		; Check the fx for this channel.

mt_GetNewNote:
        xor     ax,ax
	mov	al,[mt_SongPos] 	; Get the current sequence position.
	add	ax,[SequenceOffset]	; Pick up the pattern from the list.
	mov	di,ax			; Set di to point to it.
	xor	ax,ax			; Clear out AX.
	mov	al,[di+offset Header]	; Load in the block.
	shl	al,1			; By multiplying it by two, we can
	mov	di,offset PatternLoc	; figure out in the block segment list
	add	di,ax			; where it is so we can set up a pointer.
	mov	es,[di] 		; Get the segment.
	mov	di,[mt_PatternPos]	; Store in DI the current position
					; in the block.

	mov	si,offset Channel1	; Set pointers for the channel 1
	mov	bp,offset Channel1Seg	; information and
	call	mt_PlayVoice		; update the channel.
	mov	si,offset Channel2	; Set pointers for the channel 2
	mov	bp,offset Channel2Seg	; information and
	call	mt_PlayVoice		; update the channel.
	mov	si,offset Channel3	; Set pointers for the channel 3
	mov	bp,offset Channel3Seg	; information and
	call	mt_PlayVoice		; update the channel.
	mov	si,offset Channel4	; Set pointers for the channel 4
	mov	bp,offset Channel4Seg	; information and
	call	mt_PlayVoice		; update the channel.

	jmp	mt_dskip		; Update the block pointer values.

mt_PlayVoice:
	cmp	[Word si],0		; See if there is a note.
	jnz	mt_plvskip		; No, go on.
	cmp	[Word si+2],0
	jnz	mt_plvskip
	call	mt_PerNop		; Otherwise, figure out the frequency.
mt_plvskip:
	mov	ax,[es:di]		; Load this channel's information
	mov	[si+MS.Note],ax 	; from the actual pattern block and
	mov	ax,[es:di+02h]		; into our own internal structure
	mov	[Word si+MS.cmd],ax	; to access it from.
	add	di,4			; Increment past the stuff we just
					; moved.

	mov	al,[si+MS.cmd]		; Here we are figuring out which
	and	al,0F0h 		; instrument needs to be played by
	shr	al,4			; masking and shifting the approp. bits.
        mov     ah,[Byte si+MS.Note]    ; In order to obtain 31 instruments,
	and	ah,0F0h 		; we need to OR this bit into the
	or	al,ah			; instrument byte.  Is there an ins?
	jz	mt_SetRegs
	mov	bl,al			; Temporarily store the instrument.
	mov	TSIns,al		; Store it in the structure.
	mov	[si+MS.SampleNum],al	; Store it in the MS structure.
	mov	bh,30			; 30 is the size of an instrument
	mul	bh			; structure.  Multiply it to find its
	mov	dx,ax			; location in the header and save it.

	xor	bh,bh			; Clear out BH.
	dec	bl			; Decrement the instrument by one so
	shl	bx,1			; we can find an address in the
	add	bx,offset InsLoc	; instrument segment array.
	mov	ax,[bx] 		; Get the segment.
	mov	[si+MS.start],ax	; Store it in our structure.
	mov	bx,dx			; Load DX into BX.
	add	bx,+0Ch 		; Point bx to the sample.length.
	mov	ax,[bx+offset Header]	; Get the length.
	mov	[si+MS.Length],ax	; Store it appropriately.
	mov	[si+MS.RealLength],ax
	mov	ax,[bx+offset Header+02h] ; Get the instrument volume and fine tune.
	mov	[Word si+MS.FineTune],ax ; Store it appropriately.
        mov     al,ah                   ; Put the volume in al.
        mul     [si+MS.MasterVolume]    ; Multiply by the MasterVolume to get
	mov	TSVol1,ah		; a relative volume and store it.  Idea
					; from the MED module playback code.
	mov	cx,[bx+offset Header+06h] ; Get Repeat length
	cmp	cx,4			; If the length is less than four,
	jb	mt_NoLoop		; then there is no loop.
	mov	ax,[bx+offset Header+04h]  ; Get the Repeat start.
	shl	ax,1			; Otherwise, times it by 2.
mt_DoInsPointer2:
	mov	TSRepeat,ax		; Move it into the appropriate
	mov	[si+MS.LoopStart],ax	; structures and locations.
        mov     [si+MS.WaveStart],ax
	mov	[si+MS.RepLen],cx	; Move the length into its storage.
	; We're figuring out the offset of where the repeat length breaks.
	add	ax,cx			; Add on the offset.
	add	ax,cx			; Add it again.
	sub	ax,3
	mov	TSRepeatLen,ax		; Store it.
	jmp	mt_SetRegs		; Skip the no loop part.

mt_NoLoop:
	xor	ax,ax			; Zero out AX.
	mov	TSRepeatLen,ax		; Make sure that no loop exists and
	mov	TSRepeat,ax
	mov	[si+MS.LoopStart],ax
	mov	[si+MS.WaveStart],ax
	mov	ax,[si+MS.Length]
	mov	[si+MS.RepLen],ax
mt_SetRegs:
	mov	ax,[si+MS.Note] 	; Grab the note.
	xchg	ah,al			; Amiga exchange.
	and	ax,0FFFh		; Mask out everything but the note.
	jz	mt_CheckMoreEfx 	; Check the fx.
	mov	ax,[Word si+MS.cmd]	; Get the special fx command.
	xchg	ah,al			; Amiga exchange.
	and	ax,0FF0h		; Mask out the bits we don't want.
	cmp	ax,0E50h		; Is there a fine tune command?
	jz	mt_DoSetFineTune
	cmp	ah,3			; Is it a tone portamento?
	jz	mt_ChkTonePorta
	cmp	ah,5			; Is it a tone and volume slide?
	jz	mt_ChkTonePorta
	cmp	ah,9			; Is it a sample offset command?
	jnz	mt_SetPeriod		; If not, go do the actual note.
	call	mt_CheckMoreEfx
	jmp	mt_SetPeriod		; Go do the actual note.

mt_DoSetFineTune:
	call	mt_SetFineTune		; Update the fine tune.
	jmp	mt_SetPeriod		; Go do the note.
 
mt_ChkTonePorta:
	call	mt_SetTonePorta 	; Do part of the tone portamento.
	jmp	mt_CheckMoreEfx 	; Go do the fx.

mt_SetPeriod:
	; ﾄﾄﾄﾄ We are now going to find the note in the period table.  If it
	; ﾄﾄﾄﾄ doesn't exist, then no fine tuning can be performed.  If it
	; ﾄﾄﾄﾄ does, and fine tuning is specified, then we can update it.

	mov	ax,[si+MS.Note] 	; Get the note.
	xchg	ah,al			; Amiga exchange.
	and	ax,0FFFh		; Mask out unwanted bits.
	mov	bx,offset mt_PeriodTable; Set pointer to the beginning of table.
	mov	cx,36			; There are 36 periods to cycle through.
mt_ftuloop:
	cmp	ax,[bx] 		; Check the note against the period.
	jnb	mt_ftufound		; We found it!
	add	bx,2			; Otherwise, update the pointer and
	loop	mt_ftuloop		; keep looping.
mt_ftufound:
	mov	al,[si+MS.FineTune]	; Get the fine tune.
	mov	cl,36*2 		; The period table's size is 72.
	mul	cl			; Multiply it by the fine tune.
	add	bx,ax			; Add it onto the pointer to point to
	mov	ax,[bx] 		; the new period and get it.
	mov	[si+MS.Period],ax	; Store it.

	mov	ax,[Word si+MS.cmd]
	xchg	ah,al
	and	ax,0FF0h
	cmp	ax,0ED0h
	jz	mt_CheckMoreEfx

	mov	al,[si+MS.WaveControl]	; Get the WaveControl.
	and	al,00000100b		; Amiga: BTST #2,WaveControl.
	jz	mt_vibnoc		; If it is zero, then skip.
	mov	[Byte si+MS.VibratoPos],0
mt_vibnoc:
	mov	al,[si+MS.WaveControl]	; Get it again.
	and	al,01000000b		; Amiga: BTST #6,WaveControl
	jz	mt_trenoc		; If it is zero, then skip.
	mov	[Byte si+MS.TremoloPos],0 ; Zero the Tremolo offset.
mt_trenoc:
	mov	ax,[si+MS.start]	; Get the start segment.
	mov	TSSeg,ax		; Store it to be updated.
	xor	cx,cx			; Clear CX.
	mov	TSOff,cx		; Set the offset to zero.
	mov	ax,[si+MS.Length]
	shl	ax,1
	mov	TSMaxRep,ax		; Store in MaxRepeat
        mov     cx,[si+MS.Period]
	call	mt_PerNop2
	mov	[si+MS.Trigger],1
        jmp     mt_CheckMoreEfx
endp	sd_UpdateChannels

proc	mt_dskip
	add	[Word mt_PatternPos],16 	; Increment position by one
	mov	al,[mt_PattDelayTime]
        or      al,al
	jz	mt_dskc
	mov	[mt_PattDelayTime2],al
	mov	[Byte mt_PattDelayTime],0
mt_dskc:
	cmp	[Byte mt_PattDelayTime2],0
	jz	mt_dska
	dec	[Byte mt_PattDelayTime2]
	jz	mt_dska
	sub	[Word mt_PatternPos],16
mt_dska:
        cmp     [Byte mt_PBreakFlag],0
	jz	mt_nnpysk
	mov	[Byte mt_PBreakFlag],0
	xor	ax,ax
	mov	al,[mt_PBreakPos]
	mov	[mt_PBreakPos],ah
	shl	ax,4
        mov     [mt_PatternPos],ax
mt_nnpysk:
	cmp	[Word mt_PatternPos],1024
	jb	mt_NoNewPosYet

mt_NextPosition:
	xor	ax,ax
	mov	al,[mt_PBreakPos]
	shl	ax,4
        mov     [mt_PatternPos],ax
	mov	[Byte mt_PBreakPos],0
	mov	[Byte mt_PosJumpFlag],0
	inc	[Byte mt_SongPos]
	and	[Byte mt_SongPos],7Fh
	mov	al,[mt_SongPos]
	mov	bx,[SequenceOffset]		; Get Sequence Offset
	cmp	al,[bx-02h+offset Header]	; Compare against SongLen
	jnz	mt_NoNewPosYet
	mov	[Byte mt_SongPos],0
	cmp	[Byte PlayStatus],1
	jnz	@@Quit
	mov	[Byte mt_SongPos],0
        ret
;---------------------------------------------------
@@Quit: mov	[Byte MStatus],1
	mov	[Byte mt_SongPos],0
        ret

mt_NoNewPosYet:
	cmp	[Byte mt_PosJumpFlag],0
	jnz	mt_NextPosition
        ret
endp	mt_dskip

proc	mt_CheckEfx
	call	mt_UpdateFunk
	mov	ax,[Word si+MS.cmd]		 ; Get the special command
        xchg    al,ah
        and     ax,0FFFh
	jz	mt_PerNop
	mov	bl,[si+MS.cmd]		    ; Contains the command to do
	and	bl,0Fh
	cmp	bl,0
	jz	mt_Arpeggio
	cmp	bl,1
	jz	mt_PortaUp
	cmp	bl,2
	jz	mt_PortaDown
	cmp	bl,3
	jz	mt_TonePortamento
	cmp	bl,4
	jz	mt_Vibrato
	cmp	bl,5
	jz	mt_TonePlusVolSlide
	cmp	bl,6
	jz	mt_VibratoPlusVolSlide
	cmp	bl,0Eh
	jz	mt_E_Commands
SetBack:call	mt_PerNop
	cmp	bl,7
	jz	mt_Tremolo
	cmp	bl,0Ah
	jz	mt_VolumeSlide
mt_Return:
	ret
endp	mt_CheckEfx

proc	mt_PerNop
	mov	cx,[si+MS.Period]
	jmp	mt_PerNop2
endp	mt_PerNop

proc	mt_PerNop2
	xor	dx,dx
        or      cx,cx
        jz      @@Fig1
	mov	ax,[Word MainFreq]
        mov     dx,[Word MainFreq+2]
        div     cx
        mov     dx,ax
@@Fig1: mov     TSNoteFreq,dx
        ret
endp	mt_PerNop2

;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 0 -- Arpeggio
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_Arpeggio
	xor	ax,ax
	mov	al,[mt_counter]
	mov	bl,3
        div     bl
	xchg	al,ah
        or      al,al
        jz      mt_Arpeggio2
        cmp     al,2
        jz      mt_Arpeggio1
        mov     al,[Byte si+MS.cmdlo]
        shr     al,4
        jmp     mt_Arpeggio3

mt_Arpeggio1:
        mov     al,[Byte si+MS.cmdlo]
        and     al,0Fh
        jmp     mt_Arpeggio3

mt_Arpeggio2:
	mov	cx,[si+MS.Period]
        jmp     mt_Arpeggio4

mt_Arpeggio3:
        cbw
        shl     ax,1
        mov     bx,ax
        mov     al,[si+MS.FineTune]
        mov     cl,36*2
        mul     cl
        mov     dx,[si+MS.Period]
	push	di
	mov	di,offset mt_PeriodTable
	add	di,ax
        mov     cx,36
mt_arploop:
	mov	cx,[bx+di]
	cmp	dx,[di]
        jnb     mt_arpafterloop
	add	di,2
        loop    mt_arploop
	pop	di
        ret
mt_arpafterloop:
	pop	di

mt_Arpeggio4:
        call    mt_PerNop2
        ret
endp    mt_Arpeggio

;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 1 -- Portamento Up
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_PortaUp
        xor     ax,ax
        mov     al,[si+MS.cmdlo]                ; Number to slide up
        and     al,[mt_LowMask]
        mov     [Byte mt_LowMask],0FFh
        sub     [si+MS.Period],ax
        mov     cx,[si+MS.Period]
        and     cx,0FFFh
        cmp     cx,113
        jnb     mt_PortaUSkip
        and     [si+MS.Period],0F000h
        or      [si+MS.Period],113
mt_PortaUSkip:
        mov     cx,[si+MS.Period]
        and     cx,0FFFh
        call    mt_PerNop2
        ret
endp    mt_PortaUp


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 2 -- Portamento Down
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_PortaDown
        xor     ax,ax
        mov     al,[si+MS.cmdlo]                ; Number to slide down
        and     al,[mt_LowMask]
        mov     [Byte mt_LowMask],0FFh
        add     [si+MS.Period],ax
        mov     cx,[si+MS.Period]
        and     cx,0FFFh
        cmp     cx,856
        jb      mt_PortaDSkip
        and     [si+MS.Period],0F000h
        or      [si+MS.Period],856
mt_PortaDSkip:
        mov     cx,[si+MS.Period]
        and     cx,0FFFh
        call    mt_PerNop2
        ret
endp    mt_PortaDown

proc    mt_SetTonePorta
	mov	dx,[si+MS.Note]
	xchg	dh,dl
	and	dx,0FFFh
	xor	ax,ax
	mov	al,[si+MS.FineTune]
	mov	cl,37*2
        mul     cl
        push    di
	mov	di,offset mt_PeriodTable
        add     di,ax
        mov     bx,0
mt_StpLoop:
	cmp	dx,[bx+di]
	jnb	mt_StpFound
	add	bx,2
	cmp	bx,37*2
	jb	mt_StpLoop
	mov	bx,35*2
mt_StpFound:
	mov	dl,[si+MS.FineTune]
	and	dl,8
	jz	mt_StpGoss
	cmp	bx,0
	jz	mt_StpGoss
	sub	bx,2
mt_StpGoss:
	mov	dx,[bx+di]
        pop     di
	mov	[si+MS.WantedPeriod],dx
	mov	ax,[si+MS.Period]
	mov	[Byte si+MS.TonePortDirec],0
	cmp	dx,ax
	jz	mt_ClearTonePorta
	jnb	mt_Return
	mov	[Byte si+MS.TonePortDirec],1
        ret

mt_ClearTonePorta:
	mov	[Word si+MS.WantedPeriod],0
	ret
endp	mt_SetTonePorta


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 3 -- Tone Portamento
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_TonePortamento
        mov     al,[si+MS.cmdlo]
        or      al,al
        jz      mt_TonePortNoChange
        mov     [si+MS.TonePortSpeed],al
        mov     [Byte si+MS.cmdlo],0
mt_TonePortNoChange:
        cmp     [Word si+MS.WantedPeriod],0
	jz	mt_Return
	xor	ax,ax
        mov     al,[si+MS.TonePortSpeed]
        cmp     [Byte si+MS.TonePortDirec],0
        jnz     mt_TonePortaUp
mt_TonePortaDown:
        add     [si+MS.Period],ax
        mov     ax,[si+MS.WantedPeriod]
        cmp     ax,[si+MS.Period]
        jg      mt_TonePortaSetPer
	mov	[si+MS.Period],ax
        mov     [Word si+MS.WantedPeriod],0
        jmp     mt_TonePortaSetPer

mt_TonePortaUp:
        sub     [si+MS.Period],ax
        mov     ax,[si+MS.WantedPeriod]
        cmp     ax,[si+MS.Period]
        jl      mt_TonePortaSetPer
        mov     [si+MS.Period],ax
        mov     [Word si+MS.WantedPeriod],0

mt_TonePortaSetPer:
	mov	cx,[si+MS.Period]
	mov	al,[si+MS.GlissFunk]
        and     al,0Fh
        jz      mt_GlissSkip
        mov     al,[si+MS.FineTune]
        mov     bl,36*2
        mul     bl
        push    di
	mov	di,offset mt_PeriodTable
	add	di,ax
        mov     bx,0
mt_GlissLoop:
	cmp	cx,[bx+di]
        jnb     mt_GlissFound
        add     bx,2
        cmp     bx,36*2
        jb      mt_GlissLoop
        mov     bx,35*2
mt_GlissFound:
        mov     cx,[bx+di]
	pop	di
mt_GlissSkip:
        call    mt_PerNop2
        ret
endp    mt_TonePortamento


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 4 -- Vibrato
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_Vibrato
        mov     al,[si+MS.cmdlo]
        or      al,al
        jz      mt_Vibrato2
	mov	bl,[si+MS.VibratoCmd]
	and	al,0fh
        jz      mt_vibskip
	and	bl,0F0h
	or	bl,al
mt_vibskip:
        mov     al,[si+MS.cmdlo]
        and     al,0F0h
        jz      mt_vibskip2
	and	bl,0Fh
	or	bl,al
mt_vibskip2:
        mov     [si+MS.VibratoCmd],bl
mt_Vibrato2:
        mov     al,[si+MS.VibratoPos]
        shr     al,2
	and	ax,001Fh
	mov	bl,[si+MS.WaveControl]
	and	bl,03h
        jz      mt_vib_sine
	shl	al,3
	cmp	bl,1
        jz      mt_vib_rampdown
	mov	bl,255
        jmp     mt_vib_set
mt_vib_rampdown:
        cmp     [Byte si+MS.VibratoPos],0
	jnb	mt_vib_rampdown2
	mov	bl,255
	sub	bl,al
        jmp     mt_vib_set
mt_vib_rampdown2:
	mov	bl,al
        jmp     mt_vib_set
mt_vib_sine:
	xor	bx,bx
	mov	bl,al
        mov     bl,[Byte bx+offset mt_VibratoTable]
mt_vib_set:
        mov     al,[si+MS.VibratoCmd]
        and     al,0Fh
        mul     bl
	shr	ax,7
        mov     bx,ax
        mov     ax,[si+MS.Period]
        cmp     [Byte si+MS.VibratoPos],0
	jb	mt_VibratoNeg		; BMI
        add     ax,bx
        jmp     mt_Vibrato3
mt_VibratoNeg:
        sub     ax,bx
mt_Vibrato3:
	mov	cx,ax
        call    mt_PerNop2
        mov     al,[si+MS.VibratoCmd]
	shr	ax,2
	and	ax,3Ch
        add     [si+MS.VibratoPos],al
        ret
endp    mt_Vibrato


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 5 -- Tone and Volume Slide
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_TonePlusVolSlide
        call    mt_TonePortNoChange
        jmp     mt_VolumeSlide
endp    mt_TonePlusVolSlide

;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 6 -- Vibrato and Volume Slide
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_VibratoPlusVolSlide
        call    mt_Vibrato2
        jmp     mt_VolumeSlide
endp    mt_VibratoPlusVolSlide


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 7 -- Tremolo
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_Tremolo
        mov     al,[Byte si+MS.cmdlo]
        or      al,al
        jz      mt_Tremolo2
        mov     bl,[si+MS.TremoloCmd]
        and     al,0Fh
        jz      mt_treskip
        and     bl,0F0h
        or      bl,al
mt_treskip:
        mov     al,[Byte si+MS.cmdlo]
        and     al,0F0h
        jz      mt_treskip2
        and     bl,0Fh
        or      bl,al
mt_treskip2:
        mov     [si+MS.TremoloCmd],bl
mt_Tremolo2:
        mov     al,[si+MS.TremoloPos]
        shr     al,2
        and     ax,001Fh
        mov     bl,[si+MS.WaveControl]
        shr     bl,4
        and     bl,03h
        jz      mt_tre_sine
        shl     al,3
        cmp     bl,1
        jz      mt_tre_rampdown
        mov     bl,255
        jmp     mt_tre_set
mt_tre_rampdown:
        cmp     [Byte si+MS.VibratoPos],0
	jnb	mt_tre_rampdown2
        mov     bl,255
        sub     bl,al
        jmp     mt_tre_set
mt_tre_rampdown2:
        mov     bl,al
        jmp     mt_tre_set
mt_tre_sine:
	xor	bx,bx
	mov	bl,al
	mov	bl,[bx+offset mt_VibratoTable]
mt_tre_set:
        mov     al,[si+MS.TremoloCmd]
        and     al,0Fh
        mul     bl
        mov     bx,ax
        shr     bx,6
        mov     al,[si+MS.Volume]
        cmp     [Byte si+MS.TremoloPos],0
	jb	mt_TremoloNeg		; BMI  jns
        add     al,bl
        jmp     mt_Tremolo3
mt_TremoloNeg:
        sub     al,bl
mt_Tremolo3:
        jnb     mt_TremoloSkip
	xor	ax,ax
mt_TremoloSkip:
        cmp     al,40h
	jb	mt_TremoloOK		; BLS
        mov     al,40h
mt_TremoloOK:
        mul     [Byte si+MS.MasterVolume]
        mov     TSVol1,ah
        mov     al,[si+MS.TremoloCmd]
        shr     al,2
        and     al,3Ch
        add     [si+MS.TremoloPos],al
        ret
endp    mt_Tremolo


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 9 -- Sample Offset
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_SampleOffset
	xor	ax,ax
	mov	al,[Byte si+MS.cmdlo]
        or      al,al
        jz      mt_sononew
        mov     [si+MS.SampleOffset],al
mt_sononew:
	mov	al,[si+MS.SampleOffset] 	; Variance in Protracker code.
	shl	ax,8
        cmp     ax,TSMaxRep
	jnb	mt_sofskip
        mov     TSOff,ax
        ret
mt_sofskip:
	mov	ax,TSOff
        mov     TSMaxRep,ax
        ret
endp    mt_SampleOffset


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect A -- Volume Slide
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_VolumeSlide
        mov     al,[si+MS.cmdlo]
        shr     al,4
        cmp     al,0
        jz      mt_VolSlideDown
mt_VolSlideUp:
        add     [Byte si+MS.Volume],al
        cmp     [Byte si+MS.Volume],40h
        jb      mt_vsuskip
        mov     [Byte si+MS.Volume],40h
mt_vsuskip:
        mov     al,[Byte si+MS.Volume]
        mul     [Byte si+MS.MasterVolume]
        mov     TSVol1,ah
        ret

mt_VolSlideDown:
        mov     al,[si+MS.cmdlo]
        and     al,0Fh
mt_VolSlideDown2:
        sub     [Byte si+MS.Volume],al
        jnb     mt_vsdskip
        mov     [Byte si+MS.Volume],0
mt_vsdskip:
        mov     al,[Byte si+MS.Volume]
        mul     [Byte si+MS.MasterVolume]
        mov     TSVol1,ah
        ret
endp    mt_VolumeSlide


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect B -- Position Jump
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_PositionJump
        mov     al,[Byte si+MS.cmdlo]         ; Get where to jump
        dec     al                            ; Update the
	mov	[mt_SongPos],al 	      ; information.
mt_pj2: mov	[Byte mt_PBreakPos],0
        mov     [Byte mt_PosJumpFlag],1
        ret
endp    mt_PositionJump

;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect C -- Volume Change
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_VolumeChange
        mov     al,[Byte si+MS.cmdlo]   ; Get value for volume
        cmp     al,40h                  ; Is it greater than 40h?
        jb      mt_VolumeOK             ; Nope
        mov     al,40h
mt_VolumeOK:
        mov     [si+MS.Volume],al       ; Get it again
        mul     [Byte si+MS.MasterVolume]
        mov     TSVol1,ah

	ret
endp    mt_VolumeChange

;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect D -- Pattern Break
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_PatternBreak
        mov     al,[Byte si+MS.cmdlo]             ; Break to where?
        mov     bl,al
        shr     al,4
        mov     cl,10
        mul     cl
        and     bl,0Fh
        add     al,bl
        cmp     al,63
        jg      mt_pj2
        mov     [mt_PBreakPos],al
        mov     [Byte mt_PosJumpFlag],1
        ret
endp    mt_PatternBreak


;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect F -- Set Speed
;   Doesn't handle Protracker extended speeds.
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
proc    mt_SetSpeed
        mov     al,[Byte si+MS.cmdlo]             ; Get value for speed
        or      al,al
        jz      @@SSpe1
	cmp	al,32
	jnb	@@SSpe1
	mov	[Byte mt_counter],0
	mov	[Byte mt_speed],al
@@SSPe1:ret
endp    mt_SetSpeed


proc	mt_CheckMoreEfx
        call    mt_UpdateFunk
        mov     bl,[si+MS.cmd]
        and     bl,0Fh
	cmp	bl,09h
	jz	mt_SampleOffset
	cmp	bl,0Bh
	jz	mt_PositionJump
	cmp	bl,0Dh
	jz	mt_PatternBreak
	cmp	bl,0Eh
	jz	mt_E_Commands
	cmp	bl,0Fh
	jz	mt_SetSpeed
	cmp	bl,0Ch
        jz      mt_VolumeChange
	jmp	mt_PerNop
endp    mt_CheckMoreEfx

proc	mt_E_Commands
        mov     bl,[Byte si+MS.cmdlo]
        and     bl,0F0h
        shr     bl,4
	cmp	bl,0
	jz	mt_FilterOnOff
	cmp	bl,1
	jz	mt_FinePortaUp
	cmp	bl,2
	jz	mt_FinePortaDown
	cmp	bl,3
	jz	mt_SetGlissControl
	cmp	bl,4
	jz	mt_SetVibratoControl
	cmp	bl,5
	jz	mt_SetFineTune
	cmp	bl,6
	jz	mt_JumpLoop
	cmp	bl,7
	jz	mt_SetTremoloControl
	cmp	bl,9
	jz	mt_RetrigNote
	cmp	bl,0Ah
	jz	mt_VolumeFineUp
	cmp	bl,0Bh
	jz	mt_VolumeFineDown
	cmp	bl,0Ch
	jz	mt_NoteCut
	cmp	bl,0Dh
	jz	mt_NoteDelay
	cmp	bl,0Eh
	jz	mt_PatternDelay
	cmp	bl,0Fh
	jz	mt_FunkIt
	ret
endp    mt_E_Commands

;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect E
;ﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄﾄ
; Effect 0 -- FilterOnOff
proc	mt_FilterOnOff
	mov	al,[Byte si+MS.cmdlo]
	and	al,1
	sal	al,1
	; Amiga
	; Stuff
	ret
endp    mt_FilterOnOff

; Effect 1 -- Fine Porta Up
proc    mt_FinePortaUp
        cmp     [Byte mt_counter],0
        jnz     mt_Return
        mov     [Byte mt_LowMask],0Fh
        jmp     mt_PortaUp
endp    mt_FinePortaUp

; Effect 2 -- Fine Porta Down
proc    mt_FinePortaDown
        cmp     [Byte mt_counter],0
        jnz     mt_Return
        mov     [Byte mt_LowMask],0Fh
        jmp     mt_PortaDown
endp    mt_FinePortaDown

; Effect 3 -- Set Gliss Control
proc    mt_SetGlissControl
        mov     al,[Byte si+MS.cmdlo]
        and     al,0Fh
        and     [Byte si+MS.GlissFunk],0F0h
        or      [si+MS.GlissFunk],al
        ret
endp    mt_SetGlissControl

; Effect 4 -- Set Vibrato Control
proc    mt_SetVibratoControl
        mov     al,[si+MS.cmdlo]
        and     al,0Fh
        and     [Byte si+MS.WaveControl],0F0h
        or      [si+MS.WaveControl],al
        ret
endp    mt_SetVibratoControl

; Effect 5 -- Set Fine Tune
proc    mt_SetFineTune
        mov     al,[si+MS.cmdlo]
        and     al,0Fh
        mov     [si+MS.FineTune],al
        ret
endp    mt_SetFineTune

; Effect 6 -- Jump Loop
proc    mt_JumpLoop
        cmp     [Byte mt_counter],0
	jnz	mt_Return
	mov	al,[si+MS.cmdlo]
        and     al,0Fh
        jz      mt_SetLoop
        cmp     [Byte si+MS.loopcount],0
        jz      mt_jumpcnt
        dec     [Byte si+MS.loopcount]
	jz	mt_Return
mt_jmploop:
        mov     al,[si+MS.pattpos]
        mov     [mt_PBreakPos],al
        mov     [Byte mt_PBreakFlag],1
        ret

mt_jumpcnt:
        mov     [si+MS.loopcount],al
	jmp	mt_jmploop

mt_SetLoop:
	mov	ax,[mt_PatternPos]
        shr     ax,4
        mov     [si+MS.pattpos],al
        ret
endp    mt_JumpLoop

; Effect 7 -- Set Tremolo Control
proc    mt_SetTremoloControl
        mov     al,[Byte si+MS.cmdlo]
        and     al,0Fh
        shl     al,4
        and     [Byte si+MS.WaveControl],0Fh
        or      [si+MS.WaveControl],al
        ret
endp    mt_SetTremoloControl

; Effect 9 -- Retrig Note
proc    mt_RetrigNote
        mov     bl,[Byte si+MS.cmdlo]
        and     bl,0Fh
	jz	mt_rtnend
	xor	ax,ax
        mov     al,[mt_counter]
        or      al,al
        jnz     mt_rtnskp
        mov     cx,[si+MS.Note]
        xchg    ch,cl
        and     cx,0FFFh
	jnz	mt_rtnskp
        mov     [Byte mt_counter],0
mt_rtnskp:
        div     bl
        xchg    ah,al
        or      al,al
	jnz	mt_rtnend
mt_DoRetrig:
        xor     ax,ax
        mov     TSOff,ax
	mov	ax,[si+MS.Length]
	shl	ax,1
	mov	TSMaxRep,ax
	mov	ax,[si+MS.LoopStart]
	mov	TSRepeat,ax
	mov	cx,[si+MS.RepLen]
	add	ax,cx			; Add on the offset.
	add	ax,cx			; Add it again.
	sub	ax,3
        mov     TSRepeatLen,ax          ; Store it.
mt_rtnend:
	ret
endp    mt_RetrigNote

; Effect A -- Volume Fine Up
proc    mt_VolumeFineUp
        cmp     [Byte mt_counter],0
	jnz	mt_Return
	mov	al,[si+MS.cmdlo]
        and     al,0Fh
        jmp     mt_VolSlideUp
endp    mt_VolumeFineUp

; Effect B -- Volume Fine Down
proc    mt_VolumeFineDown
        cmp     [Byte mt_counter],0
	jnz	mt_Return
	mov	al,[si+MS.cmdlo]
        and     al,0Fh
        jmp     mt_VolSlideDown2
endp    mt_VolumeFineDown

; Effect C -- Note Cut
proc    mt_NoteCut
        mov     al,[Byte si+MS.cmdlo]
        and     al,0Fh
	cmp	al,[mt_counter]
	jnz	mt_Return
	mov	[Byte si+MS.Volume],0
	mul	[Byte si+MS.MasterVolume]
        mov     TSVol1,ah
        ret
endp    mt_NoteCut

; Effect D -- Note Delay
proc    mt_NoteDelay
        mov     al,[Byte si+MS.cmdlo]
        and     al,0Fh
	cmp	al,[mt_counter]
	jnz	mt_Return
	mov	ax,[si]
	or	ax,ax
	jz	mt_Return
	jmp	mt_DoRetrig
endp    mt_NoteDelay

; Effect E -- Pattern Delay
proc    mt_PatternDelay
        cmp     [Byte mt_counter],0
	jnz	mt_Return
	mov	al,[Byte si+MS.cmdlo]
        and     al,0Fh
        cmp     [Byte mt_PattDelayTime2],0
	jnz	mt_Return
	inc	al
        mov     [mt_PattDelayTime],al
        ret
endp    mt_PatternDelay

; Effect F -- Funk It
proc    mt_FunkIt
	cmp	[Byte mt_counter],0
	jnz	mt_Return
	mov	al,[Byte si+MS.cmdlo]
        and     al,0Fh
        shl     al,4
        and     [Byte si+MS.GlissFunk],0Fh
        or      [si+MS.GlissFunk],al
        or      al,al
	jz	mt_Return
	jmp	mt_UpdateFunk
endp    mt_FunkIt

proc    mt_UpdateFunk
	xor	bx,bx
	mov	bl,[si+MS.GlissFunk]
	shr	bl,4
	or	bl,bl
	jz	mt_funkend
        mov     al,[bx+offset mt_FunkTable]
        add     [si+MS.FunkOffset],al
	mov	al,[si+MS.FunkOffset]
	and	al,10000000b
	jz	mt_funkend
	mov	[Byte si+MS.FunkOffset],0
	; This is my best try at converting this code.
;	 mov	 ax,[si+MS.LoopStart]
;	 mov	 bx,[si+MS.RepLen]
;	 add	 ax,bx
;	 add	 ax,bx
;	 mov	 cx,[si+MS.WaveStart]
;	 inc	 cx
;	 cmp	 cx,ax
;	 jb	 mt_funkok
;	 mov	 cx,[si+MS.LoopStart]
;mt_funkok:
;	 mov	 [si+MS.WaveStart],cx
;	 mov	 ax,-1
;	 mov	 bx,cx
;	 sub	 [bx],ax
;	 mov	 ax,[bx]
mt_funkend:
	ret
endp	mt_UpdateFunk

end
