OPM_CLOCK equ 4000000
OPMCH_MAX equ 8
FMDIV_BITS equ 9
FMDIV_ENT equ (1 << FMDIV_BITS)
FMVOL_SFTBIT equ 5
SIN_BITS equ 10
EVC_BITS equ 10
ENV_BITS equ 16
KF_BITS equ 6
FREQ_BITS equ 20
ENVTBL_BIT equ 14
SINTBL_BIT equ 14
TL_BITS equ (FREQ_BITS + 2)
OPM_OUTSB equ (TL_BITS + 2 - 16)
SIN_ENT equ (1 << SIN_BITS)
EVC_ENT equ (1 << EVC_BITS)
EC_ATTACK equ 0
EC_DECAY equ (EVC_ENT << ENV_BITS)
EC_OFF equ ((2 * EVC_ENT) << ENV_BITS)
EM_ATTACK equ 4
EM_DECAY1 equ 3
EM_DECAY2 equ 2
EM_RELEASE equ 1
EM_OFF equ 0
struc slot_t
.detune1 resd 1 ; 00
.detune2 resd 1 ; 04
.totallevel resd 1 ; 08
.decaylevel resd 1 ; 0c
.attack resd 1 ; 10
.decay1 resd 1 ; 14
.decay2 resd 1 ; 18
.release resd 1 ; 1c
.freq_cnt resd 1 ; 20
.freq_inc resd 1 ; 24
.keyscale resb 1 ; 28
.multiple resb 1 ; 29
.env_mode resb 1 ; 2a
.envraito resb 1 ; 2b
.env_cnt resd 1 ; 2c
.env_end resd 1 ; 30
.env_inc resd 1 ; 34
.env_inc_attack resd 1 ; 38
.env_inc_decay1 resd 1 ; 3c
.env_inc_decay2 resd 1 ; 40
.env_inc_rel resd 1 ; 44
.size
endstruc
struc ch_t
.slot resb (slot_t.size * 4)
.algorithm resb 1
.feedback resb 1
.playing resb 1
.outslot resb 1
.op1fb resd 1
.connect1 resd 1
.connect3 resd 1
.connect2 resd 1
.connect4 resd 1
.keynote resd 1
.keyfunc resb 1
.kcode resb 1
.pan resb 1
resb 1
.size
endstruc
struc opmgen_t
.playing resd 1
.mode resb 1
.padding resb 3
.feedback2 resd 1
.feedback3 resd 1
.feedback4 resd 1
.outdl resd 1
.outdc resd 1
.outdr resd 1
.calcremain resd 1
.keyreg resb OPMCH_MAX
endstruc
struc opmcfg_t
.calc1024 resd 1
.fmvol resd 1
.sintable resd SIN_ENT
.envtable resd EVC_ENT
.envcurve resd (EVC_ENT*2 + 1)
endstruc
section .text
extern _opmgen
extern _opmch
extern _opmcfg
; extern _sinshift
; extern _envshift
ENVCURVE equ (_opmcfg + opmcfg_t.envcurve)
SINTABLE equ (_opmcfg + opmcfg_t.sintable)
ENVTABLE equ (_opmcfg + opmcfg_t.envtable)
global @opmgen_getpcm@12
%macro op_out 0
add eax, [edi + slot_t.freq_cnt]
shr eax, (FREQ_BITS - SIN_BITS)
and eax, (SIN_ENT - 1)
; mov cl, [_sinshift + eax]
mov eax, [SINTABLE + eax*4]
; add cl, [_envshift + edx]
imul eax, [ENVTABLE + edx*4]
; sar eax, cl
sar eax, ENVTBL_BIT + SINTBL_BIT - TL_BITS
%endmacro
%macro calcenv 2
mov eax, [edi + slot_t.freq_inc]
add [edi + slot_t.freq_cnt], eax
mov eax, [edi + slot_t.env_cnt]
add eax, [edi + slot_t.env_inc]
cmp eax, [edi + slot_t.env_end]
jae near %1
%2: mov [edi + slot_t.env_cnt], eax
shr eax, ENV_BITS
mov edx, [edi + slot_t.totallevel]
sub edx, [ENVCURVE + eax*4]
%endmacro
%macro setenv 3
%1: mov dl, [edi + slot_t.env_mode]
dec dl
je short %%setrr
dec dl
je short %%setd2
dec dl
je short %%setd1
dec dl
jne short %%envret
mov byte [edi + slot_t.env_mode], EM_DECAY1
mov eax, [edi + slot_t.decaylevel]
mov [edi + slot_t.env_end], eax
mov eax, [edi + slot_t.env_inc_decay1]
mov [edi + slot_t.env_inc], eax
mov eax, EC_DECAY
%%envret: jmp near %2
%%setd1: mov byte [edi + slot_t.env_mode], EM_DECAY2
mov dword [edi + slot_t.env_end], EC_OFF
mov eax, [edi + slot_t.env_inc_decay2]
mov [edi + slot_t.env_inc], eax
mov eax, [edi + slot_t.decaylevel]
jmp near %2
%%setrr: mov byte [edi + slot_t.env_mode], EM_OFF
%%setd2: mov dword [edi + slot_t.env_end], EC_OFF + 1
and dword [edi + slot_t.env_inc], byte 0
and byte [esi + ch_t.playing], ~(%3)
mov eax, EC_OFF
jmp near %2
%endmacro
align 16
@opmgen_getpcm@12:
cmp dword [esp+4], byte 0
je near og_noupdate
cmp dword [_opmgen + opmgen_t.playing], byte 0
je near og_noupdate
push ebx
push esi
push edi
push ebp
sub esp, byte 8
OPN_SAMPL equ 0
OPN_SAMPR equ 4
OPN_LENG equ 16 + 8 + 4
mov ebp, edx
mov ebx, [_opmgen + opmgen_t.calcremain]
og_fmout_st: mov eax, ebx
imul ebx, [_opmgen + opmgen_t.outdl]
mov [esp + OPN_SAMPL], ebx
mov ebx, FMDIV_ENT
sub ebx, eax
imul eax, [_opmgen + opmgen_t.outdr]
mov [esp + OPN_SAMPR], eax
og_fmout_lp: mov [_opmgen + opmgen_t.calcremain], ebx
and dword [_opmgen + opmgen_t.playing], byte 0
and dword [_opmgen + opmgen_t.outdl], byte 0
and dword [_opmgen + opmgen_t.outdc], byte 0
and dword [_opmgen + opmgen_t.outdr], byte 0
mov ch, OPMCH_MAX
mov esi, _opmch
og_calcch_lp: mov cl, [esi + ch_t.outslot]
test cl, [esi + ch_t.playing]
je near og_calcch_nt
and dword [_opmgen + opmgen_t.feedback2], byte 0
and dword [_opmgen + opmgen_t.feedback3], byte 0
and dword [_opmgen + opmgen_t.feedback4], byte 0
mov edi, esi
calcenv envcalc1, envret1 ; slot1 calculate
jl near og_calcslot3
mov cl, [esi + ch_t.feedback]
test cl, cl
je short og_nofeed
mov eax, [esi + ch_t.op1fb] ; with feedback
mov ebx, eax
shr eax, cl
op_out
mov [esi + ch_t.op1fb], eax
add eax, ebx
sar eax, 1
jmp short og_algchk
og_nofeed: xor eax, eax ; without feedback
op_out
og_algchk: cmp byte [esi + ch_t.algorithm], 5
jne short og_calcalg5
mov [_opmgen + opmgen_t.feedback2], eax ; case ALG == 5
mov [_opmgen + opmgen_t.feedback3], eax
mov [_opmgen + opmgen_t.feedback4], eax
jmp short og_calcslot3
og_calcalg5: mov ebx, [esi + ch_t.connect1] ; case ALG != 5
add [ebx], eax
og_calcslot3: add edi, byte slot_t.size ; slot3 calculate
calcenv envcalc2, envret2
jl short og_calcslot2
mov eax, [_opmgen + opmgen_t.feedback2]
op_out
mov ebx, [esi + ch_t.connect2]
add [ebx], eax
og_calcslot2: add edi, byte slot_t.size ; slot2 calculate
calcenv envcalc3, envret3
jl short og_calcslot4
mov eax, [_opmgen + opmgen_t.feedback3]
op_out
mov ebx, [esi + ch_t.connect3]
add [ebx], eax
og_calcslot4: add edi, byte slot_t.size ; slot4 calculate
calcenv envcalc4, envret4
jl short og_calcsloted
mov eax, [_opmgen + opmgen_t.feedback4]
op_out
mov ebx, [esi + ch_t.connect4]
add [ebx], eax
og_calcsloted: inc dword [_opmgen + opmgen_t.playing]
og_calcch_nt: add esi, ch_t.size
dec ch
jne near og_calcch_lp
mov eax, [_opmgen + opmgen_t.outdc]
add [_opmgen + opmgen_t.outdl], eax
add [_opmgen + opmgen_t.outdr], eax
sar dword [_opmgen + opmgen_t.outdl], FMVOL_SFTBIT
sar dword [_opmgen + opmgen_t.outdr], FMVOL_SFTBIT
mov edx, [_opmcfg + opmcfg_t.calc1024]
mov ebx, [_opmgen + opmgen_t.calcremain]
mov eax, ebx
sub ebx, edx
jbe short og_nextsamp
mov [_opmgen + opmgen_t.calcremain], ebx
mov eax, edx
imul eax, [_opmgen + opmgen_t.outdl]
add [esp + OPN_SAMPL], eax
imul edx, [_opmgen + opmgen_t.outdr]
add [esp + OPN_SAMPR], edx
jmp near og_fmout_lp
og_nextsamp: neg ebx
mov [_opmgen + opmgen_t.calcremain], ebx
mov edx, eax
mov ecx, [_opmcfg + opmcfg_t.fmvol]
imul eax, [_opmgen + opmgen_t.outdl]
imul edx, [_opmgen + opmgen_t.outdr]
add eax, [esp + OPN_SAMPL]
add edx, [esp + OPN_SAMPR]
sar eax, 8
sar edx, 8
imul eax, ecx
imul edx, ecx
sar eax, (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8)
sar edx, (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8)
add [ebp+0], eax
add [ebp+4], edx
add ebp, byte 8
dec dword [esp + OPN_LENG]
jne near og_fmout_st
add esp, byte 8
pop ebp
pop edi
pop esi
pop ebx
og_noupdate: ret 4
setenv envcalc1, envret1, 1
setenv envcalc2, envret2, 2
setenv envcalc3, envret3, 4
setenv envcalc4, envret4, 8
ends
RetroPC.NET-CVS <cvs@retropc.net>