File:  [RetroPC.NET] / np2 / win9x / x86 / opngeng.x86
Revision 1.8: download - view: text, annotated - select for diffs
Fri Feb 4 23:43:55 2011 JST (14 years, 8 months ago) by yui
Branches: MAIN
CVS tags: HEAD
fixed opna detune parameters


FMDIV_BITS		equ		8
FMDIV_ENT		equ		(1 << FMDIV_BITS)
FMVOL_SFTBIT	equ		4

SIN_BITS		equ		11
EVC_BITS		equ		10
ENV_BITS		equ		16
KF_BITS			equ		6
FREQ_BITS		equ		21
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
.totallevel		resd	1		; 04
.decaylevel		resd	1		; 08
.attack			resd	1		; 0c
.decay1			resd	1		; 10
.decay2			resd	1		; 14
.release		resd	1		; 18
.freq_cnt		resd	1		; 1c
.freq_inc		resd	1		; 20
.multiple		resd	1		; 24
.keyscale		resb	1		; 28
.env_mode		resb	1		; 29
.envraito		resb	1		; 2a
.ssgeg1			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
				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	4

.keyfunc		resb	4
.kcode			resb	4
.pan			resb	1
.extop			resb	1
.stereo			resb	1
				resb	1
				endstruc

				struc opngen_t
.playchannels	resd	1
.playing		resd	1
.feedback2		resd	1
.feedback3		resd	1
.feedback4		resd	1
.outdl			resd	1
.outdc			resd	1
.outdr			resd	1
.calcremain		resd	1
.keyreg			resb	12
				endstruc

				struc opncfg_t
.calc1024		resd	1
.fmvol			resd	1
.ratebit		resd	1
.vr_en			resd	1
.vr_l			resd	1
.vr_r			resd	1

.sintable		resd	SIN_ENT
.envtable		resd	EVC_ENT
.envcurve		resd	(EVC_ENT*2 + 1)
				endstruc


section .text

	extern	_opngen
	extern	_opnch
	extern	_opncfg

	extern	_sinshift
	extern	_envshift

ENVCURVE	equ		(_opncfg + opncfg_t.envcurve)
SINTABLE	equ		(_opncfg + opncfg_t.sintable)
ENVTABLE	equ		(_opncfg + opncfg_t.envtable)


	global	@opngen_getpcm@12
	global	@opngen_getpcmvr@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
%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
@opngen_getpcm@12:
				cmp		dword [esp+4], byte 0
				je		near og_noupdate
				cmp		dword [_opngen + opngen_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, [_opngen + opngen_t.calcremain]
og_fmout_st:	mov		eax, ebx
				imul	ebx, [_opngen + opngen_t.outdl]
				mov		[esp + OPN_SAMPL], ebx
				mov		ebx, FMDIV_ENT
				sub		ebx, eax
				imul	eax, [_opngen + opngen_t.outdr]
				mov		[esp + OPN_SAMPR], eax
og_fmout_lp:	mov		[_opngen + opngen_t.calcremain], ebx
				and		dword [_opngen + opngen_t.playing], byte 0
				and		dword [_opngen + opngen_t.outdl], byte 0
				and		dword [_opngen + opngen_t.outdc], byte 0
				and		dword [_opngen + opngen_t.outdr], byte 0
				mov		ch, [_opngen + opngen_t.playchannels]
				mov		esi, _opnch
og_calcch_lp:	mov		cl, [esi + ch_t.outslot]
				test	cl, [esi + ch_t.playing]
				je		near og_calcch_nt
				and		dword [_opngen + opngen_t.feedback2], byte 0
				and		dword [_opngen + opngen_t.feedback3], byte 0
				and		dword [_opngen + opngen_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		[_opngen + opngen_t.feedback2], eax		; case ALG == 5
				mov		[_opngen + opngen_t.feedback3], eax
				mov		[_opngen + opngen_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, [_opngen + opngen_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, [_opngen + opngen_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, [_opngen + opngen_t.feedback4]
				op_out
				mov		ebx, [esi + ch_t.connect4]
				add		[ebx], eax
og_calcsloted:	inc		dword [_opngen + opngen_t.playing]
og_calcch_nt:	add		esi, ch_t_size
				dec		ch
				jne		near og_calcch_lp
				mov		eax, [_opngen + opngen_t.outdc]
				add		[_opngen + opngen_t.outdl], eax
				add		[_opngen + opngen_t.outdr], eax
				sar		dword [_opngen + opngen_t.outdl], FMVOL_SFTBIT
				sar		dword [_opngen + opngen_t.outdr], FMVOL_SFTBIT
				mov		edx, [_opncfg + opncfg_t.calc1024]
				mov		ebx, [_opngen + opngen_t.calcremain]
				mov		eax, ebx
				sub		ebx, edx
				jbe		short og_nextsamp
				mov		[_opngen + opngen_t.calcremain], ebx
				mov		eax, edx
				imul	eax, [_opngen + opngen_t.outdl]
				add		[esp + OPN_SAMPL], eax
				imul	edx, [_opngen + opngen_t.outdr]
				add		[esp + OPN_SAMPR], edx
				jmp		near og_fmout_lp
og_nextsamp:	neg		ebx
				mov		[_opngen + opngen_t.calcremain], ebx
				mov		ecx, eax
				imul	eax, [_opngen + opngen_t.outdl]
				add		eax, [esp + OPN_SAMPL]
				imul	dword [_opncfg + opncfg_t.fmvol]
				add		[ebp], edx
				mov		eax, [_opngen + opngen_t.outdr]
				imul	ecx
				add		eax, [esp + OPN_SAMPR]
				imul	dword [_opncfg + opncfg_t.fmvol]
				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


				align	16
@opngen_getpcmvr@12:
				cmp		dword [_opncfg + opncfg_t.vr_en], byte 0
				je		near @opngen_getpcm@12

				cmp		dword [esp+4], byte 0
				je		near ogv_noupdate

				push	ebx
				push	esi
				push	edi
				push	ebp
				sub		esp, byte 8

OPNV_SAMPL		equ		0
OPNV_SAMPR		equ		4
OPNV_LENG		equ		16 + 8 + 4

				mov		ebp, edx
				mov		ebx, [_opngen + opngen_t.calcremain]
ogv_fmout_st:	mov		eax, ebx
				imul	ebx, [_opngen + opngen_t.outdl]
				mov		[esp + OPNV_SAMPL], ebx
				mov		ebx, FMDIV_ENT
				sub		ebx, eax
				imul	eax, [_opngen + opngen_t.outdr]
				mov		[esp + OPNV_SAMPR], eax
ogv_fmout_lp:	xor		eax, eax
				mov		[_opngen + opngen_t.calcremain], ebx
				mov		[_opngen + opngen_t.outdl], eax
				mov		[_opngen + opngen_t.outdc], eax
				mov		[_opngen + opngen_t.outdr], eax
				mov		ch, [_opngen + opngen_t.playchannels]
				mov		edi, _opnch
ogv_calcch_lp:	xor		eax, eax
				mov		[_opngen + opngen_t.feedback2], eax
				mov		[_opngen + opngen_t.feedback3], eax
				mov		[_opngen + opngen_t.feedback4], eax
				mov		esi, edi
				calcenv	vrenvcalc1, vrenvret1		; slot1 calculate
				jl		near ogv_calcslot3
				mov		cl, [esi + ch_t.feedback]
				test	cl, cl
				je		short ogv_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 ogv_algchk
ogv_nofeed:		xor		eax, eax					; without feedback
				op_out
ogv_algchk:		cmp		byte [esi + ch_t.algorithm], 5
				jne		short ogv_calcalg5
				mov		[_opngen + opngen_t.feedback2], eax		; case ALG == 5
				mov		[_opngen + opngen_t.feedback3], eax
				mov		[_opngen + opngen_t.feedback4], eax
				jmp		short ogv_calcslot3
ogv_calcalg5:	mov		ebx, [esi + ch_t.connect1]	; case ALG != 5
				add		[ebx], eax
ogv_calcslot3:	add		edi, byte slot_t_size		; slot3 calculate
				calcenv	vrenvcalc2, vrenvret2
				jl		short ogv_calcslot2
				mov		eax, [_opngen + opngen_t.feedback2]
				op_out
				mov		ebx, [esi + ch_t.connect2]
				add		[ebx], eax
ogv_calcslot2:	add		edi, byte slot_t_size		; slot2 calculate
				calcenv	vrenvcalc3, vrenvret3
				jl		short ogv_calcslot4
				mov		eax, [_opngen + opngen_t.feedback3]
				op_out
				mov		ebx, [esi + ch_t.connect3]
				add		[ebx], eax
ogv_calcslot4:	add		edi, byte slot_t_size		; slot4 calculate
				calcenv	vrenvcalc4, vrenvret4
				jl		short ogv_calcsloted
				mov		eax, [_opngen + opngen_t.feedback4]
				op_out
				mov		ebx, [esi + ch_t.connect4]
				add		[ebx], eax
ogv_calcsloted:	add		edi, byte (ch_t_size - (slot_t_size * 3))
				dec		ch
				jne		near ogv_calcch_lp
				mov		eax, [_opngen + opngen_t.outdl]
				mov		edx, [_opngen + opngen_t.outdc]
				imul	eax, [_opncfg + opncfg_t.vr_l]
				mov		ebx, edx
				sar		eax, 5
				add		ebx, eax
				sar		eax, 2
				add		edx, eax
				mov		eax, [_opngen + opngen_t.outdr]
				imul	eax, [_opncfg + opncfg_t.vr_r]
				sar		eax, 5
				add		edx, eax
				sar		eax, 2
				add		ebx, eax
				add		[_opngen + opngen_t.outdl], edx
				add		[_opngen + opngen_t.outdr], ebx
				sar		dword [_opngen + opngen_t.outdl], FMVOL_SFTBIT
				sar		dword [_opngen + opngen_t.outdr], FMVOL_SFTBIT
				mov		edx, [_opncfg + opncfg_t.calc1024]
				mov		ebx, [_opngen + opngen_t.calcremain]
				mov		eax, ebx
				sub		ebx, edx
				jbe		short ogv_nextsamp
				mov		[_opngen + opngen_t.calcremain], ebx
				mov		eax, edx
				imul	eax, [_opngen + opngen_t.outdl]
				add		[esp + OPNV_SAMPL], eax
				imul	edx, [_opngen + opngen_t.outdr]
				add		[esp + OPNV_SAMPR], edx
				jmp		near ogv_fmout_lp
ogv_nextsamp:	neg		ebx
				mov		[_opngen + opngen_t.calcremain], ebx
				mov		ecx, eax
				imul	eax, [_opngen + opngen_t.outdl]
				add		eax, [esp + OPNV_SAMPL]
				imul	dword [_opncfg + opncfg_t.fmvol]
				add		[ebp], edx
				mov		eax, [_opngen + opngen_t.outdr]
				imul	ecx
				add		eax, [esp + OPNV_SAMPR]
				imul	dword [_opncfg + opncfg_t.fmvol]
				add		[ebp+4], edx
				add		ebp, byte 8
				dec		dword [esp + OPNV_LENG]
				jne		near ogv_fmout_st
				add		esp, byte 8
				pop		ebp
				pop		edi
				pop		esi
				pop		ebx
ogv_noupdate:	ret		4

				setenv	vrenvcalc1, vrenvret1, 1
				setenv	vrenvcalc2, vrenvret2, 2
				setenv	vrenvcalc3, vrenvret3, 4
				setenv	vrenvcalc4, vrenvret4, 8


RetroPC.NET-CVS <cvs@retropc.net>