;께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께
;                Tiny MOD Player for Watcom C/C++32 and DOS/4GW
;                      Version 2.11a  June 5th, 1994
;
;                      Copyright 1993,94 Carlos Hasan
;께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께께

ideal
p386
model   flat,c
smart

;굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇
; EQUATES AND PUBLICS
;굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇

MAXVOICES = 8                           ; number of voices
DMABUFLEN = 4096			; DMA buffer length (multiple of 64)
VOLBUFLEN = 66*256                      ; volume table length
MIXBUFLEN = 2*DMABUFLEN+2048            ; mixing/boosting buffer length
global	MODGetSetBuff:proc	; get/set buffer.
global	MODSizeDMA:proc
global  MODPlayModule:proc
global  MODStopModule:proc
global  MODPlaySample:proc
global  MODStopSample:proc
global  MODSetPeriod:proc
global  MODSetVolume:proc
global  MODSetMusicVolume:proc
global  MODSetSampleVolume:proc
global  MODPoll:proc
global  MODVoiceTable:dword

;굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇
; STRUCTURES
;굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇

struc   module                          ; module structure
  numtracks     dw      ?               ; number of tracks
  orderlen      dw      ?               ; order length
  orders        db      128 dup (?)     ; order list
  patterns      dd      128 dup (?)     ; pattern addresses
  sampptr       dd      32 dup (?)      ; sample start addresses
  sampend       dd      32 dup (?)      ; sample end addresses
  samploop      dd      32 dup (?)      ; sample loop point addresses
  sampvolume    db      32 dup (?)      ; sample default volumes
ends    module

struc   sample                          ; sample structure
  period        dw      ?               ; default period
  volume        dw      ?               ; default volume
  datalen       dd      ?               ; sample data length
  dataptr       dd      ?               ; sample data address
ends    sample

struc   track                           ; track structure
  note          dw      ?               ; note index
  period        dw      ?               ; period value
  inst          db      ?               ; instrument
  volume        db      ?               ; volume
  effect        dw      ?               ; effect
  destperiod    dw      ?               ; toneporta wanted period
  tonespeed     db      ?               ; toneporta speed
  vibparm       db      ?               ; vibrato depth/rate
  vibpos        db      ?               ; vibrato wave position
  tremparm      db      ?               ; tremolo depth/rate
  trempos       db      ?               ; tremolo wave position
                db      ?               ; alignment
  arptable      dw      3 dup (?)       ; arpeggio periods
ends    track

;굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇
; DATA
;굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇

;갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚
; Module Player data
;갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚
udataseg

moduleptr       dd      ?               ; current module address
pattptr         dd      ?               ; current playing pattern address
orderpos        db      ?               ; order position
orderlen        db      ?               ; order length
pattrow         db      ?               ; pattern row
tempo           db      ?               ; tempo
tempocount      db      ?               ; tempo counter
bpm             db      ?               ; beats per minute
musicvolume     db      ?               ; music channels volume
samplevolume    db      ?               ; sample channels volume
numtracks       dw      ?               ; number of tracks
tracks          track   MAXVOICES dup (?)

pitchtable      dd      3425 dup (?)    ; period to pitch table

; Amiga period table
dataseg

periodtable     dw      0
                dw      3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920,1812
                dw      1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906
                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
                dw      107,101,95,90,85,80,75,71,67,63,60,56
                dw      53,50,47,45,42,40,37,35,33,31,30,28

; Sinus wave table

sintable        db      0,25,50,74,98,120,142,162,180,197,212,225
                db      236,244,250,254,255,254,250,244,236,225
                db      212,197,180,162,142,120,98,74,50,25

;갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚
; Sound Blaster driver data
;갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚
udataseg

; Voices programmable parameters

label MODVoiceTable dword

voicepos        dd      MAXVOICES dup (?)
voiceend        dd      MAXVOICES dup (?)
voiceloop       dd      MAXVOICES dup (?)
voicefrac       dd      MAXVOICES dup (?)
voicepitch      dd      MAXVOICES dup (?)
voicevolume     dd      MAXVOICES dup (?)

; Internal driver data
dataseg

mixbuffer       dd      ?               ; mixing buffer address
boosttable      dd      ?               ; boosting table address
voltable        dd      ?               ; volume table address
numvoices       dw      ?               ; number of active voices
mixfreq         dw      ?               ; playback frequency


datasel         dw      ?               ; flat model data selector
bufsel          dw      ?               ; DOS memory block selector
bufptr          dd      ?               ; DMA buffer address
bufoff          dd      ?               ; double buffer offset
timerproc       dd      ?               ; timer callback address
timeracc        dd      ?               ; timer callback accumulator
timerspeed      dd      ?               ; timer callback speed

playing         db      0               ; playing/stopped status


;굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇
; CODE
;굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇굇
codeseg

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; Copyright Strings
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같

db      'Tiny MOD Player V2.11 Copyright 1993,94 Carlos Hasan',0
db      'Compiled on: ',??date,' ',??time,0

;갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚
; Module Player stuff
;갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚
proc	MODGetSetBuff buff:dword
	mov	eax,[buff]
	mov	[mixbuffer],eax
	mov	eax,(DMABUFLEN+VOLBUFLEN+MIXBUFLEN+15)
	ret
	endp

proc	MODSizeDMA
	mov	eax,DMABUFLEN
	ret
	endp

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODPlayModule - start playing a music module
; In:
;  Song  = module address
;  Chans = number of channels
;  Rate  = playback rate
;  Port  = port address
;  irq   = irq number
;  dma   = dma channel
;  mode  = polling mode
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc	MODPlayModule Song:dword,Chans:dword,Rate:dword
        pushad

; setup the music module address

        mov     esi,[Song]
        mov     [moduleptr],esi

; setup the sound card driver

        mov     ax,[word Rate]
        mov     bl,[byte Chans]
        call    mixinit
        jc      playmoduled0

; build the period to pitch table (16.16 fixed point values)

        movzx   ebx,ax
        mov     eax,8363*428
        xor     edx,edx
        shld    edx,eax,16
        shl     eax,16
        div     ebx
        mov     esi,eax
        lea     edi,[pitchtable]
        mov     ecx,3425
        xor     ebx,ebx
playmodulel0:
        inc     ebx
        xor     edx,edx
        mov     eax,esi
        div     ebx
        mov     [edi],eax
        add     edi,4
        loop    playmodulel0

; setup global volumes for music and sample channels

        mov     [musicvolume],255
        mov     [samplevolume],255

; clear the module player track structures

        push    es
        mov     ax,ds
        mov     es,ax
        cld
        lea     edi,[tracks]
        mov     ecx,MAXVOICES*(size track)
        xor     al,al
        rep     stosb
        pop     es

; check if there is a module to playback

        xor     eax,eax
        mov     [numtracks],ax

        mov     esi,[moduleptr]
        test    esi,esi
        clc
        je      playmoduled0

; setup player interpreter variables

        mov     esi,[moduleptr]
        mov     ax,[esi+module.orderlen]
        mov     [orderlen],al
        mov     ax,[esi+module.numtracks]
        mov     [numtracks],ax
        mov     [tempo],6
        mov     [bpm],125
        mov     [orderpos],0
        mov     [tempocount],0
        mov     [pattrow],40h

; setup the player callback timer routine

        lea     edx,[pollmodule]
        call    mixsettimerproc
        mov     dl,[bpm]
        call    mixstarttimer
        clc

playmoduled0:
        popad
        sbb     eax,eax
        ret
endp    MODPlayModule

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODStopModule - shut down the music system
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc    MODStopModule
        pushad
        call    mixdone                 ; shutdown the SB stuff
        popad
        ret
endp    MODStopModule

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODPoll - polls the music system in manual mode
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc    MODPoll
        pushad
        cmp     [playing],0             ; polling mode (and if the driver
        je      modpolld0               ; is active).
	call	mixpoll
modpolld0:
        popad
        ret
endp    MODPoll

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODPlaySample - play sample instrument
; In:
;  voice  = voice number
;  sample = sample address
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc    MODPlaySample Voice:dword,SamplePtr:dword
        pushad
        cli

; get the voice number and track address

        mov     ebx,[Voice]
        mov     edi,[SamplePtr]
        mov     esi,ebx
        imul    esi,size track

; set the voice pitch value

        movzx   eax,[edi+sample.period]
        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax

; set the voice sample parameters

        mov     eax,[edi+sample.dataptr]
        mov     [4*ebx+voicepos],eax
        add     eax,[edi+sample.datalen]
        mov     [4*ebx+voiceend],eax
        mov     [4*ebx+voiceloop],eax

; set the voice and track volumes

        mov     ax,[edi+sample.volume]
        mov     [esi+tracks.volume],al
        mul     [samplevolume]
        mov     [byte 4*ebx+voicevolume],ah

        sti
        popad
        ret
endp    MODPlaySample

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODStopSample - stop the playing sample
; In:
;  voice = voice number
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc    MODStopSample Voice:dword
        pushad
        cli

; get the voice number

        mov     ebx,[Voice]
        xor     eax,eax

; clear the voice sample parameters

        mov     [4*ebx+voicepos],eax
        mov     [4*ebx+voiceend],eax
        mov     [4*ebx+voiceloop],eax

        sti
        popad
        ret
endp    MODStopSample

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODSetPeriod -  set the voice period value
; In:
;  voice = voice number
;  period = period value (113-856)
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc    MODSetPeriod Voice:dword,Period:dword
        pushad
        cli

; get the voice number and period value

        mov     ebx,[Voice]
        mov     eax,[Period]

; set the voice pitch value

        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax

        sti
        popad
        ret
endp    MODSetPeriod

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODSetVolume -  set the voice volume level
; In:
;  voice = voice number
;  volume = volume level (0-64)
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc    MODSetVolume Voice:dword,Volume:dword
        pushad
        cli

; get the voice number and track address

        mov     ebx,[Voice]
        mov     eax,[Volume]
        mov     esi,ebx
        imul    esi,size track

; set the voice and track volume

        mov     [esi+tracks.volume],al
        mul     [samplevolume]
        mov     [byte 4*ebx+voicevolume],ah

        sti
        popad
        ret
endp    MODSetVolume

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODSetMusicVolume - set the global music volume
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc    MODSetMusicVolume Volume:dword
        pushad
        cli

; set new music volume

        mov     eax,[Volume]
        mov     [musicvolume],al

; update all the music voices

        lea     esi,[tracks]
        xor     ebx,ebx
setmusicvolumel0:
        mov     al,[esi+track.volume]
        mul     [musicvolume]
        mov     [byte 4*ebx+voicevolume],ah
        add     esi,size track
        inc     ebx
        cmp     bx,[numtracks]
        jb      setmusicvolumel0

        sti
        popad
        ret
endp    MODSetMusicVolume

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; MODSetSampleVolume - set the global sample volume
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
proc    MODSetSampleVolume Volume:dword
        pushad
        cli

; set the sample volume

        mov     eax,[Volume]
        mov     [samplevolume],al

; update all the sample voices

        lea     esi,[tracks]
        xor     ebx,ebx
setsamplevolumel0:
        cmp     bx,[numtracks]
        jb      setsamplevolumef0
        mov     al,[esi+track.volume]
        mul     [samplevolume]
        mov     [byte 4*ebx+voicevolume],ah
setsamplevolumef0:
        add     esi,size track
        inc     ebx
        cmp     bx,MAXVOICES
        jb      setsamplevolumel0

        sti
        popad
        ret
endp    MODSetSampleVolume


;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; pollmodule - polls the module player
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
pollmodule:
        pushad
        dec     [tempocount]            ; decrease the tempo counter
        jle     pollmodulef0
        lea     esi,[tracks]            ; while in the same pattern row
        xor     ebx,ebx                 ; update the track effects.
pollmodulel0:
        call    updatechannel
        add     esi,size track
        inc     ebx
        cmp     bx,[numtracks]
        jb      pollmodulel0
        popad
        ret

pollmodulef0:                           ; advance to the next pattern row.
        mov     al,[tempo]              ; update the tempo counter
        mov     [tempocount],al
        mov     edx,[moduleptr]         ; get the module and pattern address
        mov     edi,[pattptr]
        cmp     [pattrow],40h           ; need to advance to the next order?
        jb      pollmodulef2
        xor     eax,eax                 ; reset the pattern row
        mov     [pattrow],al
        mov     al,[orderpos]           ; if we are at the end of the order
        cmp     al,[orderlen]           ; list, loop to the beginning
        jb      pollmodulef1
        xor     al,al
        mov     [orderpos],al
pollmodulef1:
        inc     [orderpos]              ; get the new pattern address
        movzx   eax,[edx+eax+module.orders]
        mov     edi,[edx+4*eax+module.patterns]
pollmodulef2:
        inc     [pattrow]               ; increase pattern row number
        lea     esi,[tracks]
        xor     ebx,ebx                 ; read and interpret the next
pollmodulel1:                           ; pattern row of events
        call    readchannel
        add     esi,size track
        add     edi,4
        inc     ebx
        cmp     bx,[numtracks]
        jb      pollmodulel1
        mov     [pattptr],edi           ; save pattern row address
        popad
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; readchannel - read the next note event from the pattern sheet
; In:
;  EBX = voice number
;  ESI = track address
;  EDI = pattern address
;  EDX = module address
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
readchannel:
        pushad

; check for new sample number . . .

        mov     al,[edi+1]
        test    al,al
        je      readchannelf0
        mov     [esi+track.inst],al
        movzx   eax,al
        mov     al,[edx+eax+module.sampvolume]
        mov     [esi+track.volume],al
        mul     [musicvolume]
        mov     [byte 4*ebx+voicevolume],ah

; check for new note pitch . . .

readchannelf0:
        mov     al,[edi]
        test    al,al
        je      readchannelf1
        movzx   eax,al
        mov     [esi+track.note],ax
        cmp     [byte edi+3],03h
        je      readchannelf1
        mov     ax,[2*eax+periodtable]
        mov     [esi+track.period],ax
        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax
        movzx   eax,[esi+track.inst]
        lea     edx,[4*eax+edx]
        mov     eax,[edx+module.sampptr]
        mov     [4*ebx+voicepos],eax
        mov     eax,[edx+module.sampend]
        mov     [4*ebx+voiceend],eax
        mov     eax,[edx+module.samploop]
        mov     [4*ebx+voiceloop],eax

; check the new track effect . . .

readchannelf1:
        mov     dx,[edi+2]
        mov     [esi+track.effect],dx
        movzx   eax,dh
        and     al,0Fh
        call    [4*eax+efxtable]

        popad
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; updatechannel - update the track using the current effect
; In:
;  EBX = voice number
;  ESI = track address
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
updatechannel:
        pushad
        mov     dx,[esi+track.effect]
        movzx   eax,dh
        and     al,0Fh
        call    [4*eax+efxtable2]
        popad
        ret

;갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚
; Protracker effects stuff
;갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚갚

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; Effect jump tables
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같

        align   4

label efxtable dword
        dd      efxarpeggio             ; 0 - arpeggio
        dd      efxnull                 ; 1 - porta up
        dd      efxnull                 ; 2 - porta down
        dd      efxtoneporta            ; 3 - tone porta
        dd      efxvibrato              ; 4 - vibrato
        dd      efxnull                 ; 5 - tone+slide
        dd      efxnull                 ; 6 - vibrato+slide
        dd      efxtremolo              ; 7 - tremolo
        dd      efxnull                 ; 8 - unused
        dd      efxsampoffset           ; 9 - sample offset
        dd      efxnull                 ; A - volume slide
        dd      efxpattjump             ; B - pattern jump
        dd      efxsetvolume            ; C - set volume
        dd      efxbreak                ; D - break pattern
        dd      efxnull                 ; E - extra effects
        dd      efxsetspeed             ; F - set speed

label efxtable2 dword
        dd      efxarpeggio2            ; 0 - arpeggio
        dd      efxportaup              ; 1 - porta up
        dd      efxportadown            ; 2 - porta down
        dd      efxtoneporta2           ; 3 - tone porta
        dd      efxvibrato2             ; 4 - vibrato
        dd      efxtoneslide            ; 5 - tone+slide
        dd      efxvibslide             ; 6 - vibrato+slide
        dd      efxtremolo2             ; 7 - tremolo
        dd      efxnull                 ; 8 - unused
        dd      efxnull                 ; 9 - sample offset
        dd      efxvolslide             ; A - volume slide
        dd      efxnull                 ; B - pattern jump
        dd      efxnull                 ; C - set volume
        dd      efxnull                 ; D - break pattern
        dd      efxnull                 ; E - extra effects
        dd      efxnull                 ; F - set speed

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxnull - dummy effect
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxnull:
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxarpeggio - arpeggio
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxarpeggio:
        test    dl,dl
        je      efxnull
        mov     dh,dl
        and     dl,0Fh
        shr     dh,4
        movzx   eax,[esi+track.note]
        mov     cx,[2*eax+periodtable]
        mov     [esi+track.arptable],cx
        add     al,dh
        mov     cx,[2*eax+periodtable]
        mov     [esi+2+track.arptable],cx
        sub     al,dh
        add     al,dl
        mov     cx,[2*eax+periodtable]
        mov     [esi+4+track.arptable],cx
        ret
efxarpeggio2:
        test    dl,dl
        je      efxnull
        movzx   eax,[esi+track.arptable]
        xchg    [esi+4+track.arptable],ax
        xchg    [esi+2+track.arptable],ax
        mov     [esi+track.arptable],ax
        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxportaup - slides the pitch up
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxportaup:
        xor     dh,dh
        movzx   eax,[esi+track.period]
        sub     ax,dx
        cmp     ax,28
        jge     efxportaupf0
        mov     ax,28
efxportaupf0:
        mov     [esi+track.period],ax
        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxportadown - slides the pitch down
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxportadown:
        xor     dh,dh
        movzx   eax,[esi+track.period]
        add     ax,dx
        cmp     ax,3424
        jle     efxportadownf0
        mov     ax,3424
efxportadownf0:
        mov     [esi+track.period],ax
        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxtoneporta - tone portamento
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxtoneporta:
        test    dl,dl
        jne     efxtoneportaf0
        mov     dl,[esi+track.tonespeed]
efxtoneportaf0:
        mov     [esi+track.tonespeed],dl
        mov     [esi+track.effect],dx
        movzx   eax,[esi+track.note]
        mov     ax,[2*eax+periodtable]
        mov     [esi+track.destperiod],ax
        ret
efxtoneporta2:
        xor     dh,dh
        movzx   eax,[esi+track.period]
        mov     cx,[esi+track.destperiod]
        cmp     ax,cx
        je      efxnull
        jg      efxtoneportaf1
        add     ax,dx
        cmp     ax,cx
        jle     efxtoneportaf2
        mov     ax,cx
efxtoneportaf2:
        mov     [esi+track.period],ax
        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax
        ret
efxtoneportaf1:
        sub     ax,dx
        cmp     ax,cx
        jge     efxtoneportaf3
        mov     ax,cx
efxtoneportaf3:
        mov     [esi+track.period],ax
        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxvibrato - pitch vibrato
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxvibrato:
        mov     al,[esi+track.vibparm]
        mov     ah,al
        and     ax,0F00Fh
        test    dl,0Fh
        jne     efxvibratof0
        or      dl,al
efxvibratof0:
        test    dl,0F0h
        jne     efxvibratof1
        or      dl,ah
efxvibratof1:
        mov     [esi+track.vibparm],dl
        mov     [esi+track.effect],dx
        ret
efxvibrato2:
        mov     dh,dl
        and     dx,0F00Fh
        shr     dh,2
        mov     al,[esi+track.vibpos]
        add     [esi+track.vibpos],dh
        mov     dh,al
        shr     al,2
        and     eax,1Fh
        mov     al,[eax+sintable]
        mul     dl
        shr     ax,7
        test    dh,dh
        jge     efxvibratof2
        neg     ax
efxvibratof2:
        add     ax,[esi+track.period]
        cmp     ax,28
        jge     efxvibratof3
        mov     ax,28
efxvibratof3:
        cmp     ax,3424
        jle     efxvibratof4
        mov     ax,3424
efxvibratof4:
        movzx   eax,ax
        mov     eax,[4*eax+pitchtable]
        mov     [4*ebx+voicepitch],eax
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxtoneslide - volume slide and continue last portamento
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxtoneslide:
        call    efxvolslide
        mov     dl,[esi+track.tonespeed]
        jmp     efxtoneporta

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxvibslide - volume slide and continue last pitch vibrato
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxvibslide:
        call    efxvolslide
        mov     dl,[esi+track.vibparm]
        jmp     efxvibrato2

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxtremolo - volume vibrato
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxtremolo:
        mov     al,[esi+track.tremparm]
        mov     ah,al
        and     ax,0F00Fh
        test    dl,0Fh
        jne     efxtremolof0
        or      dl,al
efxtremolof0:
        test    dl,0F0h
        jne     efxtremolof1
        or      dl,ah
efxtremolof1:
        mov     [esi+track.tremparm],dl
        mov     [esi+track.effect],dx
        ret
efxtremolo2:
        mov     dh,dl
        and     dx,0F00Fh
        shr     dh,2
        mov     al,[esi+track.trempos]
        add     [esi+track.trempos],dh
        mov     dh,al
        shr     al,2
        and     eax,1Fh
        mov     al,[eax+sintable]
        mul     dl
        shr     ax,6
        test    dh,dh
        jge     efxtremolof2
        neg     ax
efxtremolof2:
        add     al,[esi+track.volume]
        jge     efxtremolof3
        xor     al,al
efxtremolof3:
        cmp     al,40h
        jle     efxtremolof4
        mov     al,40h
efxtremolof4:
        mul     [musicvolume]
        mov     [byte 4*ebx+voicevolume],ah
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxsampoffset - set the sample offset
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxsampoffset:
        movzx   eax,[esi+track.inst]
        mov     esi,[moduleptr]
        mov     eax,[esi+4*eax+module.sampptr]
        movzx   edx,dl
        shl     edx,8
        add     eax,edx
        mov     [4*ebx+voicepos],eax
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxvolslide - volume slide
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxvolslide:
        mov     al,[esi+track.volume]
        mov     dh,dl
        shr     dl,4
        je      efxvolslidef0
        add     al,dl
        cmp     al,40h
        jle     efxvolslidef1
        mov     al,40h
efxvolslidef1:
        mov     [esi+track.volume],al
        mul     [musicvolume]
        mov     [byte 4*ebx+voicevolume],ah
        ret
efxvolslidef0:
        sub     al,dh
        jge     efxvolslidef2
        xor     al,al
efxvolslidef2:
        mov     [esi+track.volume],al
        mul     [musicvolume]
        mov     [byte 4*ebx+voicevolume],ah
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxpattjump - jump to order pattern
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxpattjump:
        mov     [orderpos],dl
        mov     [pattrow],40h
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxsetvolume - set volume
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxsetvolume:
        mov     al,dl
        mov     [esi+track.volume],al
        mul     [musicvolume]
        mov     [byte 4*ebx+voicevolume],ah
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxbreak - break pattern
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxbreak:
        mov     [pattrow],40h
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; efxsetspeed - set the tempo or BPM speed
; In:
;  EBX = voice number
;  ESI = track address
;  DL = effect parameter
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
efxsetspeed:
        test    dl,dl
        je      efxnull
        cmp     dl,20h
        jae     efxsetbpm
        mov     [tempo],dl
        mov     [tempocount],dl
        ret
efxsetbpm:
        mov     [bpm],dl
        call    mixstarttimer
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; mixstarttimer - start the timer at the specified speed
; In:
;  DL = timer speed in beats per minute (BPMs)
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
mixstarttimer:
        push    eax
        push    ebx
        push    edx
        mov     bh,dl                   ; set the timer callback speed
        xor     bl,bl                   ; to 24/60*BPM hertz
        mov     ax,[mixfreq]
        mov     dx,0280h
        mul     dx
        div     bx
        movzx   eax,ax
        mov     [timerspeed],eax
        pop     edx
        pop     ebx
        pop     eax
        ret

; mixsettimerproc - set the timer procedure
; In:
;  EDX = timer routine address
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
mixsettimerproc:
        mov     [timerproc],edx         ; set the timer callback address
        ret


;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; mixstoptimer - stop the timer routine
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
mixstoptimer:
        mov     [timerproc],offset nulltimer
nulltimer:
        ret


;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; mixinit - initialize the sound driver
; In:
;  AX = mixing speed in hertz
;  BL = number of voices
; Out:
;  CF = status
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
mixinit:
        pushad

        cmp     [playing],0
        jne     mixinitd0

        xor     eax,eax
        mov     [bufoff],eax

; setup sound card parameters
        xor     bh,bh
        mov     [mixfreq],ax
        mov     [numvoices],bx

; clear voice parameters

        push    es
        mov     ax,ds
        mov     es,ax
        cld
        lea     edi,[voicepos]
        mov     ecx,6*MAXVOICES
        xor     eax,eax
        rep     stosd
        pop     es

; set the address of the mixing buffer and boosting table
	mov	eax,[mixbuffer]
        add     eax,2*DMABUFLEN
        mov     [boosttable],eax
        add     eax,2048

; get the address of the DMA buffer and volume table

        mov     ecx,DMABUFLEN
        lea     edx,[eax+ecx]

; check for cross-pages in the DMA buffer and align the Volume table

        mov     esi,eax
        add     si,cx
        jnc     mixinitf0
        mov     edx,eax
        add     eax,VOLBUFLEN
mixinitf0:
        add     edx,255
        xor     dl,dl
        mov     [bufptr],eax
        mov     [voltable],edx

; clear DMA buffer with centered samples

        push    es
        mov     ax,ds
        mov     es,ax
        cld
        mov     edi,[bufptr]
        mov     ecx,DMABUFLEN
        mov     al,80h
        rep     stosb
        pop     es

; build volume table and boosting table

        mov     cl,6
        mov     edi,[voltable]
        xor     bx,bx
mixinitl0:
        mov     al,bl
        imul    bh
        sar     ax,cl
        mov     [edi],al
        inc     edi
        inc     bl
        jne     mixinitl0
        inc     bh
        cmp     bh,40h
        jbe     mixinitl0

        push    es
        mov     ax,ds
        mov     es,ax
        cld
        mov     edi,[boosttable]
        mov     ecx,768
        xor     ax,ax
        rep     stosb
        mov     ecx,512
mixinitl1:
        mov     [edi],ah
        add     ax,80h
        inc     edi
        loop    mixinitl1
        mov     ecx,768
        dec     al
        rep     stosb
        pop     es

        mov     [playing],1
        clc

mixinitd0:
        popad
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; mixdone - deinitialize the sound driver
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
mixdone:
        pushad

        cmp     [playing],1
        jne     mixdoned0

; set driver stopped status

        mov     [playing],0

mixdoned0:
        popad
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; mixvoice - mixes the voice samples
; In:
;  EBX = voice number (*4)
;  ECX = number of samples
;  EDI = buffer address
; Out:
;  EDI = buffer end address
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
mixvoice:

        macro   mixcode OPCODE
        local   mixcodel0,mixjmptable

        push    eax
        push    ebx
        push    ecx
        push    edx
        push    ebp
        push    esi

        push    ebx
        mov     esi,[ebx+voicepos]
        mov     dl,[byte ebx+3+voicefrac]
        mov     dh,[byte ebx+1+voicepitch]
        movzx   ebp,[word ebx+2+voicepitch]
        mov     ebx,[ebx+voicevolume]
        mov     bh,bl
        add     ebx,[voltable]

        movzx   eax,cl
        and     al,31
        shr     ecx,5
        lea     edi,[edi+4*eax-4*32]
        jmp     [4*eax+mixjmptable]

        align   4
mixcodel0:
        I=0
        rept    32
CODESTART=$
        mov     bl,[esi]
        add     dl,dh
        movsx   eax,[byte ebx]
        adc     esi,ebp
        OPCODE  [edi+I],eax
CODELEN=$-CODESTART
        I=I+4
        endm
        add     edi,4*32
        dec     ecx
        jge     mixcodel0

        pop     ebx
        mov     [ebx+voicepos],esi
        mov     [byte ebx+3+voicefrac],dl

        pop     esi
        pop     ebp
        pop     edx
        pop     ecx
        pop     ebx
        pop     eax
        ret

        align   4
        label mixjmptable dword
        I=CODESTART+CODELEN
        rept    32
        dd      I
        I=I-CODELEN
        endm
        endm

        test    ebx,ebx
        je      mixvoicef0
        mixcode add
mixvoicef0:
        mixcode mov

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; mixvoices - mixes all the voices
; In:
;  EDI = buffer address
;  ECX = number of samples
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
mixvoices:
        pushad

        xor     ebx,ebx
mixvoicesl0:
        push    ebx
        push    ecx
        push    edi
        shl     ebx,2
        mov     ebp,ecx

mixvoicesl1:
        mov     ecx,ebp
        mov     edx,[ebx+voicepos]
        mov     eax,[ebx+voiceend]
        cmp     edx,eax
        jb      mixvoicesf0
        sub     edx,eax
        add     edx,[ebx+voiceloop]
        cmp     edx,eax
        jae     mixvoicesc0
        mov     [ebx+voicepos],edx

mixvoicesf0:
        sub     eax,edx
        shl     eax,16
        mov     edx,[ebx+voicefrac]
        shr     edx,16
        sub     eax,edx

        mov     edx,ecx
        mov     esi,[ebx+voicepitch]
        imul    edx,esi
        cmp     edx,eax
        jbe     mixvoicesf1
        dec     eax
        xor     edx,edx
        add     eax,esi
        adc     edx,edx
        div     esi
        mov     ecx,eax

mixvoicesf1:
        call    mixvoice
        sub     ebp,ecx
        jg      mixvoicesl1

        pop     edi
        pop     ecx
        pop     ebx
        inc     ebx
        cmp     bx,[numvoices]
        jb      mixvoicesl0

        popad
        ret

mixvoicesc0:
        test    ebx,ebx
        jne     mixvoicesc1
        push    es
        mov     ax,ds
        mov     es,ax
        xor     eax,eax
        cld
        rep     stosd
        pop     es

mixvoicesc1:
        pop     edi
        pop     ecx
        pop     ebx
        inc     ebx
        cmp     bx,[numvoices]
        jb      mixvoicesl0

        popad
        ret

;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; mixpoll - updates the output buffer
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
mixpoll:
        pushad

; get the 32 bit mixing buffer address

        mov     ecx,DMABUFLEN/2
        mov     edi,[mixbuffer]

; fill the mixing buffer and polls the timer callback routine

mixpollf4:
        mov     eax,[timeracc]
        mov     ebp,ecx
mixpolll0:
        test    eax,eax
        jg      mixpollf0
        call    [timerproc]
        add     eax,[timerspeed]
mixpollf0:
        mov     ecx,eax
        add     ecx,63
        and     cl,not 63
        cmp     ecx,ebp
        jle     mixpollf1
        mov     ecx,ebp
mixpollf1:
        call    mixvoices
        lea     edi,[edi+4*ecx]
        sub     eax,ecx
        sub     ebp,ecx
        jg      mixpolll0
        mov     [timeracc],eax

; translate 32-bit signed samples to 8-bit unsigned samples

        mov     ecx,DMABUFLEN/2
        mov     esi,[mixbuffer]
        mov     edi,[bufptr]
        add     edi,[bufoff]
        xor     [bufoff],ecx
        mov     ebx,[boosttable]
        add     ebx,1024
        shr     ecx,4
mixpolll2:
        I=0
        rept    4
        mov     eax,[esi+16*I+8]
        mov     dl,[eax+ebx]
        mov     eax,[esi+16*I+12]
        mov     dh,[eax+ebx]
        shl     edx,16
        mov     eax,[esi+16*I]
        mov     dl,[eax+ebx]
        mov     eax,[esi+16*I+4]
        mov     dh,[eax+ebx]
        mov     [edi+4*I],edx
        I=I+1
        endm
        add     esi,4*16
        add     edi,16
        dec     ecx
        jg      mixpolll2

mixpolld0:
        popad
        ret



end
