summaryrefslogtreecommitdiff
path: root/modplay.inc
diff options
context:
space:
mode:
Diffstat (limited to 'modplay.inc')
-rw-r--r--modplay.inc1141
1 files changed, 1141 insertions, 0 deletions
diff --git a/modplay.inc b/modplay.inc
new file mode 100644
index 0000000..4a5e253
--- /dev/null
+++ b/modplay.inc
@@ -0,0 +1,1141 @@
+; MOD player (c) 2002 mls
+;
+; generates samples for 11000 HZ
+; bpm always 125
+
+
+%if 0
+ call init
+ sti
+ call loadmod
+ sti
+ call play
+ sti
+ call playmod
+ sti
+ call playsamp
+ sti
+ call setvol
+ sti
+ call getvol
+ sti
+ call getstate
+ sti
+ call stop
+ sti
+%endif
+
+; pl_loadmod - configure a mod player
+; ds:si start of player
+; es:di start of mod
+; si,di must be reasonable small ;)
+pl_loadmod:
+ pushad
+ push si
+ add si, pl_state
+ xor ax, ax
+ mov cx, pl_sizeof - pl_state
+sm1: mov [si], al
+ inc si
+ loop sm1
+ pop si
+ mov [si + pl_seg], es
+ mov dx, si
+ mov cx, 4
+ push si
+ add si, pl_channs
+sm10: mov [si + ch_player], dx
+ add si, ch_sizeof
+ loop sm10
+ pop si
+ mov dx, 32
+ mov eax, [es:di + 0x438]
+ cmp eax, 'CHN4'
+ jz sm2
+ cmp eax, 'M.K.'
+ jz sm2
+ cmp eax, 'M&K!'
+ jz sm2
+ cmp eax, 'FLT4'
+ jz sm2
+ mov dl, 16
+sm2: add di, 20 + 22
+ mov [si + pl_sampinfo], di
+ sub di, 22 + 30
+ mov cx, dx
+ imul cx, 30
+ add di, cx
+ mov al, [es:di]
+ mov [si + pl_songlen], al
+ inc di
+ inc di
+ mov [si + pl_song], di
+ xor bx, bx
+ mov cx, 128
+sm5: mov al, [es:di]
+ inc di
+ cmp bl, al
+ jge sm4
+ mov bl, al
+sm4: loop sm5
+ inc bl
+ cmp dl, 32
+ jnz sm6
+ add di, 4
+sm6: mov [si + pl_patterns], di
+ mov cx, bx
+sm7: add di, 64 * 16
+ loop sm7
+ mov [si + pl_speed], byte 6
+ mov [si + pl_effpos], byte 6
+ mov [si + pl_loaded], byte 1
+ mov cx, dx
+ dec cx
+ mov dx, es
+ mov bx, di
+ mov di, [si + pl_sampinfo]
+ add si, pl_sampd + 2
+sm9: push bx
+ shr bx, 4
+ add dx, bx
+ pop bx
+ and bx, 0x000f
+ mov [si], bx
+ mov [si + 2 * 32], dx
+ mov ax, [es:di]
+ xchg al, ah
+ add bx, ax
+ adc dx, 0
+ add bx, ax
+ adc dx, 0
+ add si, 2
+ add di, 30
+ loop sm9
+ popad
+ ret
+
+; pl_play - play modfile
+; ds:si start of player
+; es:di buffer to add samples
+pl_play:
+ pushad
+ push es
+ push di
+
+ call fixvol
+
+ mov ax, [si + pl_state]
+ or ax, ax
+ jz p3
+ dec ax
+ jnz near p1
+
+ ; run effects
+ push si
+ add si, pl_channs
+ mov cx, 4
+p31: mov ax, [si + ch_effect]
+ or ax, ax
+ jz p30
+ call doeff
+ call norm
+p30: add si, ch_sizeof
+ loop p31
+ pop si
+
+ inc word [si + pl_effpos]
+ mov ax, [si + pl_effpos]
+ cmp ax, [si + pl_speed]
+ jb near p1
+
+ ; advance note
+ xor ax, ax
+ mov [si + pl_effpos], ax
+ mov bx, [si + pl_nextsongnum]
+ mov [si + pl_songnum], bx
+ mov cx, [si + pl_songlen]
+ cmp bx, cx
+ jb p2
+p3: mov [si + pl_state], ax
+ pop di
+ pop es
+ popad
+ ret
+p2: mov dx, [si + pl_nextnotenum]
+ mov [si + pl_notenum], dx
+ cmp dx, 64
+ jnb p3
+ inc dx
+ cmp dl, 64
+ jb p4
+ xor dl, dl
+ inc bx
+ cmp bx, cx
+ jb p5
+ xor bx, bx
+p5: mov [si + pl_nextsongnum], bx
+p4: mov [si + pl_nextnotenum], dx
+
+ ; interpret events for each channel
+ mov bx, [si + pl_songnum]
+ mov es, [si + pl_seg]
+ add bx, [si + pl_song]
+ mov bl, [es:bx]
+ cmp bl, 0x80
+ jb p11
+ xor bl, bl
+p11: xor bh, bh
+ shl bx, 6
+ add bx, [si + pl_notenum]
+ shl bx, 4
+ add bx, [si + pl_patterns]
+
+ mov di, [si + pl_sampinfo]
+ push si
+ add si, pl_channs
+
+ mov cx, 4
+p18: mov ah, [es:bx]
+ and ah, 0x10
+ mov al, [es:bx + 2]
+ shr al, 4
+ or al, ah
+ jz p16
+ call setsamp
+p16: mov ah, [es:bx]
+ and ah, 0x0f;
+ mov al, [es:bx + 1]
+ or ax, ax
+ jz p17
+ mov [si + ch_pitchgoal], ax
+ mov dl, [es:bx + 2]
+ inc dl
+ or dl, 0xf2
+ cmp dl, 0xf6
+ jz p17
+ mov [si + ch_pitch], ax
+ xor ax, ax
+ mov [si + ch_pointer], ax
+ mov [si + ch_pointer8], ax
+ mov ax, [si + ch_send]
+ mov [si + ch_end], ax
+p17: xor ax, ax
+ mov [si + ch_effect], ax
+ mov dl, [es:bx + 3]
+ mov al, [es:bx + 2]
+ and al, 0x0f
+ or dl, al
+ jz p29
+ push di
+ mov di, [si + ch_player]
+ mov dl, [es:bx + 3]
+ xor dh, dh
+ call effects
+ pop di
+p29: call norm
+ add si, ch_sizeof
+ add bx, 4
+ dec cx
+ jnz near p18
+ pop si
+
+ ; prepare playing of each channel
+p1: push si
+ add si, pl_channs
+ mov cx, 4
+p10: mov ax, [si + ch_end]
+ or ax, ax
+ jnz p6
+p8: mov [si + ch_start], ax
+ mov [si + ch_startseg], ax
+ jmp p7
+p6: mov ax, [si + ch_pitch]
+ or ax, ax
+ jz p8
+ mov bx, [si + ch_samp]
+ or bx, bx
+ jz p8
+ mov dx, si
+ pop si
+ push si
+ add bx, bx
+ add si, bx
+ mov bx, [si + pl_sampd]
+ mov si, [si + pl_sampdseg]
+ xchg si, dx
+ mov [si + ch_start], bx
+ mov [si + ch_startseg], dx
+ mov dx, [si + ch_finetune]
+ add dx, dx
+ jz p9
+ mov dx, [cs: fttab]
+ mul dx
+ shl ax, 1
+ mov ax, dx
+ adc ax, ax
+p9: mov bx, ax
+ mov ax, 57213
+ xor dx, dx
+ div bx
+ mov [si + ch_step], ah
+ mov [si + ch_step8], al
+p7: add si, ch_sizeof
+ loop p10
+ pop si
+
+ ; now generate 320 samples for each channel
+ pop di
+ pop es
+ add si, pl_channs
+ mov ax, 320
+p21: push ax
+ mov cx, 4
+p20: mov bx, [si + ch_startseg]
+ or bx, bx
+ jz near p22
+ push es
+ mov es, bx
+ mov bx, [si + ch_start]
+ mov ax, [si + ch_pointer]
+ add bx, ax
+ movsx dx, [es:bx]
+ shl dx, 2
+ inc ax
+ cmp ax, [si + ch_end]
+ jnb p23
+ inc bx
+ movsx ax, [es:bx]
+ push cx
+ mov cx, [si + ch_pointer8]
+ or cx, cx
+ jz p24
+ sar dx, 2
+ imul ax, cx
+ neg cl
+ imul dx, cx
+ add dx, ax
+ sar dx, 6
+p24: pop cx
+p23: pop es
+ imul dx, [si + ch_volume]
+ sar dx, 2
+ push si
+ mov si, [si + ch_player]
+ movzx eax, word [si + pl_volume]
+ pop si
+ movsx edx, dx
+ imul edx
+ sar eax, 16
+ add ax, word [es:di]
+ jno p40
+ mov ax, 32767
+ js p40
+ inc ax
+p40: mov [es:di], ax
+ mov bx, [si + ch_pointer8]
+ mov ax, [si + ch_pointer]
+ add bl, [si + ch_step8]
+ adc ax, [si + ch_step]
+ mov [si + ch_pointer8], bl
+ cmp ax, [si + ch_end]
+ jb p25
+ mov ax, [si + ch_roff]
+ mov bx, [si + ch_rend]
+ mov [si + ch_end], bx
+ or bx, bx
+ jnz p25
+ mov [si + ch_startseg], bx
+p25: mov [si + ch_pointer], ax
+p22: add si, ch_sizeof
+ dec cx
+ jnz near p20
+ add di, 2
+ sub si, ch_sizeof * 4
+ pop ax
+ dec ax
+ jnz near p21
+ sub si, pl_channs
+ mov ax, [si + pl_state]
+ dec ax
+ jz p50
+ add si, pl_channs
+ mov cx, 4
+p51: mov ax, [si + ch_startseg]
+ or ax, ax
+ jnz p50
+ add si, ch_sizeof
+ loop p51
+ sub si, ch_sizeof * 4 + pl_channs
+ mov [si + pl_state], ax
+p50: popad
+ ret
+
+fttab: dw 32768, 32532, 32298, 32066
+ dw 31835, 31606, 31378, 31153
+ dw 34716, 34466, 34219, 33972
+ dw 33728, 33485, 33244, 33005
+
+; norm - normalize channel values
+; ds:si start of chanel
+norm: push ax
+ mov ax, [si + ch_volume]
+ or ax, ax
+ jns n1
+ xor ax, ax
+n1: cmp ax, 64
+ jb n2
+ mov ax, 64
+n2: mov [si + ch_volume], ax
+ mov ax, [si + ch_pitch]
+ or ax, ax
+ jnb n3
+ xor ax, ax
+ mov [si + ch_pitch], ax
+n3: pop ax
+ ret
+
+arptab: dw 0, 61858, 58386, 55109
+ dw 52016, 49097, 46341, 43740
+ dw 41285, 38968, 36781, 34716
+ dw 32768, 30929, 29193, 27554
+
+; effects - interpret effect
+; ax effect
+; dx arg
+; ds:di start of player
+; ds:si start of chanel
+;
+; trashes ax, dx
+effects:
+ or al, al
+ jnz e1
+ mov [si + ch_arpindex], ax
+ mov ax, [si + ch_pitch]
+ mov [si + ch_arp], ax
+ push dx
+ push ax
+ shr dl, 4
+ jz e1b
+ push bx
+ mov bx, dx
+ add bl, bl
+ mov dx, [cs: arptab + bx]
+ pop bx
+ mul dx
+ mov ax, dx
+e1b: mov [si + ch_arp + 2], ax
+ pop ax
+ pop dx
+ and dl, 0x0f
+ jz e1a
+ push bx
+ mov bx, dx
+ add bl, bl
+ mov dx, [cs: arptab + bx]
+ pop bx
+ mul dx
+ mov ax, dx
+e1a: mov [si + ch_arp + 4], ax
+ mov [si + ch_effect], byte EFF_ARP
+ ret
+e1: cmp al, 1
+ jnz e2
+ neg dx
+ jmp e3
+e2: cmp al, 2
+ jnz e4
+e3: or dl, dl
+ jz e5
+ mov [si + ch_slide], dx
+e5: mov [si + ch_effect], byte EFF_SLIDE
+ ret
+e4: cmp al, 3
+ jnz e6
+ or dl, dl
+ jz e7
+ mov [si + ch_pitchrate], dx
+e7: mov [si + ch_effect], byte EFF_PORTA
+ ret
+e6: cmp al, 4
+ jnz e8
+ mov ax, dx
+ shr ax, 4
+ jz e9
+ mov [si + ch_vibrate], ax
+e9: and dl, 0x0f
+ jz e10
+ mov [si + ch_vibdepth], dx
+e10: mov [si + ch_effect], byte EFF_VIBRA
+ ret
+e8: cmp al, 5
+ jnz e11
+ mov [si + ch_effect], byte EFF_PORTASLIDE
+ jmp e12
+e11: cmp al, 6
+ jnz e13
+ mov [si + ch_effect], byte EFF_VIBRASLIDE
+ jmp e12
+e13: cmp al, 9
+ jnz e14
+ mov ax, [si + ch_samp]
+ or al, al
+ jz e15
+ xor ax, ax
+ mov [si + ch_pointer8], ax
+ mov ax, [si + ch_send]
+ mov [si + ch_end], ax
+ shl dx, 8
+ cmp dx, ax
+ jb e16
+ sub dx, ax
+ mov ax, [si + ch_rend]
+ mov [si + ch_end], ax
+ sub ax, [si + ch_roff]
+ jz e17
+e18: cmp dx, ax
+ jb e17
+ sub dx, ax
+ jmp e18
+e17: add dx, [si + ch_roff]
+e16: mov [si + ch_pointer], dx
+e15: ret
+e14: cmp al, 10
+ jnz e19
+ mov [si + ch_effect], byte EFF_SLIDEVOL
+e12: mov ax, dx
+ and dl, 0x0f
+ jz e20
+ neg dx
+ jmp e21
+e20: mov dx, ax
+ shr dl, 4
+e21: mov [si + ch_volumerate], dx
+ ret
+e19: cmp al, 11
+ jnz e22
+ mov [di + pl_nextsongnum], dx
+ xor dx, dx
+ mov [di + pl_nextnotenum], dx
+ ret
+e22: cmp al, 12
+ jnz e23
+ mov [si + ch_volume], dx
+ ret
+e23: cmp al, 13
+ jnz e24
+ mov ax, dx
+ shr al, 4
+ imul ax, 10
+ and dx, 0x0f
+ add dx, ax
+ mov [di + pl_nextnotenum], dx
+ mov dx, [di + pl_songnum]
+ inc dx
+ mov ax, [di + pl_songlen]
+ cmp dx, ax
+ jb e25
+ xor dx, dx
+e25: mov [di + pl_nextsongnum], dx
+ ret
+e24: cmp al, 15
+ jnz e27
+ cmp dl, 32
+ jnb e26
+ mov [di + pl_speed], dx
+e26: ret
+e27: cmp al, 14
+ jnz e26
+ mov al, dl
+ shr al, 4
+ and dl, 0x0f
+ cmp al, 1
+ jnz e28
+e30: add [si + ch_pitch], dx
+ ret
+e28: cmp al, 2
+ jnz e29
+ neg dx
+ jmp e30
+e29: cmp al, 5
+ jnz e31
+ mov [si + ch_finetune], dx
+ ret
+e31: cmp al, 6
+ jnz e32
+ or dl, dl
+ jnz e33
+ mov dx, [di + pl_notenum]
+ mov [di + pl_loop_notenum], dx
+ ret
+e33: mov ax, [di + pl_loop_counter]
+ or ax, ax
+ jnz e34
+ mov ax, dx
+ inc ax
+e34: dec ax
+ mov [di + pl_loop_counter], ax
+ jz e35
+ mov dx, [di + pl_loop_notenum]
+ mov [di + pl_nextnotenum], dx
+e35: ret
+e32: cmp al, 9
+ jnz e36
+ mov [si + ch_retrig], dx
+ mov [si + ch_current], dx
+ mov [si + ch_effect], byte EFF_RETRIG
+ ret
+e36: cmp al, 10
+ jnz e37
+e39: add [si + ch_volume], dx
+ ret
+e37: cmp al, 11
+ jnz e38
+ neg dx
+ jmp e39
+e38: cmp al, 12
+ jnz e40
+ mov [si + ch_retrig], dx
+ mov [si + ch_effect], byte EFF_CUT
+ ret
+e40: cmp al, 13
+ jnz e41
+ mov [si + ch_current], dx
+ mov dx, [si + ch_samp]
+ mov [si + ch_latesamp], dx
+ xor dx, dx
+ mov [si + ch_samp], dx
+ mov [si + ch_effect], byte EFF_LATESTART
+ ret
+e41: cmp al, 14
+ jnz e42
+ inc dx
+ imul dx, [di + pl_speed]
+ sub [di + pl_effpos], dx
+e42: ret
+
+vibtab: dw 0, 50, 100, 149, 196, 241, 284, 325
+ dw 362, 396, 426, 452, 473, 490, 502, 510
+ dw 512, 510, 502, 490, 473, 452, 426, 396
+ dw 362, 325, 284, 241, 196, 149, 100, 50
+ dw 0, -49, -99,-148,-195,-240,-283,-324
+ dw -361,-395,-425,-451,-472,-489,-501,-509
+ dw -511,-509,-501,-489,-472,-451,-425,-395
+ dw -361,-324,-283,-240, -195,-148,-99, -49
+
+; doeff - apply channel effect
+; ax effect
+; ds:si start of chanel
+;
+; trashes ax, bx
+doeff:
+ bt ax, 3
+ jnc d1
+ mov bx, [si + ch_volumerate]
+ add [si + ch_volume], bx
+ sub al, 8
+d1: cmp al, EFF_ARP
+ jnz d2
+ mov bx, [si + ch_arpindex]
+ inc bl
+ cmp bl, 3
+ jb d3
+ xor bl, bl
+d3: mov [si + ch_arpindex], bl
+ add bl, bl
+ mov ax, [si + ch_arp + bx]
+ mov [si + ch_pitch], ax
+ ret
+d2: cmp al, EFF_SLIDE
+ jnz d4
+ mov ax, [si + ch_slide]
+ add [si + ch_pitch], ax
+ ret
+d4: cmp al, EFF_PORTA
+ jnz d5
+ mov ax, [si + ch_pitch]
+ mov bx, [si + ch_pitchgoal]
+ cmp ax, bx
+ jnb d6
+ add ax, [si + ch_pitchrate]
+ cmp ax, bx
+ jb d7
+d8: mov ax, bx
+d7: mov [si + ch_pitch], ax
+ ret
+d6: sub ax, [si + ch_pitchrate]
+ cmp ax, bx
+ jb d8
+ jmp d7
+d5: cmp al, EFF_VIBRA
+ jnz d9
+ mov bx, [si + ch_viboffset]
+ add bx, [si + ch_vibrate]
+ and bx, 0x3f
+ mov [si + ch_viboffset], bx
+ add bx, bx
+ mov ax, [cs: vibtab + bx]
+ imul ax, [si + ch_vibdepth]
+ sar ax, 8
+ add ax, [si + ch_pitchgoal]
+ mov [si + ch_pitch], ax
+d12: ret
+d9: cmp al, EFF_RETRIG
+ jnz d10
+ dec word [si + ch_current]
+ jz d11
+ jns d12
+d11: mov ax, [si + ch_retrig]
+ mov [si + ch_current], ax
+ mov ax, [si + ch_send]
+ mov [si + ch_end], ax
+ xor ax, ax
+ mov [si + ch_pointer], ax
+ mov [si + ch_pointer8], ax
+ ret
+d10: cmp al, EFF_CUT
+ jnz d13
+ mov ax, [si + ch_retrig]
+ jz d14
+ dec word [si + ch_retrig]
+ jnz d14
+ xor ax, ax
+ mov [si + ch_volume], ax
+d14: ret
+d13: cmp al, EFF_LATESTART
+ jnz d14
+ dec word [si + ch_current]
+ jz d15
+ jns d14
+d15: call d11
+ mov [si + ch_current], ax
+ mov [si + ch_effect], ax
+ mov ax, [si + ch_latesamp]
+ mov [si + ch_samp], ax
+ ret
+
+; fixvol - fixup volume
+; ds:si start of volblock
+fixvol:
+ push ax
+ push bx
+ mov ax, [si + vo_volume]
+ mov bx, [si + vo_volumegoal]
+ cmp ax, bx
+ jz vo3
+ jnb vo1
+ add ax, [si + vo_volumerate]
+ jc vohit
+ cmp ax, bx
+ jb vo2
+vohit: mov ax, bx
+vo2: mov [si + vo_volume], ax
+vo3: pop bx
+ pop ax
+ ret
+vo1: sub ax, [si + vo_volumerate]
+ jc vohit
+ cmp ax, bx
+ jb vohit
+ jmp vo2
+
+; vo_setvol - set volume
+; ds:si start of volblock
+; ax goal
+; bx rate 0=immediate 50=one sec
+vo_setvol:
+ mov [si + vo_volumegoal], ax
+ or bx, bx
+ jnz sv1
+ mov [si + vo_volume], ax
+ mov [si + vo_volumerate], bx
+ ret
+sv1: push ax
+ xor ax, ax
+ not ax
+ push dx
+ div bx
+ pop dx
+ mov [si + vo_volumerate], ax
+ pop ax
+ ret
+
+; getvol - get volume
+; ds:si start of volblock
+vo_getvol:
+ mov ax, [si + vo_volume]
+ ret
+
+; pl_playmod - play a modfile
+; ds:si start of player
+; ax start of song
+pl_playmod:
+ cmp [si + pl_loaded], byte 1
+ jz pm0
+ ret
+pm0: xor bx, bx
+ mov [si + pl_state], bx
+ mov [si + pl_speed], byte 6
+ mov [si + pl_effpos], byte 6
+ mov [si + pl_nextsongnum], ax
+ mov [si + pl_nextnotenum], bx
+ call clearchans
+ inc bx
+ mov [si + pl_state], bx
+ ret
+
+; pl_playsamp - play a sample
+; ds:si start of player
+; ax channel number
+; bx sample number
+; cx pitch
+pl_playsamp:
+ cmp [si + pl_loaded], byte 1
+ jz ps0
+ ret
+ps0: push ax
+ mov ax, [si + pl_state]
+ dec ax
+ dec ax
+ jz ps1
+ call clearchans
+ps1: pop ax
+ pusha
+ push es
+ mov es, [si + pl_seg]
+ mov di, [si + pl_sampinfo]
+ add si, pl_channs
+ imul ax, ch_sizeof
+ add si, ax
+ xor ax, ax
+ mov [si + ch_startseg], ax
+ mov [si + ch_effect], ax
+ mov [si + ch_pointer], ax
+ mov [si + ch_pointer8], ax
+ mov [si + ch_pitch], cx
+ mov ax, bx
+ or ax, ax
+ jz ps2
+ call setsamp
+ps2: pop es
+ mov ax, [si + ch_send]
+ mov [si + ch_end], ax
+ popa
+ mov [si + pl_state], byte 2
+ ret
+
+; pl_getstate - get state of player
+; ds:si start of player
+pl_getstate:
+ mov ax, [si + pl_state]
+ ret
+
+; pl_getstate - get state of player
+; ds:si start of player
+pl_stop:
+ mov [si + pl_state], byte 0
+ ret
+
+; clearchans - stop all channels
+; si start of player
+clearchans:
+ push si
+ push cx
+ push ax
+ xor ax, ax
+ add si, pl_channs
+ mov cx, 4
+cc1: mov [si + ch_startseg], ax
+ mov [si + ch_effect], ax
+ add si, ch_sizeof
+ loop cc1
+ pop ax
+ pop cx
+ pop si
+ ret
+
+; setsamp - start a sample
+; si start of channel
+; es:di start of sampinfo
+; ax sample number
+;
+; trashes ax, dx
+setsamp:
+ xor ah, ah
+ mov [si + ch_samp], ax
+ dec ax
+ imul ax, 30
+ push bx
+ mov bx, ax
+ mov ax, [es:di + bx]
+ xchg ah, al
+ add ax, ax
+ mov [si + ch_send], ax
+ mov ax, [es:di + bx + 4]
+ xchg ah, al
+ add ax, ax
+ mov [si + ch_roff], ax
+ mov dx, [es:di + bx + 6]
+ xchg dh, dl
+ add dx, dx
+ mov [si + ch_rend], dx
+ add ax, dx
+ mov dx, [si + ch_send]
+ dec ax
+ dec ax
+ cmp ax, dx
+ jna ss13
+ shr word [si + ch_roff], 1
+ss13: mov ax, [si + ch_roff]
+ add ax, [si + ch_rend]
+ cmp dx, [si + ch_roff]
+ jnb ss14
+ss16 xor ax, ax
+ mov [si + ch_roff], ax
+ss14: cmp dx, ax
+ jnb ss15
+ mov ax, dx
+ss15: mov [si + ch_rend], ax
+ dec ax
+ dec ax
+ jz ss16
+ mov al, [es:di + bx + 2]
+ mov [si + ch_finetune], al
+ mov al, [es:di + bx + 3]
+ mov [si + ch_volume], al
+ pop bx
+ ret
+
+; the big picture: four mod players
+
+; init - initiaize everything
+; ds:si start of area
+init:
+ pushad
+ push si
+ xor ax, ax
+ mov cx, ar_sizeof
+ii1: mov [si], al
+ inc si
+ loop ii1
+ pop si
+ not ax
+ xor bx, bx
+ push si
+ add si, ar_players
+ mov cx, 4
+ii2: call vo_setvol
+ add si, pl_sizeof
+ loop ii2
+ pop si
+ add si, ar_volume
+ mov ax, 32767
+ call vo_setvol
+ popad
+ ret
+
+; setpl - get player offset
+; ax player no.
+setpl:
+ add si, ar_players
+ imul ax, pl_sizeof
+ add si, ax
+ ret
+
+; loadmod - load a mod into one of the players
+; ds:si start of area
+; es:di start of mod
+; ax player no.
+loadmod:
+ push si
+ call setpl
+ call pl_loadmod
+ pop si
+ ret
+
+; playmod - play a modfile
+; ds:si start of area
+; ax player no.
+; bx start of song
+playmod:
+ push si
+ call setpl
+ mov ax, bx
+ call pl_playmod
+ pop si
+ ret
+
+; playsamp - play a sample
+; ds:si start of area
+; ax player no.
+; bx channel number
+; cx sample number
+; dx pitch
+playsamp:
+ push si
+ call setpl
+ mov ax, bx
+ mov bx, cx
+ mov cx, dx
+ call pl_playsamp
+ pop si
+ ret
+
+; getstate - get state of player
+; ds:si start of area
+; ax player no.
+getstate:
+ push si
+ call setpl
+ call pl_getstate
+ pop si
+ ret
+
+; stop - stop a player
+; ds:si start of area
+; ax player no.
+stop:
+ push si
+ call setpl
+ call pl_stop
+ pop si
+ ret
+
+pctab:
+ db 64, 64, 64, 64, 64, 64, 64, 64
+ db 64, 64, 63, 63, 63, 63, 63, 63
+ db 63, 63, 63, 63, 63, 63, 62, 62
+ db 62, 62, 62, 62, 62, 62, 62, 62
+ db 61, 61, 61, 61, 61, 61, 61, 61
+ db 61, 60, 60, 60, 60, 60, 60, 60
+ db 60, 60, 60, 59, 59, 59, 59, 59
+ db 59, 59, 59, 59, 59, 58, 58, 58
+ db 58, 58, 58, 58, 58, 58, 58, 57
+ db 57, 57, 57, 57, 57, 57, 57, 57
+ db 57, 56, 56, 56, 56, 56, 56, 56
+ db 56, 55, 55, 55, 55, 55, 54, 54
+ db 54, 54, 53, 53, 53, 53, 52, 52
+ db 52, 51, 51, 50, 50, 49, 49, 48
+ db 48, 47, 46, 45, 44, 43, 42, 41
+ db 40, 39, 38, 37, 36, 35, 34, 33
+ db 32, 31, 30, 29, 28, 27, 26, 25
+ db 24, 23, 22, 21, 20, 19, 18, 17
+ db 17, 16, 16, 15, 15, 14, 14, 13
+ db 13, 13, 12, 12, 12, 12, 11, 11
+ db 11, 11, 10, 10, 10, 10, 10, 9
+ db 9, 9, 9, 9, 9, 9, 9, 9
+ db 8, 8, 8, 8, 8, 8, 8, 8
+ db 8, 8, 8, 8, 7, 7, 7, 7
+ db 7, 7, 7, 6, 6, 6, 6, 6
+ db 6, 6, 6, 6, 6, 6, 5, 5
+ db 5, 5, 5, 5, 5, 5, 5, 5
+ db 4, 4, 4, 4, 4, 4, 4, 4
+ db 4, 4, 3, 3, 3, 3, 3, 3
+ db 3, 3, 3, 3, 2, 2, 2, 2
+ db 2, 2, 2, 2, 2, 1, 1, 1
+ db 1, 1, 1, 1, 1, 1, 1, 1
+
+; play - generate samples
+; ds:si start of area
+play:
+ pushad
+ push es
+ push si
+ xor ax, ax
+ mov cx, ar_volume
+ap1: mov [si], al
+ inc si
+ loop ap1
+ call fixvol
+ pop si
+ push si
+ add si, ar_ssamps
+ mov di, si
+ push ds
+ pop es
+ mov cx, ar_sizeof - ar_ssamps
+ap2: mov [si], al
+ inc si
+ loop ap2
+ pop si
+ push si
+ mov cx, 4
+ xor bx, bx
+ add si, ar_players
+ap4: mov ax, [si + pl_state]
+ or ax, ax
+ jz ap3
+ call pl_play
+ mov ax, [si + pl_volume]
+ or ax, ax
+ jz ap3
+ mov bl, 1
+ap3: add si, pl_sizeof
+ loop ap4
+ pop si
+ movzx eax, word [si + ar_volume]
+ or ax, ax
+ jz ap5
+ mov [si + ar_hassamp], bl
+ mov cx, 320
+ xor bx, bx
+ap6: movsx edx, word [si + bx + ar_ssamps]
+ imul edx, eax
+
+ sar edx, 16-2
+
+ cmp edx,32767
+ jl ap7
+ mov edx,32767
+ap7:
+ cmp edx,-32768
+ jg ap8
+ mov edx,-32768
+
+ap8:
+ add dh, 128
+ push bx
+ xor bx, bx
+ mov bl, dh
+ mov dl, [cs: pctab + bx]
+ pop bx
+ mov [si + ar_samps], dl
+ inc si
+ inc bx
+ loop ap6
+ap5: pop es
+ popad
+ ret
+
+; setvol - set volume
+; ds:si start of area
+; ax player no.
+; bx goal
+; cx rate 0=immediate 50=one sec
+setvol:
+ push si
+ call setplvl
+ mov ax, bx
+ mov bx, cx
+ call vo_setvol
+ pop si
+ ret
+
+; getvol - get volume
+; ds:si start of area
+; ax player no.
+getvol:
+ push si
+ call setplvl
+ call vo_getvol
+ pop si
+ ret
+
+; setplvl - get volume offset
+; ax player no.
+setplvl:
+ or ax, ax
+ js av1
+ jmp setpl
+av1: add si, ar_volume
+ ret
+