Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 839fab41a5
Fetching contributors…

Cannot retrieve contributors at this time

5881 lines (5068 sloc) 160.178 kb
; This file is distributed under a BSD license. See LICENSE.txt for details.
;#####################################################################################
;
;
; Farb-Rausch ViruZ II - wer das liest, ist rule
;
;
;#####################################################################################
%define POLY 64 ; maximum polyphony
%define LOWEST 39000000h ; out of 16bit range
%define MDMAXOFFS 1024
%define MAX_FRAME_SIZE 280
%define VUMETER
%define V2PROFILER 0 ; profiling support. refer to tinyplayer
;%define RONAN
%define FULLMIDI
%define FIXDENORMALS 1 ; there's really no good reason to turn this off.
icnoisemul equ 196314165
icnoiseadd equ 907633515
section .bss
;global this
;global temp
;global oldfpcw
;global todo
;global outptr
;global addflg
this resd 1
temp resd 16
oldfpcw resd 1
todo resd 2
outptr resd 2
addflg resd 1
SRfcobasefrq resd 1 ; C-3: 130.81278265029931733892499676165 Hz * 2^32 / SR
SRfclinfreq resd 1 ; 44100hz/SR
SRfcBoostSin resd 1 ; sin of 150hz/SR
SRfcBoostCos resd 1 ; cos of 150hz/SR
SRcFrameSize resd 1
SRfciframe resd 1
SRfcdcfilter resd 1
section .data
global _AUX_
_AUX_
fci12 dd 0.083333333333
fc2 dd 2.0
fc3 dd 3.0
fc6 dd 6.0
fc15 dd 15.0
fc32bit dd 2147483647.0
fci127 dd 0.007874015748
fci128 dd 0.0078125
fci6 dd 0.16666666666
fci4 dd 0.25
fci2 dd 0.5
fcpi_2 dd 1.5707963267948966192313216916398
fcpi dd 3.1415926535897932384626433832795
fc1p5pi dd 4.7123889803846898576939650749193
fc2pi dd 6.28318530717958647692528676655901
fc64 dd 64.0
fc32 dd 32.0
fci16 dd 0.0625
fcipi_2 dd 0.636619772367581343075535053490057
fc32768 dd 32768.0
fc256 dd 256.0
fc10 dd 10.0
fci32768 dd 0.000030517578125
fc1023 dd 1023.0
fcm12 dd -12.0
fcm16 dd -16.0
fci8192 dd 0.0110485434560398050687631931578883
fci64 dd 0.015625
fc48 dd 48.0
fcdcflt dd 126.0
fc0p8 dd 0.8
fc5p6 dd 5.6
fccfframe dd 11.0 ; for calcfreq2
fcOscPitchOffs dd 60.0
fcfmmax dd 2.0
fcattackmul dd -0.09375 ;-0.0859375
fcattackadd dd 7.0
fcsusmul dd 0.0019375
fcgain dd 0.6
fcgainh dd 0.6
fcmdlfomul dd 1973915.486621315192743764172335601
fcsamplesperms dd 44.1
fccrelease dd 0.01
fccpdfalloff dd 0.9998
%ifdef VUMETER
fcvufalloff dd 0.9999
%endif
fcsinx3 dq -0.16666
fcsinx5 dq 0.0083143
fcsinx7 dq -0.00018542
; r(x) = (x + 0.43157974*x^3)/(1 + 0.76443945*x^2 + 0.05831938*x^4)
; second set of coeffs is for r(1/x)
fcatanx1 dq 1.0 , -0.431597974
fcatanx3 dq 0.43157974 , -1.0
fcatanxm0 dq 1.0 , 0.05831938
fcatanxm4 dq 0.05831938 , 1.0
fcatanxm2 dq 0.76443945
fcatanadd dq 0.0 , 1.5707963267948966192313216916398
fcoscbase dd 261.6255653005986346778499935233
fcsrbase dd 44100.0
fcboostfreq dd 150.0
fcframebase dd 128.0
fcdcoffset dd 0.000003814697265625 ; 2^-18
;#####################################################################################
; Performance Monitor
;#####################################################################################
%define V2Perf_TOTAL 0
%define V2Perf_OSC 1
%define V2Perf_VCF 2
%define V2Perf_DIST 3
%define V2Perf_BASS 4
%define V2Perf_MODDEL 5
%define V2Perf_COMPRESSOR 6
%define V2Perf_PARAEQ 7
%define V2Perf_REVERB 8
%define V2Perf_RONAN 9
%define V2Perf_MAX 10
%if V2PROFILER
global _V2Perf
_V2Perf:
; 1234567890123456
db "Total ",0,0,0,0,0,0,0,0
db "Oscillators ",0,0,0,0,0,0,0,0
db "Filters ",0,0,0,0,0,0,0,0
db "Distortion ",0,0,0,0,0,0,0,0
db "Bass Boost ",0,0,0,0,0,0,0,0
db "ModDelay ",0,0,0,0,0,0,0,0
db "Compressor ",0,0,0,0,0,0,0,0
db "Equalizer ",0,0,0,0,0,0,0,0
db "Reverb ",0,0,0,0,0,0,0,0
db "Ronan ",0,0,0,0,0,0,0,0
times 24 db 0
V2PerfCounter:
times V2Perf_MAX dd 0,0
%endif
%macro V2PerfEnter 1
%if V2PROFILER
push eax
push edx
rdtsc
sub dword [V2PerfCounter + %1*8], eax
sbb dword [V2PerfCounter + %1*8 + 4], edx
pop edx
pop eax
%endif
%endmacro
%macro V2PerfLeave 1
%if V2PROFILER
push eax
push edx
rdtsc
add dword [V2PerfCounter + %1*8], eax
adc dword [V2PerfCounter + %1*8 + 4], edx
pop edx
pop eax
%endif
%endmacro
%macro V2PerfClear 0
%if V2PROFILER
push edi
push eax
push ecx
mov edi, V2PerfCounter
mov ecx, V2Perf_MAX * 2
xor eax, eax
rep stosd
pop ecx
pop eax
pop edi
%endif
%endmacro
%macro V2PerfCopy 0
%if V2PROFILER
push esi
push edi
mov esi, V2PerfCounter
mov edi, _V2Perf
%%lp:
cmp byte [edi], 0
je %%end
add edi, byte 16
movsd
movsd
jmp short %%lp
%%end:
pop edi
pop esi
%endif
%endmacro
;#####################################################################################
; Helper Routines
;#####################################################################################
section .text
global fastatan
fastatan: ; fast atan
; value in st0, -1 in st1, high 16bits in ax, "8" in ebx
shl ax, 1
fld1 ; <1> <val> <-1>
fcmovb st0, st2 ; <sign> <val> <-1>
xor edx, edx
cmp ah, 7fh
fmul st1, st0 ; <sign> <absval> <-1>
cmovge edx, ebx
fxch st1 ; <x> <sign> <-1>
; r(x)= (cx1*x + cx3*x^3)/(cxm0 + cxm2*x^2 + cxm4*x^4)
fld st0 ; <x> <x> <sign> <-1>
fmul st0, st0 ; <x²> <x> <sign> <-1>
fld st0 ; <x²> <x²> <x> <sign> <-1>
fld st0 ; <x²> <x²> <x²> <x> <sign> <-1>
fmul qword [fcatanx3 + edx] ; <x²*cx3> <x²> <x²> <x> <sign> <-1>
fxch st1 ; <x²> <x²(cx3)> <x²> <x> <sign> <-1>
fmul qword [fcatanxm4 + edx] ; <x²(cxm4)> <x²(cx3)> <x²> <x> <sign> <-1>
fxch st1 ; <x²(cx3)> <x²(cxm4)> <x²> <x> <sign> <-1>
fadd qword [fcatanx1 + edx] ; <cx1+x²(cx3)> <x²(cxm4)> <x²> <x> <sign> <-1>
fxch st1 ; <x²(cxm4)> <cx1+x²(cx3)> <x²> <x> <sign> <-1>
fadd qword [fcatanxm2] ; <cxm2+x²(cxm4)> <cx1+x²(cx3)> <x²> <x> <sign> <-1>
fxch st1 ; <cx1+x²(cx3)> <cxm2+x²(cxm4)> <x²> <x> <sign> <-1>
fmulp st3, st0 ; <cxm2+x²(cxm4)> <x²> <x(cx1)+x³(cx3)> <sign> <-1>
fmulp st1, st0 ; <x²(cxm2)+x^4(cxm4)> <x(cx1)+x³(cx3)> <sign> <-1>
fadd qword [fcatanxm0 + edx] ; <cxm0+x²(cxm2)+x^4(cxm4)> <x(cx1)+x³(cx3)> <sign> <-1>
fdivp st1, st0 ; <r(x)> <sign> <-1>
fadd qword [fcatanadd + edx] ; <r(x)+adder) <sign> <-1>
fmulp st1, st0 ; <sign*r'(x)> <-1>
ret
global fastsinrc
global fastsin
; x+ax3+bx5+cx7
; ((((c*x²)+b)*x²+a)*x²+1)*x
fastsinrc: ; fast sinus with range check
fld dword [fc2pi] ; <2pi> <x>
fxch st1 ; <x> <2pi>
fprem ; <x'> <2pi>
fxch st1 ; <2pi> <x'>
fstp st0 ; <x'>
fld1 ; <1> <x>
fldz ; <0> <1> <x>
fsub st0, st1 ; <mul> <1> <x>
fldpi ; <sub> <mul> <1> <x>
fld dword [fcpi_2] ; <pi/2> <sub> <mul> <1> <x>
fcomi st0, st4
fstp st0 ; <sub> <mul> <1> <x>
fldz ; <0> <sub> <mul> <1> <x>
fxch st1 ; <sub> <0> <mul> <1> <x>
fcmovnb st0, st1 ; <sub'> <0> <mul> <1> <x>
fxch st1 ; <0> <sub'> <mul> <1> <x>
fstp st0 ; <sub'> <mul> <1> <x>
fxch st1 ; <mul> <sub'> <1> <x>
fcmovnb st0, st2 ; <mul'> <sub'> <1> <x>
fld dword [fc1p5pi] ; <1.5pi> <mul'> <sub'> <1> <x>
fcomi st0, st4
fstp st0 ; <mul'> <sub'> <1> <x>
fld dword [fc2pi] ; <2pi> <mul'> <sub'> <1> <x>
fxch st1 ; <mul'> <2pi> <sub'> <1> <x>
fcmovb st0, st3 ; <mul''> <2pi> <sub'> <1> <x>
fxch st2 ; <sub'> <2pi> <mul''> <1> <x>
fcmovb st0, st1 ; <sub''> <2pi> <mul''> <1> <x>
fsubp st4, st0 ; <2pi> <mul''> <1> <x-sub>
fstp st0 ; <mul''> <1> <x-sub>
fmulp st2, st0 ; <1> <mul(x-sub)>
fstp st0 ; <mul(x-sub)>
fastsin: ; fast sinus approximation (st0 -> st0) from -pi/2 to pi/2, about -80dB error, should be ok
fld st0 ; <x> <x>
fmul st0, st1 ; <x²> <x>
fld qword [fcsinx7] ; <c> <x²> <x>
fmul st0, st1 ; <cx²> <x²> <x>
fadd qword [fcsinx5] ; <b+cx²> <x²> <x>
fmul st0, st1 ; <x²(b+cx²)> <x²> <x>
fadd qword [fcsinx3] ; <a+x²(b+cx²)> <x²> <x>
fmulp st1, st0 ; <x²(a+x²(b+cx²)> <x>
fld1 ; <1> <x²(a+x²(b+cx²)> <x>
faddp st1, st0 ; <1+x²(a+x²(b+cx²)> <x>
fmulp st1, st0 ; <x(1+x²(a+x²(b+cx²))>
ret
global calcNewSampleRate
calcNewSampleRate: ; new SR in eax
mov [temp], eax
fild dword [temp] ; <sr>
fld1 ; <1> <sr>
fdiv st0, st1 ; <1/sr> <sr>
fld dword [fcoscbase] ; <oscbHz> <1/sr> <sr>
fmul dword [fc32bit] ; <oscb32> <1/sr> <sr>
fmul st0, st1 ; <oscbout> <1/sr> <sr>
fstp dword [SRfcobasefrq] ; <1/sr> <sr>
fld dword [fcsrbase] ; <srbase> <1/sr> <sr>
fmul st0, st1 ; <linfrq> <1/sr> <sr>
fstp dword [SRfclinfreq] ; <1/sr> <sr>
fld st0 ; <1/sr> <1/sr> <sr>
fmul dword [fc2pi] ; <boalpha> <1/sr> <sr>
fmul dword [fcboostfreq] ; <bof/sr> <1/sr> <sr>
fsincos ; <cos> <sin> <1/sr> <sr>
fstp dword [SRfcBoostCos] ; <sin> <1/sr> <sr>
fstp dword [SRfcBoostSin] ; <1/sr> <sr>
fmul dword [fcdcflt] ; <126/sr> <sr>
fld1 ; <1> <126/sr> <sr>
fsubrp st1, st0 ; <dcfilterR> <sr>
fstp dword [SRfcdcfilter] ; <sr>
fmul dword [fcframebase] ; <framebase*sr>
fdiv dword [fcsrbase] ; <framelen>
fadd dword [fci2] ; <round framelen>
fistp dword [SRcFrameSize] ; -
fild dword [SRcFrameSize] ; <framelen>
fld1 ; <1> <framelen>
fdivrp st1, st0 ; <1/framelen>
fstp dword [SRfciframe] ; -
ret
calcfreq2:
fld1 ; 1 <0..1>
fsubp st1, st0 ; <-1..0>
fmul dword [fccfframe] ; <-11..0> -> <1/2048..1>
fld1
fld st1
fprem
f2xm1
faddp st1, st0
fscale
fstp st1
ret
global calcfreq2
global calcfreq
global pow2
global pow
calcfreq: ; (0..1 linear zu 2^-10..1)
fld1 ; 1 <0..1>
fsubp st1, st0 ; <-1..0>
fmul dword [fc10] ; <-10..0> -> <1/1024..1>
fld1
fld st1
fprem
f2xm1
faddp st1, st0
fscale
fstp st1
ret
pow2:
fld1
fld st1
fprem
f2xm1
faddp st1, st0
fscale
fstp st1
ret
pow:
fyl2x
fld1
fld st1
fprem
f2xm1
faddp st1, st0
fscale
fstp st1
ret
;#####################################################################################
; Oszillator
;#####################################################################################
global _OSC_
_OSC_
struc syVOsc
.mode resd 1
.ring resd 1
.pitch resd 1
.detune resd 1
.color resd 1
.gain resd 1
.size
endstruc
struc syWOsc
.mode resd 1 ; dword: mode (0=tri/saw 1=pulse 2=sin 3=noise)
.ring resd 1 ; dword: ringmod on/off
.cnt resd 1 ; dword: wave counter (32bit)
.freq resd 1 ; dword: wave counter inc (8x/sample)
.brpt resd 1 ; dword: break point für tri/pulse (32bit)
.nffrq resd 1 ; noise: filter freq
.nfres resd 1 ; noise: filter reso
.nseed resd 1 ; noise: random seed
.gain resd 1 ; output gain
.gain4 resd 1 ; output gain (oversampled)
.tmp resd 1 ; temp
.nfl resd 1 ; noise filter L buffer
.nfb resd 1 ; noise filter B buffer
.note resd 1 ; note
.pitch resd 1 ; pitch
.size
endstruc
syOscInit:
pushad
xor eax, eax
mov [ebp + syWOsc.cnt], eax
mov [ebp + syWOsc.cnt], eax
mov [ebp + syWOsc.nfl], eax
mov [ebp + syWOsc.nfb], eax
rdtsc
mov [ebp + syWOsc.nseed], eax
popad
ret
syOscChgPitch:
fld dword [ebp + syWOsc.pitch]
fld st0
fadd dword [fc64]
fmul dword [fci128]
call calcfreq
fmul dword [SRfclinfreq]
fstp dword [ebp + syWOsc.nffrq]
fadd dword [ebp + syWOsc.note]
fsub dword [fcOscPitchOffs]
fmul dword [fci12]
call pow2
fmul dword [SRfcobasefrq]
fistp dword [ebp + syWOsc.freq]
ret
syOscSet:
pushad
fld dword [esi + syVOsc.mode]
fistp dword [ebp + syWOsc.mode]
fld dword [esi + syVOsc.ring]
fistp dword [ebp + syWOsc.ring]
fld dword [esi + syVOsc.pitch]
fsub dword [fc64]
fld dword [esi + syVOsc.detune]
fsub dword [fc64]
fmul dword [fci128]
faddp st1, st0
fstp dword [ebp + syWOsc.pitch]
call syOscChgPitch
fld dword [esi + syVOsc.gain]
fmul dword [fci128]
fst dword [ebp + syWOsc.gain]
fmul dword [fci4]
fstp dword [ebp + syWOsc.gain4]
fld dword [esi + syVOsc.color] ; <c>
fmul dword [fci128] ; <c'>
fld st0 ; <c'> <c'>
fmul dword [fc32bit] ; <bp> <c'>
fistp dword [ebp + syWOsc.brpt] ; <c'>
shl dword [ebp + syWOsc.brpt],1
fsqrt ; <rc'>
fld1 ; <1> <rc'>
fsubrp st1, st0 ; <1-rc'>
fstp dword [ebp + syWOsc.nfres] ; -
popad
ret
; edi: dest buf
; esi: source buf
; ecx: # of samples
; ebp: workspace
section .data
oscjtab dd syOscRender.off, syOscRender.mode0, syOscRender.mode1, syOscRender.mode2,
dd syOscRender.mode3, syOscRender.mode4, syOscRender.auxa, syOscRender.auxb
section .text
syOscRender:
pushad
V2PerfEnter V2Perf_OSC
lea edi, [edi + 4*ecx]
neg ecx
movzx eax, byte [ebp + syWOsc.mode]
and al, 7
jmp dword [oscjtab + 4*eax]
section .data
.m0casetab dd syOscRender.m0c2, ; ...
dd syOscRender.m0c1, ; ..n , INVALID!
dd syOscRender.m0c212, ; .c.
dd syOscRender.m0c21, ; .cn
dd syOscRender.m0c12, ; o..
dd syOscRender.m0c1, ; o.n
dd syOscRender.m0c2, ; oc. , INVALID!
dd syOscRender.m0c121 ; ocn
section .text
.mode0 ; tri/saw
mov eax, [ebp + syWOsc.cnt]
mov esi, [ebp + syWOsc.freq]
; calc float helper values
mov ebx, esi
shr ebx, 9
or ebx, 0x3f800000
mov [ebp + syWOsc.tmp], ebx
fld dword [ebp + syWOsc.gain] ; <g>
fld1 ; 1 <g>
fsubr dword [ebp + syWOsc.tmp] ; <f> <g>
fld1 ; <1> <f> <g>
fdiv st0, st1 ; <1/f> <f> <g>
fld st2 ; <g> <1/f> <f> <g>
mov ebx, [ebp + syWOsc.brpt]
shr ebx, 9
or ebx, 0x3f800000
mov [ebp + syWOsc.tmp], ebx
fld dword [ebp + syWOsc.tmp] ; <b> <g> <1/f> <f> <g>
fld1 ; <1> <b> <g> <1/f> <f> <g>
fsubr st0, st1 ; <col> <b> <g> <1/f> <f> <g>
; m1=2/col
; m2=-2/(1-col)
; c1=gain/2*m1 = gain/col
; c2=gain/2*m2 = -gain/(1-col)
fld st0 ; <col> <col> <b> <g> <1/f> <f> <g>
fdivr st0, st3 ; <c1> <col> <b> <g> <1/f> <f> <g>
fld1 ; <1> <c1> <col> <b> <g> <1/f> <f> <g>
fsubrp st2, st0 ; <c1> <1-col> <b> <g> <1/f> <f> <g>
fxch st1 ; <1-col> <c1> <b> <g> <1/f> <f> <g>
fdivp st3, st0 ; <c1> <b> <g/(1-col)> <1/f> <f> <g>
fxch st2 ; <g/(1-col)> <b> <c1> <1/f> <f> <g>
fchs ; <c2> <b> <c1> <1/f> <f> <g>
; calc state
mov ebx, eax
sub ebx, esi ; ................................ c
rcr edx, 1 ; c............................... .
cmp ebx, [ebp + syWOsc.brpt] ; c............................... n
rcl edx, 2 ; ..............................nc .
.m0loop
mov ebx, eax
shr ebx, 9
or ebx, 0x3f800000
mov [ebp + syWOsc.tmp], ebx
fld dword [ebp + syWOsc.tmp] ; <p+b> <c2> <b> <c1> <1/f> <f> <g>
fsub st0, st2 ; <p> <c2> <b> <c1> <1/f> <f> <g>
cmp eax, [ebp + syWOsc.brpt] ; ..............................oc n
rcl edx, 1 ; .............................ocn .
and edx, 7 ; 00000000000000000000000000000ocn
jmp dword [cs: .m0casetab + 4*edx]
; cases: on entry <p> <c2> <b> <c1> <1/f> <f>, on exit: <y> <c2> <b> <c1> <1/f> <f>
.m0c21 ; y=-(g+c2(p-f+1)²-c1p²)*(1/f)
fld1 ; <1> <p> <c2> <b> <c1> <1/f> <f> <g>
fadd st0, st1 ; <p+1> <p> <c2> <b> <c1> <1/f> <f> <g>
fsub st0, st6 ; <p+1-f> <p> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st0 ; <(p+1-f)²> <p> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st2 ; <c2(p+1-f)²> <p> <c2> <b> <c1> <1/f> <f> <g>
fxch st1 ; <p> <c2(p+1-f)²> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st0 ; <p²> <c2(p+1-f)²> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st4 ; <c1p²> <c2(p+1-f)²> <c2> <b> <c1> <1/f> <f> <g>
fsubp st1, st0 ; <c2(p-f+1)²-c1p²> <c2> <b> <c1> <1/f> <f> <g>
fadd st0, st6 ; <g+c2(p-f+1)²-c1p²> <c2> <b> <c1> <1/f> <f> <g>
fchs ; <-(g+c2(p-f+1)²-c1p²)> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st4 ; <y> <c2> <b> <c1> <1/f> <f> <g>
jmp short .m0pl
.m0c121 ; y=(-g-c1(1-f)(2p+1-f))*(1/f)
fadd st0, st0 ; <2p> <c2> <b> <c1> <1/f> <f> <g>
fld1 ; <1> <2p> <c2> <b> <c1> <1/f> <f> <g>
fsub st0, st6 ; <1-f> <2p> <c2> <b> <c1> <1/f> <f> <g>
fxch st1 ; <2p> <1-f> <c2> <b> <c1> <1/f> <f> <g>
fadd st0, st1 ; <2p+1-f> <1-f> <c2> <b> <c1> <1/f> <f> <g>
fmulp st1, st0 ; <(1-f)(2p+1-f)> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st3 ; <c1(1-f)(2p+1-f)> <c2> <b> <c1> <1/f> <f> <g>
fadd st0, st6 ; <g+c1(1-f)(2p+1-f)> <c2> <b> <c1> <1/f> <f> <g>
fchs ; <-g-c1(1-f)(2p+1-f)> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st4 ; <y> <c2> <b> <c1> <1/f> <f> <g>
jmp short .m0pl
.m0c212 ; y=(g-c2(1-f)(2p+1-f))*(1/f)
fadd st0, st0 ; <2p> <c2> <b> <c1> <1/f> <f> <g>
fld1 ; <1> <2p> <c2> <b> <c1> <1/f> <f> <g>
fsub st0, st6 ; <1-f> <2p> <c2> <b> <c1> <1/f> <f> <g>
fxch st1 ; <2p> <1-f> <c2> <b> <c1> <1/f> <f> <g>
fadd st0, st1 ; <2p+1-f> <1-f> <c2> <b> <c1> <1/f> <f> <g>
fmulp st1, st0 ; <(1-f)(2p+1-f)> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st1 ; <c2(1-f)(2p+1-f)> <c2> <b> <c1> <1/f> <f> <g>
fadd st0, st6 ; <g+c2(1-f)(2p+1-f)> <c2> <b> <c1> <1/f> <f> <g>
fchs ; <-g-c2(1-f)(2p+1-f)> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st4 ; <y> <c2> <b> <c1> <1/f> <f> <g>
jmp short .m0pl
.m0c12 ; y=(c2(p²)-c1((p-f)²))*(1/f)
fld st0 ; <p> <p> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st0 ; <p²> <p> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st2 ; <c2(p²)> <p> <c2> <b> <c1> <1/f> <f> <g>
fxch st1 ; <p> <c2(p²)> <c2> <b> <c1> <1/f> <f> <g>
fsub st0, st6 ; <p-f> <c2(p²)> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st0 ; <(p-f)²> <c2(p²)> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st4 ; <c1*(p-f)²> <c2(p²)> <c2> <b> <c1> <1/f> <f> <g>
fsubp st1, st0 ; <c2(p²)-c1*(p-f)²> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st4 ; <y> <c2> <b> <c1> <1/f> <f> <g>
jmp short .m0pl
.m0c1 ; y=c1(2p-f)
fadd st0, st0 ; <2p> <c2> <b> <c1> <1/f> <f> <g>
fsub st0, st5 ; <2p-f> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st3 ; <y> <c2> <b> <c1> <1/f> <f> <g>
jmp short .m0pl
.m0c2 ; y=c2(2p-f)
fadd st0, st0 ; <2p> <c2> <b> <c1> <1/f> <f> <g>
fsub st0, st5 ; <2p-f> <c2> <b> <c1> <1/f> <f> <g>
fmul st0, st1 ; <y> <c2> <b> <c1> <1/f> <f> <g>
.m0pl
fadd st0, st6 ; <out> <c2> <b> <c1> <1/f> <f> <g>
add eax, esi ; ...............................n c
rcl edx, 1 ; ..............................nc .
test byte [ebp + syWOsc.ring], 1
jz .m0noring
fmul dword [edi + 4*ecx] ; <out'> <c2> <b> <c1> <1/f> <f> <g>
jmp .m0store
.m0noring
fadd dword [edi + 4*ecx] ; <out'> <c2> <b> <c1> <1/f> <f> <g>
.m0store
fstp dword [edi + 4*ecx] ; <c2> <b> <c1> <1/f> <f> <g>
inc ecx
jz .m0end
jmp .m0loop
.m0end
mov [ebp + syWOsc.cnt], eax
fstp st0 ; <b> <c1> <1/f> <f> <g>
fstp st0 ; <c1> <1/f> <f> <g>
fstp st0 ; <1/f> <f> <g>
fstp st0 ; <f> <g>
fstp st0 ; <g>
fstp st0 ; -
.off
V2PerfLeave V2Perf_OSC
popad
ret
section .data
.m1casetab dd syOscRender.m1c2, ; ...
dd syOscRender.m1c1, ; ..n , INVALID!
dd syOscRender.m1c212, ; .c.
dd syOscRender.m1c21, ; .cn
dd syOscRender.m1c12, ; o..
dd syOscRender.m1c1, ; o.n
dd syOscRender.m1c2, ; oc. , INVALID!
dd syOscRender.m1c121 ; ocn
section .text
.mode1 ; pulse
mov eax, [ebp + syWOsc.cnt]
mov esi, [ebp + syWOsc.freq]
; calc float helper values
mov ebx, esi
shr ebx, 9
or ebx, 0x3f800000
mov [ebp + syWOsc.tmp], ebx
fld dword [ebp + syWOsc.gain] ; <g>
fld dword [ebp + syWOsc.tmp] ; <f+1> <g>
fld1 ; <1> <f+1> <g>
fsubp st1, st0 ; <f> <g>
fdivr st0, st1 ; <gdf> <g>
mov ebx, [ebp + syWOsc.brpt]
shr ebx, 9
or ebx, 0x3f800000
mov [ebp + syWOsc.tmp], ebx
fld dword [ebp + syWOsc.tmp] ; <b> <gdf> <g>
fld st0 ; <b> <b> <gdf> <g>
fadd st0, st0 ; <2b> <b> <gdf> <g>
fld st0 ; <2b> <2b> <b> <gdf> <g>
fld1 ; <1> <2b> <2b> <b> <gdf> <g>
fadd st0, st0 ; <2> <2b> <2b> <b> <gdf> <g>
fsub st1, st0 ; <2> <2b-2> <2b> <b> <gdf> <g>
fadd st0, st0 ; <4> <2b-2> <2b> <b> <gdf> <g>
fsubp st2, st0 ; <2b-2> <2b-4> <b> <gdf> <g>
fmul st0, st3 ; <gdf(2b-2)> <2b-4> <b> <gdf> <g>
fsub st0, st4 ; <cc212> <2b-4> <b> <gdf> <g>
fxch st1 ; <2b-4> <cc212> <b> <gdf> <g>
fmul st0, st3 ; <gdf(2b-4)> <cc212> <b> <gdf> <g>
fadd st0, st4 ; <cc121> <cc212> <b> <gdf> <g>
; calc state
mov ebx, eax
sub ebx, esi ; ................................ c
rcr edx, 1 ; c............................... .
cmp ebx, [ebp + syWOsc.brpt] ; c............................... n
rcl edx, 2 ; ..............................nc .
.m1loop
mov ebx, eax
shr ebx, 9
or ebx, 0x3f800000
mov [ebp + syWOsc.tmp], ebx
cmp eax, [ebp + syWOsc.brpt] ; ..............................oc n
rcl edx, 1 ; .............................ocn .
and edx, 7 ; 00000000000000000000000000000ocn
jmp dword [cs: .m1casetab + 4*edx]
; cases: on entry <cc121> <cc212> <b> <gdf> <g>, on exit: <out> <cc121> <cc212> <b> <gdf> <g>
.m1c21 ; p2->p1 : 2(p-1)/f - 1
fld dword [ebp + syWOsc.tmp] ; <p> <cc121> <cc212> <b> <gdf> <g>
fld1 ; <1> <p> <cc121> <cc212> <b> <gdf> <g>
fsubp st1, st0 ; <p-1> <cc121> <cc212> <b> <gdf> <g>
fadd st0, st0 ; <2(p-1)> <cc121> <cc212> <b> <gdf> <g>
fmul st0, st4 ; <gdf*2(p-1)> <cc121> <cc212> <b> <gdf> <g>
fsub st0, st5 ; <out> <cc121> <cc212> <b> <gdf> <g>
jmp short .m1pl
.m1c12 ; p1->p2 : 2(b-p)/f + 1
fld st2 ; <b> <cc121> <cc212> <b> <gdf> <g>
fsub dword [ebp + syWOsc.tmp] ; <b-p> <cc121> <cc212> <b> <gdf> <g>
fadd st0, st0 ; <2(b-p)> <cc121> <cc212> <b> <gdf> <g>
fmul st0, st4 ; <gdf*2(b-p)> <cc121> <cc212> <b> <gdf> <g>
fadd st0, st5 ; <out> <cc121> <cc212> <b> <gdf> <g>
jmp short .m1pl
.m1c121 ; p1->p2->p1 : (2b-4)/f + 1
fld st0 ; <out> <cc121> <cc212> <b> <gdf> <g>
jmp short .m1pl
.m1c212 ; p2->p1->p2 : (2b-2)/f - 1
fld st1 ; <out> <cc121> <cc212> <b> <gdf> <g>
jmp short .m1pl
.m1c1 ; p1 : 1
fld st4 ; <out> <cc121> <cc212> <b> <gdf> <g>
jmp short .m1pl
.m1c2 ; p2 : -1
fld st4 ; <out> <cc121> <cc212> <b> <gdf> <g>
fchs
.m1pl
add eax, esi ; ...............................n c
rcl edx, 1 ; ..............................nc .
test byte [ebp + syWOsc.ring], 1
jz .m1noring
fmul dword [edi + 4*ecx]
jmp short .m1store
.m1noring
fadd dword [edi + 4*ecx]
.m1store
fstp dword [edi + 4*ecx]
inc ecx
jnz .m1loop
mov [ebp + syWOsc.cnt], eax
fstp st0 ; <cc212> <b> <gdf> <g>
fstp st0 ; <b> <gdf> <g>
fstp st0 ; <gdf> <g>
fstp st0 ; <g>
fstp st0 ; -
V2PerfLeave V2Perf_OSC
popad
ret
.mode2 ; sin
mov eax, [ebp + syWOsc.cnt]
mov edx, [ebp + syWOsc.freq]
fld qword [fcsinx7] ; <cx7>
fld qword [fcsinx5] ; <cx5> <cx7>
fld qword [fcsinx3] ; <cx3> <cx5> <cx7>
.m2loop1
mov ebx, eax
add ebx, 0x40000000
mov esi, ebx
sar esi, 31
xor ebx, esi
shr ebx, 8
add eax, edx
or ebx, 0x3f800000
mov [ebp + syWOsc.tmp], ebx
fld dword [ebp + syWOsc.tmp] ; <x> <cx3> <cx5> <cx7>
; scale/move to (-pi/4 .. pi/4)
fmul dword [fcpi] ; <x'> <cx3> <cx5> <cx7>
fsub dword [fc1p5pi] ; <x''> <cx3> <cx5> <cx7>
; inline fastsin
fld st0 ; <x> <x> <cx3> <cx5> <cx7>
fmul st0, st1 ; <x²> <x> <cx3> <cx5> <cx7>
fld st4 ; <c> <x²> <x> <cx3> <cx5> <cx7>
fmul st0, st1 ; <cx²> <x²> <x> <cx3> <cx5> <cx7>
fadd st0, st4 ; <b+cx²> <x²> <x> <cx3> <cx5> <cx7>
fmul st0, st1 ; <x²(b+cx²)> <x²> <x> <cx3> <cx5> <cx7>
fadd st0, st3 ; <a+x²(b+cx²)> <x²> <x> <cx3> <cx5> <cx7>
fmulp st1, st0 ; <x²(a+x²(b+cx²)> <x> <cx3> <cx5> <cx7>
fld1 ; <1> <x²(a+x²(b+cx²)> <x> <cx3> <cx5> <cx7>
faddp st1, st0 ; <1+x²(a+x²(b+cx²)> <x> <cx3> <cx5> <cx7>
fmulp st1, st0 ; <x(1+x²(a+x²(b+cx²))> <cx3> <cx5> <cx7>
fmul dword [ebp + syWOsc.gain] ; <gain(y)> <cx3> <cx5> <cx7>
test byte [ebp + syWOsc.ring], 1
jz .m2noring
fmul dword [edi + 4*ecx] ; <out> <cx3> <cx5> <cx7>
jmp short .m2store
.m2noring
fadd dword [edi + 4*ecx] ; <out> <cx3> <cx5> <cx7>
.m2store
fstp dword [edi + 4*ecx] ; <cx3> <cx5> <cx7>
inc ecx
jnz .m2loop1
mov [ebp + syWOsc.cnt], eax
fstp st0 ; <cx5> <cx7>
fstp st0 ; <cx7>
fstp st0 ; -
V2PerfLeave V2Perf_OSC
popad
ret
.mode3 ; noise
mov esi, [ebp + syWOsc.nseed]
fld dword [ebp + syWOsc.nfres] ; <r>
fld dword [ebp + syWOsc.nffrq] ; <f> <r>
fld dword [ebp + syWOsc.nfl] ; <l> <f> <r>
fld dword [ebp + syWOsc.nfb] ; <b> <l> <f> <r>
.m3loop1
imul esi, icnoisemul
add esi, icnoiseadd
mov eax, esi
shr eax, 9
or eax, 40000000h
mov [ebp + syWOsc.tmp], eax
fld dword [ebp + syWOsc.tmp] ; <n> <b> <l> <f> <r>
fld1 ; <1> <n> <b> <l> <f> <r>
fsub st1, st0 ; <1> <n-1> <b> <l> <f> <r>
fsub st1, st0 ; <1> <n-2> <b> <l> <f> <r>
fsubp st1, st0 ; <n'> <b> <l> <f> <r>
fld st1 ; <b> <n'> <b> <l> <f> <r>
fmul st0, st4 ; <b*f> <n'> <b> <l> <f> <r>
fxch st1 ; <n'> <b*f> <b> <l> <f> <r>
fld st2 ; <b> <n'> <b*f> <b> <l> <f> <r>
fmul st0, st6 ; <b*r> <n'> <b*f> <b> <l> <f> <r>
fsubp st1, st0 ; <n-(b*r)> <b*f> <b> <l> <f> <r>
fxch st1 ; <b*f> <n-(b*r)> <b> <l> <f> <r>
faddp st3, st0 ; <n-(b*r)> <b> <l'> <f> <r>
fsub st0, st2 ; <h> <b> <l'> <f> <r>
fld st0 ; <h> <h> <b> <l'> <f> <r>
fmul st0, st4 ; <h*f> <h> <b> <l'> <f> <r>
faddp st2, st0 ; <h> <b'> <l'> <f> <r>
fld st2 ; <l'> <h> <b'> <l'> <f> <r>
faddp st1, st0 ; <l+h> <b'> <l'> <f> <r>
fmul st0, st4 ; <r(l+h)> <b'> <l'> <f> <r>
fadd st0, st1 ; <r(l+h)+b> <b'> <l'> <f> <r>
fmul dword [ebp + syWOsc.gain] ; <out> <b'> <l'> <f> <r>
test byte [ebp + syWOsc.ring], 1
jz .m3noring
fmul dword [edi + 4*ecx]
jmp .m3store
.m3noring
fadd dword [edi + 4*ecx]
.m3store
fstp dword [edi + 4*ecx]
inc ecx
jnz .m3loop1
fstp dword [ebp + syWOsc.nfb] ; <l> <f> <r>
fstp dword [ebp + syWOsc.nfl] ; <f> <r>
fstp st0 ; <r>
fstp st0 ; <->
mov [ebp + syWOsc.nseed], esi
V2PerfLeave V2Perf_OSC
popad
ret
.mode4 ; fm sin
mov eax, [ebp + syWOsc.cnt]
mov edx, [ebp + syWOsc.freq]
.m4loop1
mov ebx, eax
fld dword [edi + 4*ecx] ; -1 .. 1
fmul dword [fcfmmax]
shr ebx, 9
add eax, edx
or ebx, 0x3f800000
mov [ebp + syWOsc.tmp], ebx
fadd dword [ebp + syWOsc.tmp]
fmul dword [fc2pi]
call fastsinrc
fmul dword [ebp + syWOsc.gain]
test byte [ebp + syWOsc.ring], 1
jz .m4store
fmul dword [edi + 4*ecx]
.m4store
fstp dword [edi + 4*ecx]
inc ecx
jnz .m4loop1
mov [ebp + syWOsc.cnt], eax
V2PerfLeave V2Perf_OSC
popad
ret
; CHAOS
.auxa ; copy
mov esi,[this]
lea esi,[esi + SYN.auxabuf]
.auxaloop
fld dword [esi+0]
fadd dword [esi+4]
add esi,8
fmul dword [ebp + syWOsc.gain]
fmul dword [fcgain]
test byte [ebp + syWOsc.ring], 1
jz .auxastore
fmul dword [edi + 4*ecx]
.auxastore
fstp dword [edi + 4*ecx]
inc ecx
jnz .auxaloop
V2PerfLeave V2Perf_OSC
popad
ret
.auxb ; copy
mov esi,[this]
lea esi,[esi + SYN.auxbbuf]
jmp .auxaloop
;#####################################################################################
; Envelope Generator
;#####################################################################################
global _ENV_
_ENV_
struc syVEnv
.ar resd 1
.dr resd 1
.sl resd 1
.sr resd 1
.rr resd 1
.vol resd 1
.size
endstruc
struc syWEnv
.out resd 1
.state resd 1 ; int state - 0: off, 1: attack, 2: decay, 3: sustain, 4: release
.val resd 1 ; float outval (0.0-128.0)
.atd resd 1 ; float attack delta (added every frame in phase 1, transition -> 2 at 128.0)
.dcf resd 1 ; float decay factor (mul'ed every frame in phase 2, transision -> 3 at .sul)
.sul resd 1 ; float sustain level (defines phase 2->3 transition point)
.suf resd 1 ; float sustain factor (mul'ed every frame in phase 3, transition -> 4 at gate off or ->0 at 0.0)
.ref resd 1 ; float release (mul'ed every frame in phase 4, transition ->0 at 0.0)
.gain resd 1 ; float gain (0.1 .. 1.0)
.size
endstruc
; init
; ebp: workspace
syEnvInit:
pushad
xor eax, eax
mov [ebp + syWEnv.state], eax ; reset state to "off"
popad
ret
; set
; esi: values
; epb: workspace
syEnvSet:
pushad
; ar: 2^7 (128) bis 2^-4 (0.03, ca. 10secs bei 344frames/sec)
fld dword [esi + syVEnv.ar] ; 0..127
fmul dword [fcattackmul] ; 0..-12
fadd dword [fcattackadd] ; 7..-5
call pow2
fstp dword [ebp + syWEnv.atd]
; dcf: 0 (5msecs dank volramping) bis fast 1 (durchgehend)
fld dword [esi + syVEnv.dr] ; 0..127
fmul dword [fci128] ; 0..~1
fld1 ; 1 0..~1
fsubrp st1, st0 ; 1..~0
call calcfreq2
fld1
fsubrp st1, st0
fstp dword [ebp + syWEnv.dcf] ; 0..~1
; sul: 0..127 ist schon ok
fld dword [esi + syVEnv.sl] ; 0..127
fstp dword [ebp + syWEnv.sul] ; 0..127
; suf: 1/128 (15msecs bis weg) bis 128 (15msecs bis voll da)
fld dword [esi + syVEnv.sr] ; 0..127
fsub dword [fc64] ; -64 .. 63
fmul dword [fcsusmul] ; -7 .. ~7
call pow2
fstp dword [ebp + syWEnv.suf] ; 1/128 .. ~128
; ref: 0 (5msecs dank volramping) bis fast 1 (durchgehend)
fld dword [esi + syVEnv.rr] ; 0..127
fmul dword [fci128]
fld1
fsubrp st1, st0
call calcfreq2
fld1
fsubrp st1, st0
fstp dword [ebp + syWEnv.ref] ; 0..~1
fld dword [esi + syVEnv.vol]
fmul dword [fci128]
fstp dword [ebp + syWEnv.gain]
popad
ret
; tick
; epb: workspace
; ATTENTION: eax: gate
section .data
syETTab dd syEnvTick.state_off, syEnvTick.state_atk, syEnvTick.state_dec,
dd syEnvTick.state_sus, syEnvTick.state_rel
section .text
syEnvTick:
pushad
mov ebx, [ebp + syWEnv.state]
call [syETTab + 4*ebx]
fld dword [ebp + syWEnv.val]
fmul dword [ebp + syWEnv.gain]
fstp dword [ebp + syWEnv.out]
popad
ret
.state_off ; envelope off
or eax, eax ; gate on -> attack
jz .s0ok
inc byte [ebp + syWEnv.state]
jmp .state_atk
.s0ok
fldz
fstp dword [ebp + syWEnv.val]
ret
.state_atk ; attack
or eax, eax ; gate off -> release
jnz .s1ok
mov byte [ebp + syWEnv.state], 4
jmp .state_rel
.s1ok
fld dword [ebp + syWEnv.val]
fadd dword [ebp + syWEnv.atd]
fstp dword [ebp + syWEnv.val]
mov ecx, 43000000h ; 128.0
cmp ecx, [ebp + syWEnv.val]
ja .s1end ; val above -> decay
mov [ebp + syWEnv.val], ecx
inc byte [ebp + syWEnv.state]
.s1end
ret
.state_dec
or eax, eax ; gate off -> release
jnz .s2ok
mov byte [ebp + syWEnv.state], 4
jmp .state_rel
.s2ok
fld dword [ebp + syWEnv.val]
fmul dword [ebp + syWEnv.dcf]
fstp dword [ebp + syWEnv.val]
mov ecx, [ebp + syWEnv.sul] ; sustain level
cmp ecx, [ebp + syWEnv.val]
jb .s4checkrunout ; val below -> sustain
mov [ebp + syWEnv.val], ecx
inc byte [ebp + syWEnv.state]
ret
.state_sus
or eax, eax ; gate off -> release
jnz .s3ok
inc byte [ebp + syWEnv.state]
jmp .state_rel
.s3ok
fld dword [ebp + syWEnv.val]
fmul dword [ebp + syWEnv.suf]
fstp dword [ebp + syWEnv.val]
mov ecx, LOWEST
cmp ecx, [ebp + syWEnv.val]
jb .s3not2low ; val below -> off
xor ecx, ecx
mov [ebp + syWEnv.val], ecx
mov [ebp + syWEnv.state], ecx
ret
.s3not2low
mov ecx, 43000000h ; 128.0
cmp ecx, [ebp + syWEnv.val]
ja .s3end ; val above -> decay
mov [ebp + syWEnv.val], ecx
.s3end
ret
.state_rel
or eax, eax ; gate off -> release
jz .s4ok
mov byte [ebp + syWEnv.state], 1
jmp .state_atk
.s4ok
fld dword [ebp + syWEnv.val]
fmul dword [ebp + syWEnv.ref]
fstp dword [ebp + syWEnv.val]
.s4checkrunout
mov ecx, LOWEST
cmp ecx, [ebp + syWEnv.val]
jb .s4end
xor ecx, ecx
mov [ebp + syWEnv.val], ecx
mov [ebp + syWEnv.state], ecx
.s4end
ret
;#####################################################################################
; Filter
;#####################################################################################
global _VCF_
_VCF_
struc syVFlt
.mode resd 1
.cutoff resd 1
.reso resd 1
.size
endstruc
struc syWFlt
.mode resd 1 ; int: 0 - bypass, 1 - low, 2 - band, 3 - high, 4 - notch, 5 - all, 6 - moogl, 7 - moogh
.cfreq resd 1 ; float: frq (0-1)
.res resd 1 ; float: res (0-1)
.moogf resd 1 ; moog flt f coefficient (negative!)
.moogp resd 1 ; moog flt p coefficient
.moogq resd 1 ; moog flt q coefficient
.l resd 1
.b resd 1
.mb0 resd 1
.mb1 resd 1
.mb2 resd 1
.mb3 resd 1
.mb4 resd 1
.step resd 1
.size
endstruc
syFltInit:
pushad
xor eax, eax
lea edi, [ebp + syWFlt.l]
lea ecx, [eax + 7]
rep stosd
mov al, 4
mov [ebp + syWFlt.step], eax
popad
ret
syFltSet:
pushad
fld dword [esi + syVFlt.mode]
fistp dword [ebp + syWFlt.mode]
fld dword [esi + syVFlt.cutoff]
fmul dword [fci128]
call calcfreq ; <f>
fmul dword [SRfclinfreq]
cmp byte [ebp + syWFlt.mode], 6
jge .moogflt
fld dword [esi + syVFlt.reso] ; <r> <f>
fmul dword [fci128]
fld1 ; <1> <r> <f>
fsubrp st1, st0 ; <1-res> <f>
fstp dword [ebp + syWFlt.res] ; <f>
fstp dword [ebp + syWFlt.cfreq] ; -
popad
ret
.moogflt
;t = 1.0f - frequency;
;p = frequency + 0.8f * frequency * t;
;f = p + p - 1.0f;
;q = resonance * (1.0f + 0.5f * t * (1.0f - t + 5.6f * t * t));
fmul dword [fci2] ; <0.5f>
fmul dword [fci2] ; <0.5f>
fld1 ; <1> <f>
fsub st0, st1 ; <t> <f>
fld st0 ; <t> <t> <f>
fmul st0, st2 ; <f(t)> <t> <f>
fmul dword [fc0p8] ; <0.8f(t)> <t> <f>
faddp st2, st0 ; <t> <p>
fxch st1 ; <p> <t>
fst dword [ebp + syWFlt.moogp]
fadd st0, st0 ; <2p> <t>
fld1 ; <1> <2p> <t>
fsubp st1, st0 ; <f> <t>
fchs ; <-f> <t>
fstp dword [ebp + syWFlt.moogf] ; <t>
fld st0 ; <t> <t>
fmul st0, st0 ; <t²> <t>
fmul dword [fc5p6] ; <5.6t²> <t>
fld1 ; <1> <5.6t²> <t>
fsub st0, st2 ; <1-t> <5.6t²> <t>
faddp st1, st0 ; <1-t+5.6t²> <t>
fmulp st1, st0 ; <t(1-t+5.6t²)>
fmul dword [fci2] ; <0.5t(1-t+5.6t²)>
fld1
faddp st1, st0 ; <1+0.5t(1-t+5.6t²)>
fld dword [esi + syVFlt.reso] ; <r> <1+0.5t(1-t+5.6t²)>
fmul dword [fci128] ; <r'> <1+0.5t(1-t+5.6t²)>
fmulp st1, st0 ; <q>
fadd st0, st0
fadd st0, st0
fstp dword [ebp + syWFlt.moogq] ; -
popad
ret
section .data
syFRTab dd syFltRender.mode0, syFltRender.mode1, syFltRender.mode2
dd syFltRender.mode3, syFltRender.mode4, syFltRender.mode5
dd syFltRender.modemlo, syFltRender.modemhi
section .text
; ebp: workspace
; ecx: count
; esi: source
; edi: dest
global syFltRender
syFltRender:
pushad
V2PerfEnter V2Perf_VCF
movzx eax, byte [ebp + syWFlt.mode]
and al, 7
cmp al, 6
jge .moogflt
fld dword [ebp + syWFlt.res] ; <r>
fld dword [ebp + syWFlt.cfreq]; <f> <r>
fld dword [ebp + syWFlt.l] ; <l> <f> <r>
fld dword [ebp + syWFlt.b] ; <b> <l> <f> <r>
call [syFRTab + 4*eax]
fstp dword [ebp + syWFlt.b] ; <l''> <f> <r>
fstp dword [ebp + syWFlt.l] ; <f> <r>
fstp st0
fstp st0
V2PerfLeave V2Perf_VCF
popad
ret
.moogflt
fld dword [ebp + syWFlt.mb4] ; <b4>
fld dword [ebp + syWFlt.mb3] ; <b3> <b4>
fld dword [ebp + syWFlt.mb2] ; <b2> <b3> <b4>
fld dword [ebp + syWFlt.mb1] ; <b1> <b2> <b3> <b4>
fld dword [ebp + syWFlt.mb0] ; <b0> <b1> <b2> <b3> <b4>
call [syFRTab + 4*eax]
fstp dword [ebp + syWFlt.mb0] ; <b1> <b2> <b3> <b4>
fstp dword [ebp + syWFlt.mb1] ; <b2> <b3> <b4>
fstp dword [ebp + syWFlt.mb2] ; <b3> <b4>
fstp dword [ebp + syWFlt.mb3] ; <b4>
fstp dword [ebp + syWFlt.mb4] ; -
V2PerfLeave V2Perf_VCF
popad
ret
.process: ; <b> <l> <f> <r>
fld dword [esi] ; <in> <b> <l> <f> <r>
%if FIXDENORMALS
fadd dword [fcdcoffset]
%endif
fld st1 ; <b> <in> <b> <l> <f> <r>
fld st2 ; <b> <b> <in> <b> <l> <f> <r>
fmul st0, st5 ; <b*f> <b> <in> <b> <l> <f> <r>
fxch st1 ; <b> <b*f> <in> <b> <l> <f> <r>
fmul st0, st6 ; <b*r> <b*f> <in> <b> <l> <f> <r>
fxch st1 ; <b*f> <b*r> <in> <b> <l> <f> <r>
add esi, [ebp + syWFlt.step]
fsub dword [fcdcoffset]
faddp st4, st0 ; <b*r> <in> <b> <l'> <f> <r>
fsubr st0, st1 ; <in-b*r> <in> <b> <l'> <f> <r>
fsub st0, st3 ; <h> <in> <b> <l'> <f> <r>
fmul st0, st4 ; <f*h> <in> <b> <l'> <f> <r>
faddp st2, st0 ; <in> <b'> <l'> <f> <r>
fld st1 ; <b'> <in> <b'> <l'> <f> <r>
fld st2 ; <b'> <b'> <in> <b'> <l'> <f> <r>
fmul st0, st5 ; <b'*f> <b'> <in> <b'> <l'> <f> <r>
fxch st1 ; <b'> <b'*f> <in> <b'> <l'> <f> <r>
fmul st0, st6 ; <b'*r> <b'*f> <in> <b'> <l'> <f> <r>
fxch st1 ; <b'*f> <b'*r> <in> <b'> <l'> <f> <r>
faddp st4, st0 ; <b'*r> <in> <b'> <l''> <f> <r>
fsubp st1, st0 ; <in-b'*r> <b'> <l''> <f> <r>
fsub st0, st2 ; <h> <b'> <l''> <f> <r>
fld st0 ; <h> <h> <b'> <l''> <f> <r>
fmul st0, st4 ; <h*f> <h> <b'> <l''> <f> <r>
faddp st2, st0 ; <h> <b''> <l''> <f> <r>
ret
.mode0: ; bypass
cmp esi, edi
je .m0end
rep movsd
.m0end
ret
.mode1: ; low
call .process ; <h> <b''> <l''> <f> <r>
fstp st0 ; <b''> <l''> <f> <r>
fxch st1 ; <l''> <b''> <f> <r>
fst dword [edi] ; -> l'' stored
fxch st1 ; <b''> <l''> <f> <r>
add edi, [ebp + syWFlt.step]
dec ecx
jnz .mode1
ret
.mode2: ; band
call .process ; <h> <b''> <l''> <f> <r>
fstp st0 ; <b''> <l''> <f> <r>
fst dword [edi] ; -> b'' stored
add edi, [ebp + syWFlt.step]
dec ecx
jnz .mode2
ret
.mode3: ; high
call .process ; <h> <b''> <l''> <f> <r>
fstp dword [edi] ; <b''> <l''> <f> <r> -> h stored
add edi, [ebp + syWFlt.step]
dec ecx
jnz .mode3
ret
.mode4: ; notch
call .process ; <h> <b''> <l''> <f> <r>
fadd st2 ; <h+l> <b''> <l''> <f> <r>
fstp dword [edi] ; <b''> <l''> <f> <r> -> h+l'' stored
add edi, [ebp + syWFlt.step]
dec ecx
jnz .mode4
ret
.mode5: ; allpass
call .process ; <h> <b''> <l''> <f> <r>
fadd st1 ; <h+b> <b''> <l''> <f> <r>
fadd st2 ; <h+b+l> <b''> <l''> <f> <r>
fstp dword [edi] ; <b''> <l''> <f> <r> -> h+b''+l'' stored
add edi, [ebp + syWFlt.step]
dec ecx
jnz .mode5
ret
; in -= q * b4; //feedback
; t1 = b1; b1 = (in + b0) * p - b1 * f;
; t2 = b2; b2 = (b1 + t1) * p - b2 * f;
; t3 = b3; b3 = (b2 + t2) * p - b3 * f;
; b4 = (b3 + t3) * p - b4 * f;
; b4 = b4 - b4 * b4 * b4 * 0.166667f; //clipping
; b0 = in;
.processmoog ; moog lowpass <b0> <b1> <b2> <b3> <b4>
fld dword [esi] ; <in> <b0> <b1> <b2> <b3> <b4>
fadd dword [fcdcoffset]
fld st5 ; <b4> <in> <b0> <b1> <b2> <b3> <b4>
fmul dword [ebp + syWFlt.moogq] ; <q*b4> <in> <b0> <b1> <b2> <b3> <b4>
fsubp st1, st0 ; <in'> <b0> <b1> <b2> <b3> <b4>
fld st2 ; <b1> <in'> <b0> <t1:=b1> <b2> <b3> <b4>
fmul dword [ebp + syWFlt.moogf] ; <-f*b1> <in'> <b0> <t1> <b2> <b3> <b4>
fxch st2 ; <b0> <in'> <-f*b1> <t1> <b2> <b3> <b4>
faddp st1, st0 ; <in'+b0> <-f*b1> <t1> <b2> <b3> <b4>
fmul dword [ebp + syWFlt.moogp] ; <p(in'+b0)> <-f*b1> <t1> <b2> <b3> <b4>
faddp st1, st0 ; <b1> <t1> <b2> <b3> <b4>
fld st2 ; <b2> <b1> <t1> <t2:=b2> <b3> <b4>
fmul dword [ebp + syWFlt.moogf] ; <-f*b2> <b1> <t1> <t2> <b3> <b4>
fxch st2 ; <t1> <b1> <-f*b2> <t2> <b3> <b4>
fadd st0, st1 ; <t1+b1> <b1> <-f*b2> <t2> <b3> <b4>
fmul dword [ebp + syWFlt.moogp] ; <p(t1+b1)> <b1> <-f*b2> <t2> <b3> <b4>
faddp st2, st0 ; <b1> <b2> <t2> <b3> <b4>
fld st3 ; <b3> <b1> <b2> <t2> <t3:=b3> <b4>
fmul dword [ebp + syWFlt.moogf] ; <-f*b3> <b1> <b2> <t2> <t3> <b4>
fxch st3 ; <t2> <b1> <b2> <-f*b3> <t3> <b4>
fadd st0, st2 ; <t2+b2> <b1> <b2> <-f*b3> <t3> <b4>
fmul dword [ebp + syWFlt.moogp] ; <p(t2+b2)> <b1> <b2> <-f*b3> <t3> <b4>
faddp st3, st0 ; <b1> <b2> <b3> <t3> <b4>
fxch st4 ; <b4> <b2> <b3> <t3> <b1>
fmul dword [ebp + syWFlt.moogf] ; <-f*b4> <b2> <b3> <t3> <b1>
fxch st3 ; <t3> <b2> <b3> <-f*b4> <b1>
fadd st0, st2 ; <t3+b3> <b2> <b3> <-f*b4> <b1>
fmul dword [ebp + syWFlt.moogp] ; <p(t3+b3)> <b2> <b3> <-f*b4> <b1>
faddp st3, st0 ; <b2> <b3> <b4> <b1>
fxch st2 ; <b4> <b3> <b2> <b1>
fld st0 ; <b4> <b4> <b3> <b2> <b1>
fmul st0, st0 ; <b4²> <b4> <b3> <b2> <b1>
fmul st0, st1 ; <b4³> <b4> <b3> <b2> <b1>
fmul dword [fci6] ; <b4³/6> <b4> <b3> <b2> <b1>
fsubp st1, st0 ; <b4'> <b3> <b2> <b1>
fsub dword [fcdcoffset]
; todo: improve this
fxch st1 ; <b3> <b4> <b2> <b1>
fxch st2 ; <b2> <b4> <b3> <b1>
fxch st1 ; <b4> <b2> <b3> <b1>
fxch st3 ; <b1> <b2> <b3> <b4>
fld dword [esi] ; <b0:=in> <b1> <b2> <b3> <b4>
fld st4 ; <out:=b4> <b1> <b2> <b3> <b4>
ret
.modemlo:
call .processmoog
fstp st0
call .processmoog
fstp dword [edi]
add esi, [ebp + syWFlt.step]
add edi, [ebp + syWFlt.step]
dec ecx
jnz .modemlo
ret
.modemhi:
call .processmoog
fstp st0
call .processmoog
fsubr dword [esi]
fstp dword [edi]
add esi, [ebp + syWFlt.step]
add edi, [ebp + syWFlt.step]
dec ecx
jnz .modemhi
ret
;#####################################################################################
; Low Frequency Oscillator
;#####################################################################################
global _LFO_
_LFO_
struc syVLFO
.mode resd 1 ; 0: saw, 1: tri, 2: pulse, 3: sin, 4: s&h
.sync resd 1 ; 0: free 1: in sync with keyon
.egmode resd 1 ; 0: continuous 1: one-shot (EG mode)
.rate resd 1 ; rate (0Hz .. ~43hz)
.phase resd 1 ; start phase shift
.pol resd 1 ; polarity: + , . , +/-
.amp resd 1 ; amplification (0 .. 1)
.size
endstruc
struc syWLFO
.out resd 1 ; float: out
.mode resd 1 ; int: mode
.fs resd 1 ; int: sync flag
.feg resd 1 ; int: eg flag
.freq resd 1 ; int: freq
.cntr resd 1 ; int: counter
.cph resd 1 ; int: counter sync phase
.gain resd 1 ; float: output gain
.dc resd 1 ; float: output DC
.nseed resd 1 ; int: random seed
.last resd 1 ; int: last counter value (for s&h transition)
.size
endstruc
syLFOInit
pushad
xor eax, eax
mov [ebp + syWLFO.cntr], eax
mov [ebp + syWLFO.last], eax
rdtsc
mov [ebp + syWLFO.nseed], eax
popad
ret
syLFOSet
pushad
fld dword [esi + syVLFO.mode]
fistp dword [ebp + syWLFO.mode]
fld dword [esi + syVLFO.sync]
fistp dword [ebp + syWLFO.fs]
fld dword [esi + syVLFO.egmode]
fistp dword [ebp + syWLFO.feg]
fld dword [esi + syVLFO.rate]
fmul dword [fci128]
call calcfreq
fmul dword [fc32bit]
fmul dword [fci2]
fistp dword [ebp + syWLFO.freq]
fld dword [esi + syVLFO.phase]
fmul dword [fci128]
fmul dword [fc32bit]
fistp dword [ebp + syWLFO.cph]
shl dword [ebp + syWLFO.cph],1
fld dword [esi + syVLFO.amp]
fld dword [esi + syVLFO.pol]
fistp dword [temp]
mov eax, [temp]
fld st0
fchs
fmul dword [fci2]
cmp al, 2 ; +/- polarity?
jz .isp2
fsub st0, st0
.isp2
fstp dword [ebp + syWLFO.dc]
cmp al, 1 ; +/- polarity?
jnz .isntp1
fchs
.isntp1
fstp dword [ebp + syWLFO.gain]
popad
ret
syLFOKeyOn
pushad
mov eax, [ebp + syWLFO.fs]
or eax, eax
jz .end
mov eax, [ebp + syWLFO.cph]
mov [ebp + syWLFO.cntr], eax
xor eax, eax
not eax
mov [ebp + syWLFO.last], eax
.end
popad
ret
section .data
syLTTab dd syLFOTick.mode0, syLFOTick.mode1, syLFOTick.mode2, syLFOTick.mode3
dd syLFOTick.mode4, syLFOTick.mode0, syLFOTick.mode0, syLFOTick.mode0
section .text
syLFOTick
pushad
mov eax, [ebp + syWLFO.cntr]
mov edx, [ebp + syWLFO.mode]
and dl, 7
call [syLTTab + 4*edx]
fmul dword [ebp + syWLFO.gain]
fadd dword [ebp + syWLFO.dc]
fstp dword [ebp + syWLFO.out]
mov eax, [ebp + syWLFO.cntr]
add eax, [ebp + syWLFO.freq]
jnc .isok
mov edx, [ebp + syWLFO.feg]
or edx, edx
jz .isok
xor eax, eax
not eax
.isok
mov [ebp + syWLFO.cntr], eax
popad
ret
.mode0 ; saw
shr eax, 9
or eax, 3f800000h
mov [temp], eax
fld dword [temp] ; <1..2>
fld1 ; <1> <1..2>
fsubp st1, st0 ; <0..1>
ret
.mode1 ; tri
shl eax, 1
sbb ebx, ebx
xor eax, ebx
jmp .mode0
.mode2 ; pulse
shl eax, 1
sbb eax, eax
jmp .mode0
.mode3 ; sin
call .mode0
fmul dword [fc2pi] ; <0..2pi>
call fastsinrc ; <-1..1>
fmul dword [fci2] ; <-0.5..0.5>
fadd dword [fci2] ; <0..1>
ret
.mode4 ; s&h
cmp eax, [ebp + syWLFO.last]
mov [ebp + syWLFO.last], eax
jae .nonew
mov eax, [ebp + syWLFO.nseed]
imul eax, icnoisemul
add eax, icnoiseadd
mov [ebp + syWLFO.nseed], eax
.nonew
mov eax, [ebp + syWLFO.nseed]
jmp .mode0
;#####################################################################################
; INDUSTRIALGELÖT UND UNKAPUTTBARE ORGELN
; Das Verzerr- und Verüb-Modul!
;#####################################################################################
; mode1: overdrive ... input gain, output gain, offset
; mode2: clip... input gain, output gain, offset
; mode3: bitcrusher... input gain, crush, xor
; mode4: decimator... -, resamplingfreq, -
; mode5..9: filters -, cutoff, reso
global _DIST_
_DIST_
struc syVDist
.mode resd 1 ; 0: off, 1: overdrive, 2: clip, 3: bitcrusher, 4: decimator
; modes 4 to 8: filters (see syVFlt)
.ingain resd 1 ; -12dB ... 36dB
.param1 resd 1 ; outgain/crush/outfreq
.param2 resd 1 ; offset/offset/xor/jitter
.size
endstruc
struc syWDist
.mode resd 1
.gain1 resd 1 ; float: input gain for all fx
.gain2 resd 1 ; float: output gain for od/clip
.offs resd 1 ; float: offs for od/clip
.crush1 resd 1 ; float: crush factor^-1
.crush2 resd 1 ; int: crush factor^1
.crxor resd 1 ; int: xor value for crush
.dcount resd 1 ; int: decimator counter
.dfreq resd 1 ; int: decimator frequency
.dvall resd 1 ; float: last decimator value (mono/left)
.dvalr resd 1 ; float: last decimator value (right)
.dlp1c resd 1 ; float: decimator pre-filter coefficient
.dlp1bl resd 1 ; float: decimator pre-filter buffer (mono/left)
.dlp1br resd 1 ; float: decimator pre-filter buffer (right)
.dlp2c resd 1 ; float: decimator post-filter coefficient
.dlp2bl resd 1 ; float: decimator post-filter buffer (mono/left)
.dlp2br resd 1 ; float: decimator post-filter buffer (right)
.fw1 resb syWFlt.size ; left/mono filter workspace
.fw2 resb syWFlt.size ; right filter workspace
.size
endstruc
syDistInit:
pushad
xor eax, eax
mov [ebp + syWDist.dcount], eax
mov [ebp + syWDist.dvall], eax
mov [ebp + syWDist.dvalr], eax
mov [ebp + syWDist.dlp1bl], eax
mov [ebp + syWDist.dlp1br], eax
mov [ebp + syWDist.dlp2bl], eax
mov [ebp + syWDist.dlp2br], eax
lea ebp, [ebp + syWDist.fw1]
call syFltInit
lea ebp, [ebp + syWDist.fw2 - syWDist.fw1]
call syFltInit
popad
ret
section .data
syDSTab dd syDistSet.mode0, syDistSet.mode1, syDistSet.mode2, syDistSet.mode3, syDistSet.mode4
dd syDistSet.modeF, syDistSet.modeF, syDistSet.modeF, syDistSet.modeF, syDistSet.modeF
dd syDistSet.modeF, syDistSet.modeF, syDistSet.mode0, syDistSet.mode0, syDistSet.mode0
dd syDistSet.mode0
section .text
syDistSet:
pushad
fld dword [esi + syVDist.mode]
fistp dword [ebp + syWDist.mode]
fld dword [esi + syVDist.ingain]
fsub dword [fc32]
fmul dword [fci16]
call pow2
fstp dword [ebp + syWDist.gain1]
fld dword [esi + syVDist.param1]
mov eax, [ebp + syWDist.mode]
and al, 15
call [syDSTab + 4*eax]
popad
ret
.mode0
fstp st0
ret
.mode1 ; overdrive
fmul dword [fci128]
fld dword [ebp + syWDist.gain1]
fld1
fpatan
fdivp st1, st0
jmp .mode2b
.mode2 ; clip
fmul dword [fci128]
.mode2b
fstp dword [ebp + syWDist.gain2]
fld dword [esi + syVDist.param2]
fsub dword [fc64]
fmul dword [fci128]
fadd st0, st0
fmul dword [ebp + syWDist.gain1]
fstp dword [ebp + syWDist.offs]
ret
.mode3 ; bitcrusher
fmul dword [fc256] ; 0 .. 32xxx
fld1
faddp st1, st0 ; 1 .. 32xxx
fld dword [fc32768] ; 32768 x
fxch st1 ; x 32768
fdiv st1, st0 ; x 32768/x
fistp dword [ebp + syWDist.crush2]
fmul dword [ebp + syWDist.gain1]
fstp dword [ebp + syWDist.crush1]
fld dword [esi + syVDist.param2]
fistp dword [temp]
mov eax, [temp]
shl eax, 9
mov [ebp + syWDist.crxor], eax
ret
.mode4 ; decimator
fmul dword [fci128]
call calcfreq
fmul dword [fc32bit]
fistp dword [ebp + syWDist.dfreq]
shl dword [ebp + syWDist.dfreq], 1
fld dword [esi + syVDist.ingain]
fmul dword [fci127]
fmul st0, st0
fstp dword [ebp + syWDist.dlp1c]
fld dword [esi + syVDist.param2]
fmul dword [fci127]
fmul st0, st0
fstp dword [ebp + syWDist.dlp2c]
ret
.modeF ; filters
fstp dword [temp + syVFlt.cutoff]
fld dword [esi + syVDist.param2]
fstp dword [temp + syVFlt.reso]
mov eax, [ebp + syWDist.mode]
lea eax, [eax-4]
mov [temp + syVFlt.mode], eax
fild dword [temp + syVFlt.mode]
fstp dword [temp + syVFlt.mode]
lea esi, [temp]
lea ebp, [ebp + syWDist.fw1]
call syFltSet
lea ebp, [ebp + syWDist.fw2 - syWDist.fw1]
jmp syFltSet
section .data
syDRMTab dd syDistRenderMono.mode0, syDistRenderMono.mode1, syDistRenderMono.mode2, syDistRenderMono.mode3
dd syDistRenderMono.mode4, syDistRenderMono.modeF, syDistRenderMono.modeF, syDistRenderMono.modeF
dd syDistRenderMono.modeF, syDistRenderMono.modeF, syDistRenderMono.modeF, syDistRenderMono.modeF
dd syDistRenderMono.mode0, syDistRenderMono.mode0, syDistRenderMono.mode0, syDistRenderMono.mode0
section .text
; esi : sourceptr
; edi : destptr
; ecx : size
syDistRenderMono:
pushad
V2PerfEnter V2Perf_DIST
mov edx, [ebp + syWDist.mode]
call [syDRMTab + 4*edx]
V2PerfLeave V2Perf_DIST
popad
ret
.mode0 ; bypass
cmp esi, edi
je .m0end
rep movsd
.m0end
ret
.mode1 ; overdrive
fld1 ; <1>
fchs ; <-1>
xor ebx, ebx
mov bl, 8
.m1loop
fld dword [esi]
lea esi, [esi+4]
fmul dword [ebp + syWDist.gain1]
fadd dword [ebp + syWDist.offs]
fst dword [temp]
mov ax, [temp+2]
call fastatan
fmul dword [ebp + syWDist.gain2]
fstp dword [edi]
lea edi, [edi+4]
dec ecx
jnz .m1loop
fstp st0 ; -
ret
.mode2 ; clip
fld dword [esi]
lea esi, [esi+4]
fmul dword [ebp + syWDist.gain1]
fadd dword [ebp + syWDist.offs]
fld1
fcomi st0, st1
fxch st1
fcmovb st0, st1
fxch st1
fchs
fcomi st0, st1
fcmovb st0, st1
fxch st1
fstp st0
fmul dword [ebp + syWDist.gain2]
fstp dword [edi]
lea edi, [edi+4]
dec ecx
jnz .mode2
ret
.mode3 ; bitcrusher
mov ebx, 7fffh
mov edx, -7fffh
.m3loop
fld dword [esi]
lea esi, [esi+4]
fmul dword [ebp + syWDist.crush1]
fistp dword [temp]
mov eax, [temp]
imul eax, [ebp + syWDist.crush2]
cmp ebx, eax
cmovle eax, ebx
cmp edx, eax
cmovge eax, edx
xor eax, [ebp + syWDist.crxor]
mov [temp], eax
fild dword [temp]
fmul dword [fci32768]
fstp dword [edi]
lea edi, [edi+4]
dec ecx
jnz .m3loop
ret
.mode4 ; decimator
mov eax, [ebp + syWDist.dvall]
mov edx, [ebp + syWDist.dfreq]
mov ebx, [ebp + syWDist.dcount]
.m4loop
add ebx, edx
cmovc eax, [esi]
add esi, byte 4
stosd
dec ecx
jnz .m4loop
mov [ebp + syWDist.dcount], ebx
mov [ebp + syWDist.dvall], eax
ret
.modeF ; filters
lea ebp, [ebp + syWDist.fw1]
jmp syFltRender
section .data
syDRSTab dd syDistRenderMono.mode0, syDistRenderMono.mode1, syDistRenderMono.mode2, syDistRenderMono.mode3
dd syDistRenderStereo.mode4, syDistRenderStereo.modeF, syDistRenderStereo.modeF, syDistRenderStereo.modeF
dd syDistRenderStereo.modeF, syDistRenderStereo.modeF, syDistRenderMono.mode0, syDistRenderMono.mode0
dd syDistRenderMono.mode0, syDistRenderMono.mode0, syDistRenderMono.mode0, syDistRenderMono.mode0
section .text
syDistRenderStereo:
pushad
V2PerfEnter V2Perf_DIST
shl ecx, 1
mov edx, [ebp + syWDist.mode]
call [syDRSTab + 4*edx]
V2PerfLeave V2Perf_DIST
popad
ret
.mode4 ; decimator
shr ecx, 1
mov eax, [ebp + syWDist.dvall]
mov edx, [ebp + syWDist.dvalr]
mov ebx, [ebp + syWDist.dcount]
.m4loop
add ebx, [ebp + syWDist.dfreq]
cmovc eax, [esi]
cmovc edx, [esi + 4]
add esi, byte 8
stosd
xchg eax, edx
stosd
xchg eax, edx
dec ecx
jnz .m4loop
mov [ebp + syWDist.dcount], ebx
mov [ebp + syWDist.dvall], eax
mov [ebp + syWDist.dvalr], edx
ret
.modeF ; filters
shr ecx, 1
xor eax, eax
mov al, 8
mov [ebp + syWDist.fw1 + syWFlt.step], eax
mov [ebp + syWDist.fw2 + syWFlt.step], eax
lea ebp, [ebp + syWDist.fw1]
call syFltRender
lea ebp, [ebp + syWDist.fw2 - syWDist.fw1]
lea esi, [esi + 4]
lea edi, [edi + 4]
jmp syFltRender
;#####################################################################################
; DC filter
;#####################################################################################
global _DCFILTER_
_DCFILTER_
struc syWDCF
.xm1l resd 1
.ym1l resd 1
.xm1r resd 1
.ym1r resd 1
.size
endstruc
; ebp: workspace
syDCFInit:
pushad
xor eax, eax
mov edi, ebp
mov ecx, syWDCF.size/4
rep stosd
popad
ret
; ebp: workspace
; esi: source
; edi: dest
; ecx: count
; y(n) = x(n) - x(n-1) + R * y(n-1)
syDCFRenderMono:
pushad
fld dword [fcdcoffset]
fld dword [SRfcdcfilter] ; <R> <dc>
fld dword [ebp + syWDCF.xm1l] ; <xm1> <R> <dc>
fld dword [ebp + syWDCF.ym1l] ; <ym1> <xm1> <R> <dc>
.floop:
fmul st0, st2 ; <R*ym1> <xm1> <R> <dc>
fsubrp st1, st0 ; <R*ym1-xm1> <R> <dc>
fld dword [esi] ; <x> <R*ym1-xm1> <R> <dc>
lea esi, [esi+4]
fxch st1 ; <R*ym1-xm1> <x> <R> <dc>
fadd st0, st1 ; <y> <x> <R> <dc>
fadd st0, st3 ; <y+dc> <x> <R> <dc>
fsub st0, st3 ; <y>
fst dword [edi]
lea edi, [edi+4]
dec ecx
jnz .floop
fstp dword [ebp + syWDCF.ym1l] ; <xm1> <R> <dc>
fstp dword [ebp + syWDCF.xm1l] ; <R> <dc>
fstp st0 ; <dc>
fstp st0 ; -
popad
ret
; ebp: workspace
; esi: source
; edi: dest
; ecx: count
; y(n) = x(n) - x(n-1) + R * y(n-1)
global syDCFRenderStereo
syDCFRenderStereo:
pushad
fld dword [fcdcoffset] ; <dc>
fld dword [SRfcdcfilter] ; <R> <dc>
fld dword [ebp + syWDCF.xm1r] ; <xm1r> <R> <dc>
fld dword [ebp + syWDCF.xm1l] ; <xm1l> <xm1r> <R> <dc>
fld dword [ebp + syWDCF.ym1r] ; <ym1r> <xm1l> <xm1r> <R> <dc>
fld dword [ebp + syWDCF.ym1l] ; <ym1l> <ym1r> <xm1l> <xm1r> <R> <dc>
.floop:
fmul st0, st4 ; <R*ym1l> <ym1r> <xm1l> <xm1r> <R> <dc>
fsubrp st2, st0 ; <ym1r> <R*ym1l-xm1l> <xm1r> <R> <dc>
fmul st0, st3 ; <R*ym1r> <R*ym1l-xm1l> <xm1r> <R> <dc>
fsubrp st2, st0 ; <R*ym1l-xm1l> <R*ym1r-xm1r> <R> <dc>
fld dword [esi] ; <xl> <R*ym1l-xm1l> <R*ym1r-xm1r> <R> <dc>
fxch st1 ; <R*ym1l-xm1l> <xl> <R*ym1r-xm1r> <R> <dc>
fadd st0, st1 ; <yl> <xl> <R*ym1r-xm1r> <R> <dc>
fadd st0, st4 ; <yl+dc> <xl> <R*ym1r-xm1r> <R> <dc>
fsub st0, st4 ; <yl> <xl> <R*ym1r-xm1r> <R> <dc>
fst dword [edi]
fld dword [esi+4] ; <xr> <yl> <xl> <R*ym1r-xm1r> <R> <dc>
fxch st3 ; <R*ym1r-xm1r> <yl> <xl> <xr> <R> <dc>
fadd st0, st3 ; <yr> <yl> <xl> <xr> <R> <dc>
fadd st0, st5 ; <yr+dc> <yl> <xl> <xr> <R> <dc>
fsub st0, st5 ; <yr> <yl> <xl> <xr> <R> <dc>
fst dword [edi+4]
fxch st1 ; <yl> <yr> <xl> <xr> <R> <dc>
lea esi, [esi+8]
lea edi, [edi+8]
dec ecx
jnz .floop
fstp dword [ebp + syWDCF.ym1l] ; <ym1r> <xm1l> <xm1r> <R> <dc>
fstp dword [ebp + syWDCF.ym1r] ; <xm1l> <xm1r> <R> <dc>
fstp dword [ebp + syWDCF.xm1l] ; <xm1r> <R> <dc>
fstp dword [ebp + syWDCF.xm1r] ; <R> <dc>
fstp st0 ; <dc>
fstp st0 ; -
popad
ret
;#####################################################################################
; V2 - Voice
;#####################################################################################
global _V2V_
_V2V_
struc syVV2
.panning resd 1 ; panning
.transp resd 1 ; transpose
.osc1 resb syVOsc.size ; oszi 1
.osc2 resb syVOsc.size ; oszi 2
.osc3 resb syVOsc.size ; oszi 3
.vcf1 resb syVFlt.size ; filter 1
.vcf2 resb syVFlt.size ; filter 2
.routing resd 1 ; 0: single 1: serial 2: parallel
.fltbal resd 1 ; parallel filter balance
.dist resb syVDist.size ; distorter
.aenv resb syVEnv.size ; amplitude env
.env2 resb syVEnv.size ; EG 2
.lfo1 resb syVLFO.size ; LFO 1
.lfo2 resb syVLFO.size ; LFO 2
.oscsync resd 1 ; osc keysync flag
.size
endstruc
struc syWV2
.note resd 1
.velo resd 1
.gate resd 1
.curvol resd 1
.volramp resd 1
.xpose resd 1
.fmode resd 1
.lvol resd 1
.rvol resd 1
.f1gain resd 1
.f2gain resd 1
.oks resd 1
.osc1 resb syWOsc.size
.osc2 resb syWOsc.size
.osc3 resb syWOsc.size
.vcf1 resb syWFlt.size ; filter 1
.vcf2 resb syWFlt.size ; filter 2
.aenv resb syWEnv.size
.env2 resb syWEnv.size
.lfo1 resb syWLFO.size ; LFO 1
.lfo2 resb syWLFO.size ; LFO 2
.dist resb syWDist.size ; distorter
.dcf resb syWDCF.size ; post dc filter
.size
endstruc
; ebp: workspace
syV2Init:
pushad
lea ebp, [ebp + syWV2.osc1 - 0]
call syOscInit
lea ebp, [ebp + syWV2.osc2 - syWV2.osc1]
call syOscInit
lea ebp, [ebp + syWV2.osc3 - syWV2.osc2]
call syOscInit
lea ebp, [ebp + syWV2.aenv - syWV2.osc3]
call syEnvInit
lea ebp, [ebp + syWV2.env2 - syWV2.aenv]
call syEnvInit
lea ebp, [ebp + syWV2.vcf1 - syWV2.env2]
call syFltInit
lea ebp, [ebp + syWV2.vcf2 - syWV2.vcf1]
call syFltInit
lea ebp, [ebp + syWV2.lfo1 - syWV2.vcf2]
call syLFOInit
lea ebp, [ebp + syWV2.lfo2 - syWV2.lfo1]
call syLFOInit
lea ebp, [ebp + syWV2.dist - syWV2.lfo2]
call syDistInit
lea ebp, [ebp + syWV2.dcf - syWV2.dist]
call syDCFInit
popad
ret
; tick
; ebp: workspace
syV2Tick:
pushad
; 1. EGs
mov eax, [ebp + syWV2.gate]
lea ebp, [ebp + syWV2.aenv - 0]
call syEnvTick
lea ebp, [ebp + syWV2.env2 - syWV2.aenv]
call syEnvTick
; 2. LFOs
lea ebp, [ebp + syWV2.lfo1 - syWV2.env2]
call syLFOTick
lea ebp, [ebp + syWV2.lfo2 - syWV2.lfo1]
call syLFOTick
lea ebp, [ebp + 0 - syWV2.lfo2]
; 3. Volume Ramping
fld dword [ebp + syWV2.aenv + syWEnv.out]
fmul dword [fci128]
fsub dword [ebp + syWV2.curvol]
fmul dword [SRfciframe]
fstp dword [ebp + syWV2.volramp]
popad
ret
; render
; edi: dest buf
; ecx: # of samples
; ebp: workspace
syV2Render:
pushad
mov ebx, [this]
add ebx, SYN.vcebuf
; clear buffer
push ecx
mov edi, ebx
xor eax, eax
rep stosd
pop ecx
mov edi, ebx
lea ebp, [ebp - 0 + syWV2.osc1]
call syOscRender
lea ebp, [ebp - syWV2.osc1 + syWV2.osc2]
call syOscRender
lea ebp, [ebp - syWV2.osc2 + syWV2.osc3]
call syOscRender
lea ebp, [ebp - syWV2.osc3 + 0]
; Filter + Routing
; wenn parallel -> erst filter 2 in buf2 rendern
mov edx, [ebp + syWV2.fmode]
cmp dl, 2 ; parallel?
jne .nopar1
lea ebp, [ebp - 0 + syWV2.vcf2]
mov esi, ebx
lea edi, [ebx + SYN.vcebuf2-SYN.vcebuf]
call syFltRender
lea ebp, [ebp - syWV2.vcf2 + 0]
.nopar1
; dann auf jeden fall filter 1 rendern
lea ebp, [ebp - 0 + syWV2.vcf1]
mov esi, ebx
mov edi, ebx
call syFltRender
lea ebp, [ebp - syWV2.vcf1 + 0]
; dann fallunterscheidung...
or dl, dl ; single?
jz .fltend
cmp dl, 2 ; parallel?
jnz .nopar2
push ecx ; ja -> buf2 auf buf adden
lea esi, [ebx + SYN.vcebuf2-SYN.vcebuf]
mov edi, ebx
fld dword [ebp + syWV2.f1gain] ; <g1>
fld dword [ebp + syWV2.f2gain] ; <g2> <g1>
.parloop
fld dword [esi] ; <v2> <g2> <g1>
fmul st0, st1 ; <v2'> <g2> <g1>
add esi, byte 4
fld dword [edi] ; <v1> <v2'> <g2> <g1>
fmul st0, st3 ; <v1'> <v2'> <g2> <g1>
faddp st1, st0 ; <out> <g2> <g1>
fstp dword [edi] ; <g2> <g1>
add edi, byte 4
dec ecx
jnz .parloop
fstp st0 ; <g1>
fstp st0 ; -
pop ecx
jmp .fltend
.nopar2
; ... also seriell ... filter 2 drüberrechnen
lea ebp, [ebp - 0 + syWV2.vcf2]
mov esi, ebx
mov edi, ebx
call syFltRender
lea ebp, [ebp - syWV2.vcf2 + 0]
.fltend
; distortion
mov esi, ebx
mov edi, ebx
lea ebp, [ebp - 0 + syWV2.dist]
call syDistRenderMono
; dc filter
lea ebp, [ebp + syWV2.dcf - syWV2.dist]
call syDCFRenderMono
lea ebp, [ebp - syWV2.dcf + 0]
; vcebuf (mono) nach chanbuf(stereo) kopieren
lea edi, [ebx + SYN.chanbuf-SYN.vcebuf]
mov esi, ebx
fld dword [ebp + syWV2.curvol] ; cv
.copyloop1
fld dword [esi] ; out cv
fmul st1 ; out' cv
fxch st1 ; cv out'
fadd dword [ebp + syWV2.volramp] ; cv' out'
fxch st1 ; out' cv'
fld st0 ; out out cv
fmul dword [ebp + syWV2.lvol] ; outl out cv
fxch st1 ; out outl cv
fmul dword [ebp + syWV2.rvol] ; outr outl cv
fxch st1 ; outl outr cv
%ifdef FIXDENORMALS
fadd dword [fcdcoffset]
fxch st1
fadd dword [fcdcoffset]
fxch st1
%endif
fadd dword [edi] ; l outr cv
fxch st1 ; outr l cv
fadd dword [edi+4] ; r l cv
fxch st1 ; l r cv
fstp dword [edi] ; r cv
fstp dword [edi+4] ; cv
add esi, 4
add edi, 8
dec ecx
jnz .copyloop1
fstp dword [ebp + syWV2.curvol] ; -
popad
ret
; set
; esi: values
; ebp: workspace
syV2Set:
pushad
fld dword [esi + syVV2.transp]
fsub dword [fc64]
fst dword [ebp + syWV2.xpose]
fiadd dword [ebp + syWV2.note]
fst dword [ebp + syWV2.osc1 + syWOsc.note]
fst dword [ebp + syWV2.osc2 + syWOsc.note]
fstp dword [ebp + syWV2.osc3 + syWOsc.note]
fld dword [esi + syVV2.routing]
fistp dword [ebp + syWV2.fmode]
fld dword [esi + syVV2.oscsync]
fistp dword [ebp + syWV2.oks]
; ... denn EQP - Panning rult.
fld dword [esi + syVV2.panning] ; <p>
fmul dword [fci128] ; <p'>
fld st0 ; <p'> <p'>
fld1 ; <1> <p'> <p'>
fsubrp st1, st0 ; <1-p'> <p'>
fsqrt ; <lv> <p'>
fstp dword [ebp + syWV2.lvol] ; <p'>
fsqrt ; <rv>
fstp dword [ebp + syWV2.rvol]
; filter balance für parallel
fld dword [esi + syVV2.fltbal]
fsub dword [fc64]
fist dword [temp]
mov eax, [temp]
fmul dword [fci64] ; <x>
or eax, eax
js .fbmin
fld1 ; <1> <x>
fsubr st1, st0 ; <1> <1-x>
jmp short .fbgoon
.fbmin
fld1 ; <1> <x>
fadd st1, st0 ; <g1> <g2>
fxch st1 ; <g2> <g1>
.fbgoon
fstp dword [ebp + syWV2.f2gain] ; <g1>
fstp dword [ebp + syWV2.f1gain] ; -
lea ebp, [ebp + syWV2.osc1 - 0]
lea esi, [esi + syVV2.osc1 - 0]
call syOscSet
lea ebp, [ebp + syWV2.osc2 - syWV2.osc1]
lea esi, [esi + syVV2.osc2 - syVV2.osc1]
call syOscSet
lea ebp, [ebp + syWV2.osc3 - syWV2.osc2]
lea esi, [esi + syVV2.osc3 - syVV2.osc2]
call syOscSet
lea ebp, [ebp + syWV2.aenv - syWV2.osc3]
lea esi, [esi + syVV2.aenv - syVV2.osc3]
call syEnvSet
lea ebp, [ebp + syWV2.env2 - syWV2.aenv]
lea esi, [esi + syVV2.env2 - syVV2.aenv]
call syEnvSet
lea ebp, [ebp + syWV2.vcf1 - syWV2.env2]
lea esi, [esi + syVV2.vcf1 - syVV2.env2]
call syFltSet
lea ebp, [ebp + syWV2.vcf2 - syWV2.vcf1]
lea esi, [esi + syVV2.vcf2 - syVV2.vcf1]
call syFltSet
lea ebp, [ebp + syWV2.lfo1 - syWV2.vcf2]
lea esi, [esi + syVV2.lfo1 - syVV2.vcf2]
call syLFOSet
lea ebp, [ebp + syWV2.lfo2 - syWV2.lfo1]
lea esi, [esi + syVV2.lfo2 - syVV2.lfo1]
call syLFOSet
lea ebp, [ebp + syWV2.dist - syWV2.lfo2]
lea esi, [esi + syVV2.dist - syVV2.lfo2]
call syDistSet
popad
ret
; note on
; eax: note
; ebx: vel
; ebp: workspace
syV2NoteOn:
pushad
mov [ebp + syWV2.note], eax
fild dword [ebp + syWV2.note]
fadd dword [ebp + syWV2.xpose]
fst dword [ebp + syWV2.osc1 + syWOsc.note]
fst dword [ebp + syWV2.osc2 + syWOsc.note]
fstp dword [ebp + syWV2.osc3 + syWOsc.note]
mov [temp], ebx
fild dword [temp]
fstp dword [ebp + syWV2.velo]
xor eax, eax
inc eax
mov [ebp + syWV2.gate], eax
; reset EGs
mov [ebp + syWV2.aenv + syWEnv.state], eax
mov [ebp + syWV2.env2 + syWEnv.state], eax
mov eax, [ebp + syWV2.oks]
or eax, eax
jz .nosync
xor eax, eax
mov [ebp + syWV2.osc1 + syWOsc.cnt], eax
mov [ebp + syWV2.osc2 + syWOsc.cnt], eax
mov [ebp + syWV2.osc3 + syWOsc.cnt], eax
.nosync
;fldz
; fst dword [ebp + syWV2.curvol]
;fstp dword [ebp + syWV2.volramp]
lea ebp, [ebp + syWV2.osc1 - 0]
call syOscChgPitch
lea ebp, [ebp + syWV2.osc2 - syWV2.osc1]
call syOscChgPitch
lea ebp, [ebp + syWV2.osc3 - syWV2.osc2]
call syOscChgPitch
lea ebp, [ebp + syWV2.lfo1 - syWV2.osc3]
call syLFOKeyOn
lea ebp, [ebp + syWV2.lfo2 - syWV2.lfo1]
call syLFOKeyOn
lea ebp, [ebp + syWV2.dcf - syWV2.lfo2]
call syDCFInit
popad
ret
; note off
; ebp: workspace
syV2NoteOff:
pushad
xor eax, eax
mov [ebp + syWV2.gate], eax
popad
ret
section .data
; table for mod sources
sVTab dd syWV2.aenv + syWEnv.out
dd syWV2.env2 + syWEnv.out
dd syWV2.lfo1 + syWLFO.out
dd syWV2.lfo2 + syWLFO.out
section .text
storeV2Values: ; ebp: pointer auf globals / edx: voice
pushad
mov ebx, [ebp + SYN.chanmap + 4*edx] ; ebx = channel
or ebx, ebx
jns .doit
jmp .end ; voice gar ned belegt?
.doit
movzx eax, byte [ebp + SYN.chans + 8*ebx] ; pgmnummer
mov edi, [ebp + SYN.patchmap]
mov edi, [edi + 4*eax] ; edi -> sounddaten
add edi, [ebp + SYN.patchmap]
mov eax, edx
imul eax, syVV2.size
lea esi, [ebp + SYN.voicesv + eax] ; esi -> values
mov eax, edx
imul eax, syWV2.size
lea ebx, [ebp + SYN.voicesw + eax] ; ebx -> workspace
; voicedependent daten übertragen
xor ecx, ecx
.goloop
movzx eax, byte [edi + ecx]
mov [temp], eax
fild dword [temp]
fstp dword [esi + 4*ecx]
inc ecx
cmp cl, v2sound.endvdvals
jne .goloop
; MODMATRIX!
movzx ecx, byte [edi + v2sound.modnum]
lea edi, [edi + v2sound.modmatrix]
or ecx, ecx
jnz .modloop
jmp .modend
.modloop
movzx eax, byte [edi + v2mod.source] ; source
or eax, eax
jnz .mnotvel
fld dword [ebx + syWV2.velo]
jmp .mdo
.mnotvel
cmp al, 8
jae .mnotctl
push ebx
mov ebx, [ebp + SYN.chanmap + 4*edx]
lea ebx, [8*ebx + eax]
movzx eax, byte [ebp + SYN.chans + ebx]
pop ebx
mov [temp], eax
fild dword [temp]
jmp .mdo
.mnotctl
cmp al, 12
jae .mnotvm
and al, 3
mov eax, [sVTab + 4*eax]
fld dword [ebx + eax]
jmp .mdo
.mnotvm
cmp al, 13
jne .mnotnote
.mnotnote
fild dword [ebx + syWV2.note]
fsub dword [fc48]
fadd st0, st0
jmp .mdo
.mdo
movzx eax, byte [edi + v2mod.val]
mov [temp], eax
fild dword [temp]
fsub dword [fc64]
fmul dword [fci128]
fadd st0, st0
fmulp st1, st0
movzx eax, byte [edi + v2mod.dest]
cmp eax, v2sound.endvdvals
jb .misok
fstp st0
jmp .mlend
.misok
fadd dword [esi + 4*eax]
fstp dword [temp]
; clippen
push edx
mov edx, [temp]
or edx, edx
jns .mnoclip1
xor edx, edx
.mnoclip1
cmp edx, 43000000h
jbe .mnoclip2
mov edx, 43000000h
.mnoclip2
mov [esi + 4*eax], edx
pop edx
.mlend
lea edi, [edi+3]
dec ecx
jz .modend
jmp .modloop
.modend
mov ebp, ebx
call syV2Set
.end
popad
ret
;#####################################################################################
; Bass, Bass, wir brauchen Bass
; BASS BOOST (fixed low shelving EQ)
;#####################################################################################
global _BASS_
_BASS_
struc syVBoost
.amount resd 1 ; boost in dB (0..18)
.size
endstruc
struc syWBoost
.ena resd 1
.a1 resd 1
.a2 resd 1
.b0 resd 1
.b1 resd 1
.b2 resd 1
.x1 resd 2
.x2 resd 2
.y1 resd 2
.y2 resd 2
.size
endstruc
syBoostInit:
pushad
popad
ret
; fixed frequency: 150Hz -> omega is 0,0213713785958489335949839685937381
syBoostSet:
pushad
fld dword [esi + syVBoost.amount]
fist dword [temp]
mov eax, [temp]
mov [ebp + syWBoost.ena], eax
or eax, eax
jnz .isena
fstp st0
popad
ret
.isena
; A = 10^(dBgain/40) bzw ne stark gefakete version davon
fmul dword [fci128]
call pow2 ; <A>
; beta = sqrt[ (A^2 + 1)/S - (A-1)^2 ] (for shelving EQ filters only)
fld st0 ; <A> <A>
fmul st0, st0 ; <A²> <A>
fld1 ; <1> <A²> <A>
faddp st1, st0 ; <A²+1> <A>
fld st1 ; <A> <A²+1> <A>
fld1 ; <1> <A> <A²+1> <A>
fsubp st1, st0 ; <A-1> <A²+1> <A>
fmul st0, st0 ; <(A-1)²> <A²+1> <A>
fsubp st1, st0 ; <beta²> <A>
fsqrt ; <beta> <A>
; zwischenvars: beta*sin, A+1, A-1, A+1*cos, A-1*cos
fmul dword [SRfcBoostSin] ; <bs> <A>
fld1 ; <1> <bs> <A>
fld st2 ; <A> <1> <bs> <A>
fld st0 ; <A> <A> <1> <bs> <A>
fsub st0, st2 ; <A-> <A> <1> <bs> <A>
fxch st1 ; <A> <A-> <1> <bs> <A>
faddp st2, st0 ; <A-> <A+> <bs> <A>
fxch st1 ; <A+> <A-> <bs> <A>
fld st0 ; <A+> <A+> <A-> <bs> <A>
fmul dword [SRfcBoostCos] ; <cA+> <A+> <A-> <bs> <A>
fld st2 ; <A-> <cA+> <A+> <A-> <bs> <A>
fmul dword [SRfcBoostCos] ; <cA-> <cA+> <A+> <A-> <bs> <A>
; a0 = (A+1) + (A-1)*cos + beta*sin
fld st4 ; <bs> <cA-> <cA+> <A+> <A-> <bs> <A>
fadd st0, st1 ; <bs+cA-> <cA-> <cA+> <A+> <A-> <bs> <A>
fadd st0, st3 ; <a0> <cA-> <cA+> <A+> <A-> <bs> <A>
; zwischenvar: 1/a0
fld1 ; <1> <a0> <cA-> <cA+> <A+> <A-> <bs> <A>
fdivrp st1, st0 ; <ia0> <cA-> <cA+> <A+> <A-> <bs> <A>
; b1 = 2*A*[ (A-1) - (A+1)*cos
fld st4 ; <A-> <ia0> <cA-> <cA+> <A+> <A-> <bs> <A>
fsub st0, st3 ; <A- - cA+> <ia0> <cA-> <cA+> <A+> <A-> <bs> <A>
fadd st0, st0 ; <2(A- - cA+)> <ia0> <cA-> <cA+> <A+> <A-> <bs> <A>
fmul st0, st7 ; <b1> <ia0> <cA-> <cA+> <A+> <A-> <bs> <A>
fmul st0, st1 ; <b1'> <ia0> <cA-> <cA+> <A+> <A-> <bs> <A>
fstp dword [ebp + syWBoost.b1] ; <ia0> <cA-> <cA+> <A+> <A-> <bs> <A>
; a1 = -2*[ (A-1) + (A+1)*cos
fxch st4 ; <A-> <cA-> <cA+> <A+> <ia0> <bs> <A>
faddp st2, st0 ; <cA-> <cA+ + A-> <A+> <ia0> <bs> <A>
fxch st1 ; <cA+ + A-> <cA-> <A+> <ia0> <bs> <A>
fadd st0, st0 ; <2*(cA+ + A-)> <cA-> <A+> <ia0> <bs> <A>
fchs ; <a1> <cA-> <A+> <ia0> <bs> <A>
fmul st0, st3 ; <a1'> <cA-> <A+> <ia0> <bs> <A>
fstp dword [ebp + syWBoost.a1] ; <cA-> <A+> <ia0> <bs> <A>
; a2 = (A+1) + (A-1)*cos - beta*sin
fld st0 ; <cA-> <cA-> <A+> <ia0> <bs> <A>
fadd st0, st2 ; <A+ + cA-> <cA-> <A+> <ia0> <bs> <A>
fsub st0, st4 ; <a2> <cA-> <A+> <ia0> <bs> <A>
fmul st0, st3 ; <a2'> <cA-> <A+> <ia0> <bs> <A>
fstp dword [ebp + syWBoost.a2] ; <cA-> <A+> <ia0> <bs> <A>
; b0 = A*[ (A+1) - (A-1)*cos + beta*sin ]
fsubp st1, st0 ; <A+ - cA-> <ia0> <bs> <A>
fxch st1 ; <ia0> <A+ - cA-> <bs> <A>
fmulp st3, st0 ; <A+ - cA-> <bs> <A*ia0>
fld st0 ; <A+ - cA-> <A+ - cA-> <bs> <A*ia0>
fadd st0, st2 ; <A+ - ca- + bs> <A+ - cA-> <bs> <A*ia0>
fmul st0, st3 ; <b0'> <A+ - cA-> <bs> <A*ia0>
fstp dword [ebp + syWBoost.b0] ; <A+ - cA-> <bs> <A*ia0>
; b2 = A*[ (A+1) - (A-1)*cos - beta*sin ]
fsubrp st1, st0 ; <A+ - cA- - bs> <A*ia0>
fmulp st1, st0 ; <b2'>
fstp dword [ebp + syWBoost.b2] ; -
popad
ret
; esi: src/dest buffer
; ecx: # of samples
; y[n] = (b0/a0)*x[n] + (b1/a0)*x[n-1] + (b2/a0)*x[n-2] - (a1/a0)*y[n-1] - (a2/a0)*y[n-2]
syBoostProcChan: ; <y2> <x2> <y1> <x2>
pushad
.doloop
; y0 = b0'*in + b1'*x1 + b2'*x2 + a1'*y1 + a2'*y2
fmul dword [ebp + syWBoost.a2] ; <y2a2> <x2> <y1> <x1>
fxch st1 ; <x2> <y2a2> <y1> <x1>
fmul dword [ebp + syWBoost.b2] ; <x2b2> <y2a2> <y1> <x1>
fld st3 ; <x1> <x2b2> <y2a2> <y1> <x1>
fmul dword [ebp + syWBoost.b1] ; <x1b1> <x2b2> <y2a2> <y1> <x1>
fld st3 ; <y1> <x1b1> <x2b2> <y2a2> <y1> <x1>
fmul dword [ebp + syWBoost.a1] ; <y1a1> <x1b1> <x2b2> <y2a2> <y1> <x1>
fxch st3 ; <y2a2> <x1b1> <x2b2> <y1a1> <y1> <x1>
fsubp st2, st0 ; <x1b1> <x2b2-y2a2> <y1a1> <y1> <x1>
fsubrp st2, st0 ; <x2b2-y2a2> <x1b1-y1a1> <y1> <x1>
fld dword [esi] ; <x0> <x2b2-y2a2> <x1b1-y1a1> <y1> <x1>
%if FIXDENORMALS
fadd dword [fcdcoffset]
%endif
fxch st4 ; <x1> <x2b2-y2a2> <x1b1-y1a1> <y1> <x0>
fld st4 ; <x0> <x1> <x2b2-y2a2> <x1b1-y1a1> <y1> <x0>
fmul dword [ebp + syWBoost.b0] ; <b0x0> <x1> <x2b2-y2a2> <x1b1-y1a1> <y1> <x0>
fxch st2 ; <x2b2-y2a2> <x1> <b0x0> <x1b1-y1a1> <y1> <x0>
faddp st3, st0 ; <x1> <b0x0> <x1b1-y1a1+x2b2-y2a2> <y1> <x0>
fxch st2 ; <x1b1-y1a1+x2b2-y2a2> <b0x0> <x1> <y1> <x0>
faddp st1, st0 ; <y0> <x1> <y1> <x0>
fst dword [esi]
fxch st2 ; <y1> <x1> <y0> <x0>
lea esi, [esi+8] ; ... = <y2'> <x2'> <y1'> <x1'>
dec ecx
jnz .doloop
popad
ret
syBoostRender:
pushad
V2PerfEnter V2Perf_BASS
test byte [ebp + syWBoost.ena], 255
jz .nooo
; left channel
fld dword [ebp + syWBoost.x1] ; <x1>
fld dword [ebp + syWBoost.y1] ; <y1> <x1>
fld dword [ebp + syWBoost.x2] ; <x2> <y1> <x1>
fld dword [ebp + syWBoost.y2] ; <y2> <x2> <y1> <x1>
call syBoostProcChan
fstp dword [ebp + syWBoost.y2] ; <x2'> <y1> <x1>
fstp dword [ebp + syWBoost.x2] ; <y1> <x1>
fstp dword [ebp + syWBoost.y1] ; <x1>
fstp dword [ebp + syWBoost.x1] ; -
lea esi, [esi+4]
; right channel
fld dword [ebp + syWBoost.x1 + 4] ; <x1>
fld dword [ebp + syWBoost.y1 + 4] ; <y1> <x1>
fld dword [ebp + syWBoost.x2 + 4] ; <x2> <y1> <x1>
fld dword [ebp + syWBoost.y2 + 4] ; <y2> <x2> <y1> <x1>
call syBoostProcChan
fstp dword [ebp + syWBoost.y2 + 4] ; <x2'> <y1> <x1>
fstp dword [ebp + syWBoost.x2 + 4] ; <y1> <x1>
fstp dword [ebp + syWBoost.y1 + 4] ; <x1>
fstp dword [ebp + syWBoost.x1 + 4] ; -
.nooo
V2PerfLeave V2Perf_BASS
popad
ret
;#####################################################################################
; Böse Dinge, die man mit Jan Delay anstellen kann:
; MODULATING DELAYTEIL
; (für chorus, flanger, aber auch als "großes" stereo delay. Mit Liebe verpackt, ganz für sie.)
;#####################################################################################
global _MODDEL_
_MODDEL_
struc syVModDel
.amount resd 1 ; dry/eff value (0=-eff, 64=dry, 127=eff)
.fb resd 1 ; feedback (0=-100%, 64=0%, 127=~+100%)
.llength resd 1 ; length of left delay
.rlength resd 1 ; length of right delay
.mrate resd 1 ; modulation rate
.mdepth resd 1 ; modulation depth
.mphase resd 1 ; modulation stereo phase (0=-180°, 64=0°, 127=180°)
.size
endstruc
struc syWModDel
.db1 resd 1 ; ptr: delay buffer 1
.db2 resd 1 ; ptr: delay buffer 2
.dbufmask resd 1 ; int: delay buffer mask
.dbptr resd 1 ; int: buffer write pos
.db1offs resd 1 ; int: buffer 1 offset
.db2offs resd 1 ; int: buffer 2 offset
.mcnt resd 1 ; mod counter
.mfreq resd 1 ; mod freq
.mphase resd 1 ; mod phase
.mmaxoffs resd 1 ; mod max offs (2048samples*depth)
.fbval resd 1 ; float: feedback val
.dryout resd 1 ; float: dry out
.effout resd 1 ; float: eff out
.size
endstruc
syModDelInit
pushad
xor eax, eax
mov [ebp + syWModDel.dbptr],eax
mov [ebp + syWModDel.mcnt],eax
mov esi, [ebp + syWModDel.db1]
mov edi, [ebp + syWModDel.db2]
mov ecx, [ebp + syWModDel.dbufmask]
.clloop
stosd
mov [esi+4*ecx],eax
dec ecx
jns .clloop
popad
ret
syModDelSet
pushad
fld dword [esi + syVModDel.amount]
fsub dword [fc64]
fmul dword [fci128]
fadd st0, st0
fst dword [ebp + syWModDel.effout]
fabs
fld1
fsubrp st1, st0
fstp dword [ebp + syWModDel.dryout]
fld dword [esi + syVModDel.fb]
fsub dword [fc64]
fmul dword [fci128]
fadd st0, st0
fstp dword [ebp + syWModDel.fbval]
fild dword [ebp + syWModDel.dbufmask]
fsub dword [fc1023]
fmul dword [fci128]
fld dword [esi + syVModDel.llength]
fmul st0, st1
fistp dword [ebp + syWModDel.db1offs]
fld dword [esi + syVModDel.rlength]
fmulp st1, st0
fistp dword [ebp + syWModDel.db2offs]
fld dword [esi + syVModDel.mrate]
fmul dword [fci128]
call calcfreq
fmul dword [fcmdlfomul]
fmul dword [SRfclinfreq]
fistp dword [ebp + syWModDel.mfreq]
fld dword [esi + syVModDel.mdepth]
fmul dword [fci128]
fmul dword [fc1023]
fistp dword [ebp + syWModDel.mmaxoffs]
fld dword [esi + syVModDel.mphase]
fsub dword [fc64]
fmul dword [fci128]
fmul dword [fc32bit]
fistp dword [ebp + syWModDel.mphase]
shl dword [ebp + syWModDel.mphase], 1
popad
ret
syModDelProcessSample
; fpu: <r> <l> <eff> <dry> <fb>
; edx: buffer index
push edx
; step 1: rechtes dingens holen
mov eax, [ebp + syWModDel.mcnt]
add eax, [ebp + syWModDel.mphase]
shl eax, 1
sbb ebx, ebx
xor eax, ebx
mov ebx, [ebp + syWModDel.mmaxoffs]
mul ebx
add edx, [ebp + syWModDel.db2offs]
mov ebx, [esp]
sub ebx, edx
dec ebx
and ebx, [ebp + syWModDel.dbufmask]
shr eax, 9
or eax, 3f800000h
mov [temp], eax
fld dword [temp] ; <1..2> <r> <l> <eff> <dry> <fb>
fsubr dword [fc2] ; <x> <r> <l> <eff> <dry> <fb>
mov eax, [ebp + syWModDel.db2]
fld dword [eax + 4*ebx] ; <in1> <x> <r> <l> <eff> <dry> <fb>
inc ebx
and ebx, [ebp + syWModDel.dbufmask]
fld dword [eax + 4*ebx] ; <in2> <in1> <x> <r> <l> <eff> <dry> <fb>
fsub st0, st1 ; <in2-in1> <in1> <x> <r> <l> <eff> <dry> <fb>
mov ebx, [esp]
fmulp st2, st0 ; <in1> <x*(in2-in1)> <r> <l> <eff> <dry> <fb>
faddp st1, st0 ; <in> <r> <l> <eff> <dry> <fb>
fld st1 ; <r> <in> <r> <l> <eff> <dry> <fb>
fmul st0, st5 ; <r*dry> <in> <r> <l> <eff> <dry> <fb>
fld st1 ; <in> <r*dry> <in> <r> <l> <eff> <dry> <fb>
fmul st0, st5 ; <in*eff> <r*dry> <in> <r> <l> <eff> <dry> <fb>
fxch st2 ; <in> <in*eff> <r*dry> <r> <l> <eff> <dry> <fb>
fmul st0, st7 ; <in*fb> <in*eff> <r*dry> <r> <l> <eff> <dry> <fb>
fxch st1 ; <in*eff> <in*fb> <r*dry> <r> <l> <eff> <dry> <fb>
faddp st2, st0 ; <in*fb> <r'> <r> <l> <eff> <dry> <fb>
faddp st2, st0 ; <r'> <rb> <l> <eff> <dry> <fb>
fxch st1 ; <rb> <r'> <l> <eff> <dry> <fb>
fstp dword [eax+4*ebx] ; <r'> <l> <eff> <dry> <fb>
fxch st1 ; <l> <r'> <eff> <dry> <fb>
; step 2: linkes dingens holen
mov eax, [ebp + syWModDel.mcnt]
shl eax, 1
sbb ebx, ebx
xor eax, ebx
mov ebx, [ebp + syWModDel.mmaxoffs]
mul ebx
add edx, [ebp + syWModDel.db1offs]
mov ebx, [esp]
sub ebx, edx
and ebx, [ebp + syWModDel.dbufmask]
shr eax, 9
or eax, 3f800000h
mov [temp], eax
fld dword [temp] ; <1..2> <l> <r'> <eff> <dry> <fb>
fsubr dword [fc2] ; <x> <l> <r'> <eff> <dry> <fb>
mov eax, [ebp + syWModDel.db1]
fld dword [eax + 4*ebx] ; <in1> <x> <l> <r'> <eff> <dry> <fb>
inc ebx
and ebx, [ebp + syWModDel.dbufmask]
fld dword [eax + 4*ebx] ; <in2> <in1> <x> <l> <r'> <eff> <dry> <fb>
fsub st0, st1 ; <in2-in1> <in1> <x> <l> <r'> <eff> <dry> <fb>
mov ebx, [esp]
fmulp st2, st0 ; <in1> <x*(in2-in1)> <l> <r'> <eff> <dry> <fb>
faddp st1, st0 ; <in> <l> <r'> <eff> <dry> <fb>
fld st1 ; <l> <in> <l> <r'> <eff> <dry> <fb>
fmul st0, st5 ; <l*dry> <in> <l> <r'> <eff> <dry> <fb>
fld st1 ; <in> <l*dry> <in> <l> <r'> <eff> <dry> <fb>
fmul st0, st5 ; <in*eff> <l*dry> <in> <l> <r'> <eff> <dry> <fb>
fxch st2 ; <in> <in*eff> <l*dry> <l> <r'> <eff> <dry> <fb>
fmul st0, st7 ; <in*fb> <in*eff> <l*dry> <l> <r'> <eff> <dry> <fb>
fxch st1 ; <in*eff> <in*fb> <l*dry> <l> <r'> <eff> <dry> <fb>
faddp st2, st0 ; <in*fb> <l'> <l> <r'> <eff> <dry> <fb>
faddp st2, st0 ; <l'> <lb> <r'> <eff> <dry> <fb>
fxch st1 ; <lb> <l'> <r'> <eff> <dry> <fb>
fstp dword [eax+4*ebx] ; <l'> <r'> <eff> <dry> <fb>
pop edx
mov eax, [ebp + syWModDel.mfreq]
add [ebp + syWModDel.mcnt], eax
inc edx
and edx, [ebp + syWModDel.dbufmask]
ret
syModDelRenderAux2Main
pushad
V2PerfEnter V2Perf_MODDEL
mov eax, [ebp + syWModDel.effout]
or eax, eax
jz .dont
fld dword [ebp + syWModDel.fbval] ; <fb>
fldz ; <"dry"=0> <fb>
fld dword [ebp + syWModDel.effout] ; <eff> <dry> <fb>
mov edx, [ebp + syWModDel.dbptr]
mov esi, [this]
add esi, SYN.aux2buf
.rloop
fld dword [esi] ; <m> <eff> <dry> <fb>
%if FIXDENORMALS
fadd dword [fcdcoffset]
%endif
fld st0 ; <m> <m> <eff> <dry> <fb>
lea esi, [esi+4]
call syModDelProcessSample ; <l'> <r'> <eff> <dry> <fb>
fadd dword [edi] ; <lout> <r'> <eff> <dry> <fb>
fstp dword [edi] ; <r'> <eff> <dry> <fb>
fadd dword [edi+4] ; <rout> <eff> <dry> <fb>
fstp dword [edi+4] ; <eff> <dry> <fb>
lea edi, [edi+8]
dec ecx
jnz .rloop
mov [ebp + syWModDel.dbptr], edx
fstp st0 ; <dry> <fb>
fstp st0 ; <fb>
fstp st0 ; -
.dont
V2PerfLeave V2Perf_MODDEL
popad
ret
syModDelRenderChan
pushad
V2PerfEnter V2Perf_MODDEL
mov eax, [ebp + syWModDel.effout]
or eax, eax
jz .dont
fld dword [ebp + syWModDel.fbval] ; <fb>
fld dword [ebp + syWModDel.dryout] ; <dry> <fb>
fld dword [ebp + syWModDel.effout] ; <eff> <dry> <fb>
mov edx, [ebp + syWModDel.dbptr]
mov esi, [this]
add esi, SYN.chanbuf
.rloop
fld dword [esi] ; <l> <eff> <dry> <fb>
%if FIXDENORMALS
fadd dword [fcdcoffset]
%endif
fld dword [esi+4] ; <r> <l> <eff> <dry> <fb>
%if FIXDENORMALS
fadd dword [fcdcoffset]
%endif
call syModDelProcessSample ; <l'> <r'> <eff> <dry> <fb>
fstp dword [esi] ; <r'> <eff> <dry> <fb>
fstp dword [esi+4] ; <eff> <dry> <fb>
lea esi, [esi+8]
dec ecx
jnz .rloop
mov [ebp + syWModDel.dbptr], edx
fstp st0 ; <dry> <fb>
fstp st0 ; <fb>
fstp st0 ; -
.dont
V2PerfLeave V2Perf_MODDEL
popad
ret
;#####################################################################################
; Für Ronny und die Freunde des Lauten:
; STEREO COMPRESSOR
;#####################################################################################
global _COMPRESSOR_
_COMPRESSOR_
%define COMPDLEN 5700
;PLAN:
; 1. Pegeldetection
; - entweder Peak mit fixem Falloff...
; - oder RMS über einen 8192-Samples-Buffer
; MODE: stereo/mono
; Zukunft: sidechain? low/highcut dafür?
; 2. Lookahead:
; - Delayline fürs Signal, Länge einstellbar (127msecs)
; 3. Pegelangleicher
; Werte: Threshold, Ratio (1:1 ... 1:inf), Attack (0..?), Decay (0..?)
; Zukunft: Transientdingens (releasetime-anpassung)? Enhancer (high shelving EQ mit boost 1/reduction)?
; Knee? (ATAN!)
struc syVComp
.mode resd 1 ; 0: off / 1: Peak / 2: RMS
.stereo resd 1 ; 0: mono / 1: stereo
.autogain resd 1 ; 0: off / 1: on
.lookahead resd 1 ; lookahead in ms
.threshold resd 1 ; threshold (-54dB .. 6dB ?)
.ratio resd 1 ; ratio (0 : 1:1 ... 127: 1:inf)
.attack resd 1 ; attack value
.release resd 1 ; release value
.outgain resd 1 ; output gain
.size
endstruc
struc syWComp
.mode resd 1 ; int: mode (bit0: peak/rms, bit1: stereo, bit2: off)
.oldmode resd 1 ; int: last mode
.invol resd 1 ; flt: input gain (1/threshold, internal threshold is always 0dB)
.ratio resd 1 ; flt: ratio
.outvol resd 1 ; flt: output gain (outgain * threshold)
.attack resd 1 ; flt: attack (lpf coeff, 0..1)
.release resd 1 ; flt: release (lpf coeff, 0..1)
.dblen resd 1 ; int: lookahead buffer length
.dbcnt resd 1 ; int: lookahead buffer offset
.curgain1 resd 1 ; flt: left current gain
.curgain2 resd 1 ; flt: right current gain
.pkval1 resd 1 ; flt: left/mono peak value
.pkval2 resd 1 ; flt: right peak value
.rmscnt resd 1 ; int: RMS buffer offset
.rmsval1 resd 1 ; flt: left/mono RMS current value
.rmsval2 resd 1 ; flt: right RMS current value
.dbuf resd 2*COMPDLEN ; lookahead delay buffer
.rmsbuf resd 2*8192 ; RMS ring buffer
.size
endstruc
syCompInit:
pushad
mov al, 2
mov byte [ebp + syWComp.mode], al
popad
ret
syCompSet:
pushad
fld dword [esi + syVComp.mode]
fistp dword [temp]
mov eax, [temp]
dec eax
and eax, 5
fld dword [esi + syVComp.stereo]
fistp dword [temp]
mov ebx, [temp]
add ebx, ebx
add eax, ebx
mov [ebp + syWComp.mode], eax
cmp eax, [ebp + syWComp.oldmode]
je .norst
mov [ebp + syWComp.oldmode], eax
mov ecx, 2*8192
xor eax, eax
mov [ebp + syWComp.pkval1], eax
mov [ebp + syWComp.pkval2], eax
mov [ebp + syWComp.rmsval1], eax
mov [ebp + syWComp.rmsval2], eax
lea edi, [ebp + syWComp.rmsbuf]
rep stosd
fld1
fst dword [ebp + syWComp.curgain1]
fstp dword [ebp + syWComp.curgain2]
.norst
fld dword [esi + syVComp.lookahead]
fmul dword [fcsamplesperms]
fistp dword [ebp + syWComp.dblen]
fld dword [esi + syVComp.threshold]
fmul dword [fci128]
call calcfreq
fadd st0, st0
fadd st0, st0
fadd st0, st0
fld1
fdiv st0, st1
fstp dword [ebp + syWComp.invol]
fld dword [esi + syVComp.autogain]
fistp dword [temp]
mov eax, [temp]
or eax, eax
jz .noag
fstp st0
fld1
.noag
fld dword [esi + syVComp.outgain]
fsub dword [fc64]
fmul dword [fci16]
call pow2
fmulp st1, st0
fstp dword [ebp + syWComp.outvol]
fld dword [esi + syVComp.ratio]
fmul dword [fci128]
fstp dword [ebp + syWComp.ratio]
;attack: 0 (!) ... 200msecs (5Hz)
fld dword [esi + syVComp.attack]
fmul dword [fci128] ; 0 .. fast1
fmul dword [fcm12] ; 0 .. fastminus12
call pow2 ; 1 .. 2^(fastminus12)
fstp dword [ebp + syWComp.attack]
;release: 5ms bis 5s
fld dword [esi + syVComp.release]
fmul dword [fci128] ; 0 .. fast1
fmul dword [fcm16] ; 0 .. fastminus16
call pow2 ; 1 .. 2^(fastminus16)
fstp dword [ebp + syWComp.release]
popad
ret
syCompLDMonoPeak:
pushad
fld dword [ebp + syWComp.pkval1] ; <pv>
.lp
fld dword [esi] ; <l> <pv>
fadd dword [esi + 4] ; <l+r> <pv>
fmul dword [fci2] ; <in> <pv>
fstp dword [temp] ; <pv>
fmul dword [fccpdfalloff] ; <pv'>
%if FIXDENORMALS
fadd dword [fcdcoffset]
%endif
lea esi, [esi+8]
fstp dword [temp + 4] ; -
mov eax, [temp]
and eax, 7fffffffh ; fabs()
cmp eax, [temp + 4]
jbe .nonp
mov [temp + 4], eax
.nonp
fld dword [temp + 4] ; <npv>
fld st0
fmul dword [ebp + syWComp.invol]
fst dword [edi]
fstp dword [edi+4]
lea edi, [edi+8]
dec ecx
jnz .lp
fstp dword [ebp + syWComp.pkval1] ; -
popad
ret
syCompLDMonoRMS:
pushad
fld dword [ebp + syWComp.rmsval1] ; <rv>
mov eax, [ebp + syWComp.rmscnt]
lea edx, [ebp + syWComp.rmsbuf]
.lp
fsub dword [edx + 4*eax] ; <rv'>
fld dword [esi] ; <l> <rv'>
fadd dword [esi + 4] ; <l+r> <rv'>
fmul dword [fci2] ; <in> <rv'>
%if FIXDENORMALS
fadd dword [fcdcoffset]
%endif
lea esi, [esi+8]
fmul st0, st0 ; <in²> <rv'>
fadd st1, st0 ; <in²> <rv''>
fstp dword [edx + 4*eax] ; <rv''>
fld st0 ; <rv''> <rv''>
fsqrt ; <sqrv> <rv''>
fmul dword [fci8192]
inc eax
and ah, 0x1f
fmul dword [ebp + syWComp.invol]
fst dword [edi]
fstp dword [edi+4] ; <rv''>
lea edi, [edi+8]
dec ecx
jnz .lp
mov [ebp + syWComp.rmscnt], eax
fstp dword [ebp + syWComp.rmsval1] ; -
popad
ret
syCompLDStereoPeak:
pushad
fld dword [ebp + syWComp.pkval2] ; <rpv>
fld dword [ebp + syWComp.pkval1] ; <lpv> <rpv>
.lp
fmul dword [fccpdfalloff] ; <lpv'> <rpv>
fxch st1 ; <rpv> <lpv'>
fmul dword [fccpdfalloff] ; <rpv'> <lpv'>
fxch st1 ; <lpv'> <rpv'>
%if FIXDENORMALS
fadd dword [fcdcoffset]
fxch st1
fadd dword [fcdcoffset]
fxch st1
%endif
fstp dword [temp] ; <rpv'>
fstp dword [temp+4] ; -
mov eax, [esi]
and eax, 7fffffffh ; fabs()
cmp eax, [temp]
jbe .nonp1
mov [temp], eax
.nonp1
mov eax, [esi+4]
and eax, 7fffffffh ; fabs()
cmp eax, [temp+4]
jbe .nonp2
mov [temp+4], eax
.nonp2
lea esi, [esi+8]
fld dword [temp+4] ; <nrpv>
fld st0
fmul dword [ebp + syWComp.invol]
fstp dword [edi+4]
fld dword [temp] ; <nlpv> <nrpv>
fld st0
fmul dword [ebp + syWComp.invol]
fstp dword [edi]
lea edi, [edi+8]
dec ecx
jnz .lp
fstp dword [ebp + syWComp.pkval1] ; <nrpv>
fstp dword [ebp + syWComp.pkval2] ; -
popad
ret
syCompLDStereoRMS:
pushad
fld dword [ebp + syWComp.rmsval2] ; <rrv>
fld dword [ebp + syWComp.rmsval1] ; <lrv> <rrv>
mov eax, [ebp + syWComp.rmscnt]
lea edx, [ebp + syWComp.rmsbuf]
.lp
fsub dword [edx + 8*eax] ; <lrv'> <rrv>
fxch st1 ; <rrv> <lrv'>
fsub dword [edx + 8*eax + 4] ; <rrv'> <lrv'>
fxch st1 ; <lrv'> <rrv'>
%if FIXDENORMALS
fadd dword [fcdcoffset]
fxch st1
fadd dword [fcdcoffset]
fxch st1
%endif
fld dword [esi] ; <l> <lrv'> <rrv'>
fmul st0, st0 ; <l²> <lrv'> <rrv'>
fadd st1, st0 ; <l²> <lrv''> <rrv'>
fstp dword [edx + 8*eax] ; <lrv''> <rrv'>
fld st0 ; <lrv''> <lrv''> <rrv'>
fsqrt ; <sqlrv> <lrv''> <rrv'>
fmul dword [fci8192]
fmul dword [ebp + syWComp.invol]
fstp dword [edi] ; <lrv''> <rrv'>
fld dword [esi+4] ; <r> <lrv''> <rrv'>
fmul st0, st0 ; <r²> <lrv''> <rrv'>
fadd st2, st0 ; <r²> <lrv''> <rrv''>
fstp dword [edx + 8*eax + 4] ; <lrv''> <rrv''>
fld st1 ; <rrv''> <lrv''> <rrv''>
fsqrt ; <sqrrv> <lrv''> <rrv''>
fmul dword [fci8192]
fmul dword [ebp + syWComp.invol]
fstp dword [edi+4] ; <lrv''> <rrv''>
lea esi, [esi+8]
inc eax
and ah, 0x1f
lea edi, [edi+8]
dec ecx
jnz .lp
mov [ebp + syWComp.rmscnt], eax
fstp dword [ebp + syWComp.rmsval1] ; <nrrv>
fstp dword [ebp + syWComp.rmsval2] ; -
popad
ret
; ebp: this
; ebx: ptr to lookahead line
; ecx: # of samples to process
; edx: offset into lookahead line
; esi: ptr to in/out buffer
; edi: ptr to level buffer
; st0: current gain value
syCompProcChannel:
pushad
.cloop
fst dword [temp]
; lookahead
fld dword [ebx + 8*edx] ; <v> <gain>
fld dword [esi] ; <nv> <v> <gain>
fmul dword [ebp + syWComp.invol] ; <nv'> <v> <gain>
fstp dword [ebx + 8*edx] ; <v> <gain>
fmul dword [ebp + syWComp.outvol]; <v'> <gain>
inc edx
cmp edx, [ebp + syWComp.dblen]
jbe .norst
xor edx, edx
.norst
; destgain ermitteln
mov eax, [edi]
cmp eax, 3f800000h ; 1.0
jae .docomp
fld1 ; <dgain> <v> <gain>
jmp .cok
.docomp
fld dword [edi] ; <lvl> <v> <gain>
fld1 ; <1> <lvl> <v> <gain>
fsubp st1, st0 ; <lvl-1> <v> <gain>
fmul dword [ebp + syWComp.ratio] ; <r*(lvl-1)> <v> <gain>
fld1 ; <1> <r*(lvl-1)> <v> <gain>
faddp st1, st0 ; <1+r*(lvl-1)> <v> <gain>
fld1 ; <1> <1+r*(lvl-1)> <v> <gain>
fdivrp st1, st0 ; <dgain> <v> <gain>
.cok
lea edi, [edi+8]
fst dword [temp+4]
mov eax, [temp+4]
cmp eax, [temp]
jb .attack
fld dword [ebp + syWComp.release] ; <spd> <dgain> <v> <gain>
jmp .cok2
.attack
fld dword [ebp + syWComp.attack] ; <spd> <dgain> <v> <gain>
.cok2
; und compressen
fxch st1 ; <dg> <spd> <v> <gain>
fsub st0, st3 ; <dg-gain> <spd> <v> <gain>
fmulp st1, st0 ; <spd*(dg-d)> <v> <gain>
faddp st2, st0 ; <v> <gain'>
fmul st0, st1 ; <out> <gain'>
fstp dword [esi] ; <gain'>
lea esi, [esi+8]
dec ecx
jnz near .cloop
mov [temp], edx
popad
ret
; on exit: [temp] = new dline count
section .data
syCRMTab dd syCompLDMonoPeak, syCompLDMonoRMS, syCompLDStereoPeak, syCompLDStereoRMS
section .text
; esi: input/output buffer
; ecx: # of samples
syCompRender:
pushad
V2PerfEnter V2Perf_COMPRESSOR
fclex ; clear exceptions
mov eax, [ebp + syWComp.mode]
test al, 4
jz .doit
V2PerfLeave V2Perf_COMPRESSOR
popad
ret
.doit
; STEP 1: level detect (fills LD buffers)
mov edi, [this]
add edi, SYN.vcebuf
and al, 3
call [syCRMTab + 4*eax]
; check for FPU exception
fstsw ax
or al, al
jns .fpuok
; if occured, clear LD buffer
push ecx
push edi
fldz
add ecx, ecx
xor eax, eax
rep stosd
fstp st0
pop edi
pop ecx
.fpuok
; STEP 2: compress!
lea ebx, [ebp + syWComp.dbuf]
mov edx, [ebp + syWComp.dbcnt]
fld dword [ebp + syWComp.curgain1]
call syCompProcChannel
fstp dword [ebp + syWComp.curgain1]
lea esi, [esi+4]
lea edi, [edi+4]
lea ebx, [ebx+4]
fld dword [ebp + syWComp.curgain2]
call syCompProcChannel
fstp dword [ebp + syWComp.curgain2]
mov edx, [temp]
mov [ebp + syWComp.dbcnt], edx
V2PerfLeave V2Perf_COMPRESSOR
popad
ret
;#####################################################################################
;#
;# E L I T E G R O U P
;# we are very good.
;#
;# World Domination Intro Sound System
;# -> Stereo reverb plugin (reads aux1)
;#
;# Written and (C) 1999 by The Artist Formerly Known As Doctor Roole
;#
;# This is a modified Schroeder reverb (as found in csound et al) consisting
;# of four parallel comb filter delay lines (with low pass filtered feedback),
;# followed by two allpass filter delay lines per channel. The input signal
;# is feeded directly into half of the comb delays, while it's inverted before
;# being feeded into the other half to minimize the response to DC offsets in
;# the incoming signal, which was a great problem of the original implementa-
;# tion. Also, all of the comb delays are routed through 12dB/oct IIR low pass
;# filters before feeding the output signal back to the input to simulate the
;# walls' high damping, which makes this reverb sound a lot smoother and much
;# more realistic.
;#
;# This leaves nothing but the conclusion that we're simply better than you.
;#
;#####################################################################################
; lengths of delay lines in samples
lencl0 equ 1309 ; left comb filter delay 0
lencl1 equ 1635 ; left comb filter delay 1
lencl2 equ 1811 ; left comb filter delay 2
lencl3 equ 1926 ; left comb filter delay 3
lenal0 equ 220 ; left all pass delay 0
lenal1 equ 74 ; left all pass delay 1
lencr0 equ 1327 ; right comb filter delay 0
lencr1 equ 1631 ; right comb filter delay 1
lencr2 equ 1833 ; right comb filter delay 2
lencr3 equ 1901 ; right comb filter delay 3
lenar0 equ 205 ; right all pass delay 0
lenar1 equ 77 ; right all pass delay 1
global _REVERB_
_REVERB_
struc syVReverb
.revtime resd 1
.highcut resd 1
.lowcut resd 1
.vol resd 1
.size
endstruc
struc syCReverb
.gainc0 resd 1 ; feedback gain for comb filter delay 0
.gainc1 resd 1 ; feedback gain for comb filter delay 1
.gainc2 resd 1 ; feedback gain for comb filter delay 2
.gainc3 resd 1 ; feedback gain for comb filter delay 3
.gaina0 resd 1 ; feedback gain for allpass delay 0
.gaina1 resd 1 ; feedback gain for allpass delay 1
.gainin resd 1 ; input gain
.damp resd 1 ; high cut (1-val²)
.lowcut resd 1 ; low cut (val²)
.size
endstruc
struc syWReverb
.setup resb syCReverb.size
; positions of delay lines
.dyn
.poscl0 resd 1
.poscl1 resd 1
.poscl2 resd 1
.poscl3 resd 1
.posal0 resd 1
.posal1 resd 1
.poscr0 resd 1
.poscr1 resd 1
.poscr2 resd 1
.poscr3 resd 1
.posar0 resd 1
.posar1 resd 1
; comb delay low pass filter buffers (y(k-1))
.lpfcl0 resd 1
.lpfcl1 resd 1
.lpfcl2 resd 1
.lpfcl3 resd 1
.lpfcr0 resd 1
.lpfcr1 resd 1
.lpfcr2 resd 1
.lpfcr3 resd 1
; memory for low cut filters
.hpfcl resd 1
.hpfcr resd 1
; memory for the delay lines
.linecl0 resd lencl0
.linecl1 resd lencl1
.linecl2 resd lencl2
.linecl3 resd lencl3
.lineal0 resd lenal0
.lineal1 resd lenal1
.linecr0 resd lencr0
.linecr1 resd lencr1
.linecr2 resd lencr2
.linecr3 resd lencr3
.linear0 resd lenar0
.linear1 resd lenar1
.size
endstruc
section .data
; see struct above
syRvDefs dd 0.966384599, 0.958186359, 0.953783929, 0.950933178, 0.994260075, 0.998044717
dd 1.0 ; input gain
dd 0.8 ; high cut
section .text
syReverbInit
pushad
xor eax, eax
mov ecx, syWReverb.size
mov edi, ebp
rep stosb
popad
ret
syReverbReset
pushad
xor eax, eax
mov ecx, syWReverb.size-syWReverb.dyn
lea edi, [ebp + syWReverb.dyn]
rep stosb
popad
ret
syReverbSet
pushad
fld dword [esi + syVReverb.revtime]
fld1
faddp st1, st0
fld dword [fc64]
fdivrp st1, st0
fmul st0, st0
fmul dword [SRfclinfreq]
xor ecx, ecx
.rtloop
fld st0
fld dword [syRvDefs+4*ecx]
call pow
fstp dword [ebp + syWReverb.setup + syCReverb.gainc0 + 4*ecx]
inc ecx
cmp cl, 6
jne .rtloop
fstp st0
fld dword [esi + syVReverb.highcut]
fmul dword [fci128]
fmul dword [SRfclinfreq]
fstp dword [ebp + syWReverb.setup + syCReverb.damp]
fld dword [esi + syVReverb.vol]
fmul dword [fci128]
fstp dword [ebp + syWReverb.setup + syCReverb.gainin]
fld dword [esi + syVReverb.lowcut]
fmul dword [fci128]
fmul st0, st0
fmul st0, st0
fmul dword [SRfclinfreq]
fstp dword [ebp + syWReverb.setup + syCReverb.lowcut]
popad
ret
syReverbProcess
pushad
V2PerfEnter V2Perf_REVERB
fclex
mov esi, [this]
add esi, SYN.aux1buf
fld dword [ebp + syWReverb.setup + syCReverb.lowcut] ; <lc> <0>
fld dword [ebp + syWReverb.setup + syCReverb.damp] ; <damp> <lc> <0>
xor ebx, ebx
mov eax, ecx
.sloop ; prinzipiell nur ne große schleife
; step 1: get input sample
fld dword [esi] ; <in'> <damp> <lc> <0>
fmul dword [ebp + syWReverb.setup + syCReverb.gainin] ; <in> <damp> <lc> <0>
%if FIXDENORMALS
fadd dword [fcdcoffset]
%endif
lea esi, [esi+4]
; step 2a: process the 4 left lpf filtered comb delays
; left comb 0
mov edx, [ebp + syWReverb.poscl0]
fld dword [ebp + syWReverb.linecl0+4*edx] ; <dv> <in> <damp> <lc> <chk>
fmul dword [ebp + syWReverb.setup + syCReverb.gainc0] ; <dv'> <in> <damp> <lc> <chk>
fadd st0, st1 ; <nv> <in> <damp> <lc> <chk>
fsub dword [ebp + syWReverb.lpfcl0] ; <v-lp> <in> <damp> <lc> <chk>
fmul st0, st2 ; <d*(v-lp)> <in> <damp> <lc> <chk>
fadd dword [ebp + syWReverb.lpfcl0] ; <dout> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.lpfcl0] ; <dout> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.linecl0+4*edx] ; <asuml> <in> <damp> <lc> <chk>
inc edx
cmp dx, lencl0
cmove edx, ebx
mov [ebp + syWReverb.poscl0], edx
; left comb 1
mov edx, [ebp + syWReverb.poscl1]
fld dword [ebp + syWReverb.linecl1+4*edx] ; <dv> <asuml> <in> <damp> <lc> <chk>
fmul dword [ebp + syWReverb.setup + syCReverb.gainc1] ; <dv'> <asuml> <in> <damp> <lc> <chk>
fsub st0, st2 ; <nv> <asuml> <in> <damp> <lc> <chk>
fsub dword [ebp + syWReverb.lpfcl1] ; <v-lp> <asuml> <in> <damp> <lc> <chk>
fmul st0, st3 ; <d*(v-lp)> <asuml> <in> <damp> <lc> <chk>
fadd dword [ebp + syWReverb.lpfcl1] ; <dout> <asuml> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.lpfcl1] ; <dout> <asuml> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.linecl1+4*edx] ; <dout> <asuml> <in> <damp> <lc> <chk>
faddp st1, st0 ; <asuml'> <in> <damp> <lc> <chk>
inc edx
cmp dx, lencl1
cmove edx, ebx
mov [ebp + syWReverb.poscl1], edx
; left comb 2
mov edx, [ebp + syWReverb.poscl2]
fld dword [ebp + syWReverb.linecl2+4*edx] ; <dv> <asuml> <in> <damp> <lc> <chk>
fmul dword [ebp + syWReverb.setup + syCReverb.gainc2] ; <dv'> <asuml> <in> <damp> <lc> <chk>
fadd st0, st2 ; <nv> <asuml> <in> <damp> <lc> <chk>
fsub dword [ebp + syWReverb.lpfcl2] ; <v-lp> <asuml> <in> <damp> <lc> <chk>
fmul st0, st3 ; <d*(v-lp)> <asuml> <in> <damp> <lc> <chk>
fadd dword [ebp + syWReverb.lpfcl2] ; <dout> <asuml> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.lpfcl2] ; <dout> <asuml> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.linecl2+4*edx] ; <dout> <asuml> <in> <damp> <lc> <chk>
faddp st1, st0 ; <asuml'> <in> <damp> <lc> <chk>
inc edx
cmp dx, lencl2
cmove edx, ebx
mov [ebp + syWReverb.poscl2], edx
; left comb 3
mov edx, [ebp + syWReverb.poscl3]
fld dword [ebp + syWReverb.linecl3+4*edx] ; <dv> <asuml> <in> <damp> <lc> <chk>
fmul dword [ebp + syWReverb.setup + syCReverb.gainc3] ; <dv'> <asuml> <in> <damp> <lc> <chk>
fsub st0, st2 ; <nv> <asuml> <in> <damp> <lc> <chk>
fsub dword [ebp + syWReverb.lpfcl3] ; <v-lp> <asuml> <in> <damp> <lc> <chk>
fmul st0, st3 ; <d*(v-lp)> <asuml> <in> <damp> <lc> <chk>
fadd dword [ebp + syWReverb.lpfcl3] ; <dout> <asuml> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.lpfcl3] ; <dout> <asuml> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.linecl3+4*edx] ; <dout> <asuml> <in> <damp> <lc> <chk>
faddp st1, st0 ; <asuml'> <in> <damp> <lc> <chk>
inc edx
cmp dx, lencl3
cmove edx, ebx
mov [ebp + syWReverb.poscl3], edx
; step 2b: process the 2 left allpass delays
; left allpass 0
mov edx, [ebp + syWReverb.posal0]
fld dword [ebp + syWReverb.lineal0+4*edx] ; <d0v> <asuml> <in> <damp> <lc> <chk>
fld st0 ; <d0v> <d0v> <asuml> <in> <damp> <lc> <chk>
fmul dword [ebp + syWReverb.setup + syCReverb.gaina0] ; <d0v'> <d0v> <asuml> <in> <damp> <lc> <chk>
faddp st2, st0 ; <d0v> <d0z> <in> <damp> <lc> <chk>
fxch st0, st1 ; <d0z> <d0v> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.lineal0+4*edx]
fmul dword [ebp + syWReverb.setup + syCReverb.gaina0] ; <d0z'> <d0v> <in> <damp> <lc> <chk>
fsubp st1, st0 ; <d0o> <in> <damp> <lc> <chk>
inc edx
cmp dl, lenal0
cmove edx, ebx
mov [ebp + syWReverb.posal0], edx
; left allpass 1
mov edx, [ebp + syWReverb.posal1]
fld dword [ebp + syWReverb.lineal1+4*edx] ; <d1v> <d0o> <in> <damp> <lc> <chk>
fld st0 ; <d1v> <d1v> <d0o> <in> <damp> <lc> <chk>
fmul dword [ebp + syWReverb.setup + syCReverb.gaina1] ; <d1v'> <d1v> <d0o> <in> <damp> <lc> <chk>
faddp st2, st0 ; <d1v> <d1z> <in> <damp> <lc> <chk>
fxch st0, st1 ; <d1z> <d1v> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.lineal1+4*edx]
fmul dword [ebp + syWReverb.setup + syCReverb.gaina1] ; <d1z'> <d1v> <in> <damp> <lc> <chk>
fsubp st1, st0 ; <d1o> <in> <damp> <lc> <chk>
inc edx
cmp dl, lenal1
cmove edx, ebx
mov [ebp + syWReverb.posal1], edx
; step 2c: low cut
fld dword [ebp + syWReverb.hpfcl] ; <hpf> <d1o> <in> <damp> <lc> <chk>
fld st0 ; <hpf> <hpf> <d1o> <in> <damp> <lc> <chk>
fsubr st0, st2 ; <d1o-hpf> <hpf> <d1o> <in> <damp> <lc> <chk>
fmul st0, st5 ; <lc(d1o-hpf)> <hpf> <d1o> <in> <damp> <lc> <chk>
faddp st1, st0 ; <hpf'> <d1o> <in> <damp> <lc> <chk>
fst dword [ebp + syWReverb.hpfcl]