Implement support for 64-bit builds.

The implentation is through a few macros to handle the fact in 64-bit, all addresses have to be loaded first to register and only offsets are ok. Also, push only supports 64-bit registers in 64-bit, so we have _AX, _BX, _CX etc. defines, which are eax, ebx and ecx on 32bit and rax, rbx and rcx on 64bit.
This commit is contained in:
Veikko Sariola
2020-05-21 17:18:18 +03:00
parent 6f7fed4c6b
commit 654e5868bc
13 changed files with 472 additions and 264 deletions

View File

@ -70,8 +70,8 @@ EXPORT MANGLE_FUNC(su_op_loadnote,0)
call su_op_loadnote_mono
su_op_loadnote_mono:
%endif
fild dword [ecx+su_unit.size-su_voice.workspace+su_voice.note]
fmul dword [c_i128]
fild dword [_CX+su_unit.size-su_voice.workspace+su_voice.note]
apply fmul dword, c_i128
ret
%endif

View File

@ -14,7 +14,7 @@ EXPORT MANGLE_FUNC(su_op_distort,0)
call su_effects_stereohelper
%define INCLUDE_EFFECTS_STEREOHELPER
%endif
fld dword [edx+su_distort_ports.drive]
fld dword [INP+su_distort_ports.drive]
%define SU_INCLUDE_WAVESHAPER
; flow into waveshaper
%endif
@ -25,7 +25,7 @@ su_waveshaper:
call su_clip
fxch ; a x' (from now on just called x)
fld st0 ; a a x
fsub dword [c_0_5] ; a-.5 a x
apply fsub dword,c_0_5 ; a-.5 a x
fadd st0 ; 2*a-1 a x
fld st2 ; x 2*a-1 a x
fabs ; abs(x) 2*a-1 a x
@ -53,17 +53,17 @@ EXPORT MANGLE_FUNC(su_op_hold,0)
call su_effects_stereohelper
%define INCLUDE_EFFECTS_STEREOHELPER
%endif
fld dword [edx+su_hold_ports.freq] ; f x
fld dword [INP+su_hold_ports.freq] ; f x
fmul st0, st0 ; f^2 x
fchs ; -f^2 x
fadd dword [WRK+su_hold_wrk.phase] ; p-f^2 x
fst dword [WRK+su_hold_wrk.phase] ; p <- p-f^2
fldz ; 0 p x
fucomip st1 ; p x
fstp dword [esp-4] ; t=p, x
fstp dword [_SP-4] ; t=p, x
jc short su_op_hold_holding ; if (0 < p) goto holding
fld1 ; 1 x
fadd dword [esp-4] ; 1+t x
fadd dword [_SP-4] ; 1+t x
fstp dword [WRK+su_hold_wrk.phase] ; x
fst dword [WRK+su_hold_wrk.holdval] ; save holded value
ret ; x
@ -85,10 +85,10 @@ EXPORT MANGLE_FUNC(su_op_crush,0)
%ifdef INCLUDE_STEREO_CRUSH
call su_effects_stereohelper
%define INCLUDE_EFFECTS_STEREOHELPER
%endif
fdiv dword [edx+su_crush_ports.resolution]
%endif
fdiv dword [INP+su_crush_ports.resolution]
frndint
fmul dword [edx+su_crush_ports.resolution]
fmul dword [INP+su_crush_ports.resolution]
ret
%endif ; CRUSH_ID > -1
@ -101,15 +101,15 @@ EXPORT MANGLE_FUNC(su_op_crush,0)
SECT_TEXT(sugain)
%ifdef INCLUDE_STEREO_GAIN
EXPORT MANGLE_FUNC(su_op_gain,0)
fld dword [edx+su_gain_ports.gain] ; g l (r)
fld dword [INP+su_gain_ports.gain] ; g l (r)
jnc su_op_gain_mono
fmul st2, st0 ; g l r/g
fmul st2, st0 ; g l r/g
su_op_gain_mono:
fmulp st1, st0 ; l/g (r/)
ret
%else
EXPORT MANGLE_FUNC(su_op_gain,0)
fmul dword [edx+su_gain_ports.gain]
fmul dword [INP+su_gain_ports.gain]
ret
%endif
%endif ; GAIN_ID > -1
@ -122,7 +122,7 @@ SECT_TEXT(sugain)
SECT_TEXT(suingain)
%ifdef INCLUDE_STEREO_INVGAIN
EXPORT MANGLE_FUNC(su_op_invgain,0)
fld dword [edx+su_invgain_ports.invgain] ; g l (r)
fld dword [INP+su_invgain_ports.invgain] ; g l (r)
jnc su_op_invgain_mono
fdiv st2, st0 ; g l r/g
su_op_invgain_mono:
@ -130,7 +130,7 @@ SECT_TEXT(suingain)
ret
%else
EXPORT MANGLE_FUNC(su_op_invgain,0)
fdiv dword [edx+su_invgain_ports.invgain]
fdiv dword [INP+su_invgain_ports.invgain]
ret
%endif
%endif ; INVGAIN_ID > -1
@ -150,14 +150,14 @@ SECT_TEXT(sufilter)
EXPORT MANGLE_FUNC(su_op_filter,0)
lodsb ; load the flags to al
%ifdef INCLUDE_STEREO_FILTER
%ifdef INCLUDE_STEREO_FILTER
call su_effects_stereohelper
%define INCLUDE_EFFECTS_STEREOHELPER
%endif
fld dword [edx+su_filter_ports.res] ; r x
fld dword [edx+su_filter_ports.freq]; f r x
fld dword [INP+su_filter_ports.res] ; r x
fld dword [INP+su_filter_ports.freq]; f r x
fmul st0, st0 ; f2 x (square the input so we never get negative and also have a smoother behaviour in the lower frequencies)
fst dword [esp-4] ; f2 r x
fst dword [_SP-4] ; f2 r x
fmul dword [WRK+su_filter_wrk.band] ; f2*b r x
fadd dword [WRK+su_filter_wrk.low] ; f2*b+l r x
fst dword [WRK+su_filter_wrk.low] ; l'=f2*b+l r x
@ -165,7 +165,7 @@ EXPORT MANGLE_FUNC(su_op_filter,0)
fmul dword [WRK+su_filter_wrk.band] ; r*b x-l'
fsubp st1, st0 ; x-l'-r*b
fst dword [WRK+su_filter_wrk.high] ; h'=x-l'-r*b
fmul dword [esp-4] ; f2*h'
fmul dword [_SP-4] ; f2*h'
fadd dword [WRK+su_filter_wrk.band] ; f2*h'+b
fstp dword [WRK+su_filter_wrk.band] ; b'=f2*h'+b
fldz ; 0
@ -212,9 +212,9 @@ SECT_TEXT(suclip)
%if CLIP_ID > -1
EXPORT MANGLE_FUNC(su_op_clip,0)
%ifdef INCLUDE_STEREO_CLIP
%ifdef INCLUDE_STEREO_CLIP
call su_effects_stereohelper
%define INCLUDE_EFFECTS_STEREOHELPER
%define INCLUDE_EFFECTS_STEREOHELPER
%endif
%define SU_INCLUDE_CLIP
; flow into su_doclip
@ -255,7 +255,7 @@ EXPORT MANGLE_FUNC(su_op_pan,0)
jc su_op_pan_do ; this time, if this is mono op...
fld st0 ; ...we duplicate the mono into stereo first
su_op_pan_do:
fld dword [edx+su_pan_ports.panning] ; p l r
fld dword [INP+su_pan_ports.panning] ; p l r
fld1 ; 1 p l r
fsub st1 ; 1-p p l r
fmulp st2 ; p (1-p)*l r
@ -265,7 +265,7 @@ su_op_pan_do:
%else ; ifndef INCLUDE_STEREO_PAN
EXPORT MANGLE_FUNC(su_op_pan,0)
fld dword [edx+su_pan_ports.panning] ; p s
fld dword [INP+su_pan_ports.panning] ; p s
fmul st1 ; p*s s
fsub st1, st0 ; p*s s-p*s
; Equal to
@ -288,7 +288,7 @@ su_effects_stereohelper:
jnc su_effects_stereohelper_mono ; carry is still the stereo bit
add WRK, 16
fxch ; r l
call dword [esp] ; call whoever called me...
call [_SP] ; call whoever called me...
fxch ; l r
sub WRK, 16 ; move WRK back to where it was
su_effects_stereohelper_mono:
@ -324,68 +324,68 @@ EXPORT MANGLE_FUNC(su_op_delay,0)
add edi, eax ; the second delay is done with the delay time index added by count
su_op_delay_mono:
%endif
pushad
push_registers _AX, _CX, _BX, WRK, _SI, _DI
mov ebx, edi; ugly register juggling, refactor
%ifdef DELAY_NOTE_SYNC
test ebx, ebx ; note s
jne su_op_delay_skipnotesync
fld1
fild dword [ecx+su_unit.size-su_voice.workspace+su_voice.note]
fmul dword [c_i12]
fild dword [_CX+su_unit.size-su_voice.workspace+su_voice.note]
apply fmul dword, c_i12
call MANGLE_FUNC(su_power,0)
fmul dword [c_freq_normalize] ; // normalize
apply fmul dword, c_freq_normalize ; // normalize
fdivp st1, st0 ; // invert to get numer of samples
fistp word [MANGLE_DATA(su_delay_times)] ; store current comb size
apply fistp word, MANGLE_DATA(su_delay_times) ; store current comb size
su_op_delay_skipnotesync:
%endif
kmDLL_func_process:
mov ecx, eax ;// ecx is the number of parallel delays
mov WRK, dword [MANGLE_DATA(su_delay_buffer_ofs)] ;// ebp is current delay
apply {mov WRK, PTRWORD},MANGLE_DATA(su_delay_buffer_ofs) ;// ebp is current delay
fld st0 ; x x
fmul dword [edx+su_delay_ports.dry] ; dr*x x
fmul dword [INP+su_delay_ports.dry] ; dr*x x
fxch ; x dr*x
fmul dword [edx+su_delay_ports.pregain] ; p*x dr*x
fmul dword [edx+su_delay_ports.pregain] ; p^2*x dr*x
fmul dword [INP+su_delay_ports.pregain] ; p*x dr*x
fmul dword [INP+su_delay_ports.pregain] ; p^2*x dr*x
kmDLL_func_loop:
mov edi, dword [WRK + su_delayline_wrk.time]
inc edi
and edi, MAX_DELAY-1
mov dword [WRK + su_delayline_wrk.time],edi
movzx esi, word [MANGLE_DATA(su_delay_times)+ebx*2] ; esi = comb size from the delay times table
apply {movzx esi, word},MANGLE_DATA(su_delay_times),_BX*2,{} ; esi = comb size from the delay times table
mov eax, edi
sub eax, esi
and eax, MAX_DELAY-1
fld dword [WRK+eax*4+su_delayline_wrk.buffer] ; s p^2*x dr*x, where s is the sample from delay buffer
apply fld dword, su_delayline_wrk.buffer, WRK, _AX*4,{} ; s p^2*x dr*x, where s is the sample from delay buffer
;// add comb output to current output
fadd st2, st0 ; s p^2*x dr*x+s
fld1 ; 1 s p^2*x dr*x+s
fsub dword [edx+su_delay_ports.damp] ; 1-da s p^2*x dr*x+s
fsub dword [INP+su_delay_ports.damp] ; 1-da s p^2*x dr*x+s
fmulp st1, st0 ; s*(1-da) p^2*x dr*x+s
fld dword [edx+su_delay_ports.damp] ; da s*(1-da) p^2*x dr*x+s
fld dword [INP+su_delay_ports.damp] ; da s*(1-da) p^2*x dr*x+s
fmul dword [WRK+su_delayline_wrk.filtstate] ; o*da s*(1-da) p^2*x dr*x+s, where o is stored
faddp st1, st0 ; o*da+s*(1-da) p^2*x dr*x+s
fst dword [WRK+su_delayline_wrk.filtstate] ; o'=o*da+s*(1-da), o' p^2*x dr*x+s
fmul dword [edx+su_delay_ports.feedback] ; f*o' p^2*x dr*x+s
fmul dword [INP+su_delay_ports.feedback] ; f*o' p^2*x dr*x+s
fadd st0, st1 ; f*o'+p^2*x p^2*x dr*x+s
fstp dword [WRK+edi*4+su_delayline_wrk.buffer]; save f*o'+p^2*x to delay buffer
fstp dword [WRK+_DI*4+su_delayline_wrk.buffer]; save f*o'+p^2*x to delay buffer
inc ebx ;// go to next delay lenkmh index
add WRK, su_delayline_wrk.size ;// go to next delay
mov dword [MANGLE_DATA(su_delay_buffer_ofs)], WRK ;// store next delay offset
apply mov PTRWORD, MANGLE_DATA(su_delay_buffer_ofs),{, WRK} ;// store next delay offset
loopne kmDLL_func_loop
fstp st0 ; dr*x+s1+s2+s3+...
; DC-filtering
sub WRK, su_delayline_wrk.size ; the reason to use the last su_delayline_wrk instead of su_delay_wrk is that su_delay_wrk is wiped by retriggering
fld dword [WRK+su_delayline_wrk.dcout] ; o s
fmul dword [c_dc_const] ; c*o s
apply fmul dword, c_dc_const ; c*o s
fsub dword [WRK+su_delayline_wrk.dcin] ; c*o-i s
fxch ; s c*o-i
fst dword [WRK+su_delayline_wrk.dcin] ; i'=s, s c*o-i
faddp st1 ; s+c*o-i
fadd dword [c_0_5] ;// add and sub small offset to prevent denormalization
fsub dword [c_0_5]
apply fadd dword, c_0_5 ;// add and sub small offset to prevent denormalization
apply fsub dword, c_0_5
fst dword [WRK+su_delayline_wrk.dcout] ; o'=s+c*o-i
popad
pop_registers _AX, _CX, _BX, WRK, _SI, _DI
ret
;-------------------------------------------------------------------------------
@ -394,7 +394,8 @@ kmDLL_func_loop:
SECT_BSS(sudelbuf)
EXPORT MANGLE_DATA(su_delay_buffer_ofs)
resd 1
RESPTR 1
EXPORT MANGLE_DATA(su_delay_buffer)
resb NUM_DELAY_LINES*su_delayline_wrk.size
@ -443,7 +444,7 @@ su_op_compressor_releasing:
fmulp st2, st0 ; l c*(x^2-l) x
faddp st1, st0 ; l+c*(x^2-l) x
fst dword [WRK+su_compres_wrk.level] ; l'=l+c*(x^2-l), l' x
fld dword [edx+su_compres_ports.threshold] ; t l' x
fld dword [INP+su_compres_ports.threshold] ; t l' x
fmul st0, st0 ; t*t
fucomi st0, st1 ; if threshold < l'
jb su_op_compressor_compress ; then we actually do compression
@ -453,8 +454,8 @@ su_op_compressor_releasing:
ret ; return unity gain when we are below threshold
su_op_compressor_compress: ; l' x
fdivrp st1, st0 ; t*t/l' x
fld dword [edx+su_compres_ports.ratio] ; r t*t/l' x
fmul dword [c_0_5] ; p=r/2 t*t/l' x
fld dword [INP+su_compres_ports.ratio] ; r t*t/l' x
apply fmul dword, c_0_5 ; p=r/2 t*t/l' x
fxch ; t*t/l' p x
fyl2x ; p*log2(t*t/l') x
jmp MANGLE_FUNC(su_power,0) ; 2^(p*log2(t*t/l')) x

View File

@ -21,31 +21,29 @@ SECT_TEXT(suopadvn)
%ifdef INCLUDE_POLYPHONY
EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
mov WRK, dword [esp+8] ; WRK = wrkptr
mov WRK, [_SP+PTRSIZE*2] ; WRK = wrkptr
add WRK, su_voice.size ; move to next voice
mov dword [esp+8], WRK ; update stack
mov ecx, dword [esp+4] ; ecx = voice
bt dword [su_polyphony_bitmask],ecx ; if voice bit of su_polyphonism not set
mov [_SP+PTRSIZE*2], WRK ; update stack
mov ecx, [_SP+PTRSIZE] ; ecx = voice
apply bt dword,su_polyphony_bitmask,{,ecx} ; if voice bit of su_polyphonism not set
jnc su_op_advance_next_instrument ; goto next_instrument
mov VAL, dword [esp+12] ; rollback to where we were earlier
mov COM, dword [esp+16]
mov VAL, PTRWORD [_SP+PTRSIZE*3] ; rollback to where we were earlier
mov COM, PTRWORD [_SP+PTRSIZE*4]
jmp short su_op_advance_finish
su_op_advance_next_instrument:
mov dword [esp+12], VAL ; save current VAL as a checkpoint
mov dword [esp+16], COM ; save current COM as a checkpoint
mov PTRWORD [_SP+PTRSIZE*3], VAL ; save current VAL as a checkpoint
mov PTRWORD [_SP+PTRSIZE*4], COM ; save current COM as a checkpoint
su_op_advance_finish:
inc dword [esp+4]
inc PTRWORD [_SP+PTRSIZE]
ret
%else
EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
mov WRK, dword [esp+8] ; WRK = wrkptr
add WRK, su_voice.size ; move to next voice
mov dword [esp+8], WRK ; update stack
inc dword [esp+4] ; voice++
ret
EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
mov WRK, PTRWORD [_SP+PTRSIZE*2] ; WRK = wrkptr
add WRK, su_voice.size ; move to next voice
mov PTRWORD [_SP+PTRSIZE*2], WRK ; update stack
inc PTRWORD [_SP+PTRSIZE] ; voice++
ret
%endif
;-------------------------------------------------------------------------------
@ -56,18 +54,18 @@ EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
SECT_TEXT(suspeed)
EXPORT MANGLE_FUNC(su_op_speed,0)
fsub dword [c_0_5] ; s-.5
apply fsub dword, c_0_5 ; s-.5
fadd st0, st0 ; 2*s-1
fmul dword [c_bpmscale] ; (2*s-1)*64/24, let's call this p from now on
apply fmul dword, c_bpmscale ; (2*s-1)*64/24, let's call this p from now on
call MANGLE_FUNC(su_power,0) ; 2^p, this is how many ticks we should be taking
fld1 ; 1 2^p
fsubp st1, st0 ; 2^p-1, the player is advancing 1 tick by its own
fadd dword [WRK+su_speed_wrk.remainder] ; t+2^p-1, t is the remainder from previous rounds as ticks have to be rounded to 1
push eax
fist dword [esp] ; Main stack: k=int(t+2^p-1)
fisub dword [esp] ; t+2^p-1-k, the remainder
pop eax
add dword [esp+24], eax ; add the whole ticks to song tick count, [esp+24] is the current tick in the row
push _AX
fist dword [_SP] ; Main stack: k=int(t+2^p-1)
fisub dword [_SP] ; t+2^p-1-k, the remainder
pop _AX
add dword [_SP+6*PTRSIZE], eax ; add the whole ticks to song tick count, [esp+24] is the current tick in the row
fstp dword [WRK+su_speed_wrk.remainder] ; save the remainder for future
ret

View File

@ -6,16 +6,16 @@
SECT_TEXT(suopout)
EXPORT MANGLE_FUNC(su_op_out,0) ; l r
mov eax, su_synth_obj + su_synth.left
%ifdef INCLUDE_STEREO_OUT
jnc su_op_out_mono
call su_op_out_mono
add eax, 4
su_op_out_mono:
%endif
fmul dword [edx+su_out_ports.gain] ; g*l
fadd dword [eax] ; g*l+o
fstp dword [eax] ; o'=g*l+o
mov _AX, PTRWORD su_synth_obj + su_synth.left
%ifdef INCLUDE_STEREO_OUT
jnc su_op_out_mono
call su_op_out_mono
add _AX, 4
su_op_out_mono:
%endif
fmul dword [INP+su_out_ports.gain] ; g*l
fadd dword [_AX] ; g*l+o
fstp dword [_AX] ; o'=g*l+o
ret
%endif ; SU_OUT_ID > -1
@ -38,33 +38,33 @@ EXPORT MANGLE_FUNC(su_op_send,0)
lodsw
%ifdef INCLUDE_STEREO_SEND
jnc su_op_send_mono
mov edi, eax
inc eax ; send the right channel first
mov _DI, _AX
inc _AX ; send the right channel first
fxch ; r l
call su_op_send_mono ; (r) l
mov eax, edi ; move back to original address
test eax, SEND_POP ; if r was not popped and is still in the stack
mov _AX, _DI ; move back to original address
test _AX, SEND_POP ; if r was not popped and is still in the stack
jnz su_op_send_mono
fxch ; swap them back: l r
su_op_send_mono:
%endif
%ifdef INCLUDE_GLOBAL_SEND
test eax, SEND_GLOBAL
test _AX, SEND_GLOBAL
jz su_op_send_skipglobal
mov ecx, su_synth_obj - su_unit.size
mov _CX, PTRWORD su_synth_obj - su_unit.size
su_op_send_skipglobal:
%endif
test eax, SEND_POP ; if the SEND_POP bit is not set
test _AX, SEND_POP ; if the SEND_POP bit is not set
jnz su_op_send_skippush
fld st0 ; duplicate the signal on stack: s s
su_op_send_skippush: ; there is signal s, but maybe also another: s (s)
fld dword [edx+su_send_ports.amount] ; a l (l)
fsub dword [c_0_5] ; a-.5 l (l)
fld dword [INP+su_send_ports.amount] ; a l (l)
apply fsub dword, c_0_5 ; a-.5 l (l)
fadd st0 ; g=2*a-1 l (l)
and eax, 0x0000ffff - SEND_POP - SEND_GLOBAL ; eax = send address
and _AX, 0x0000ffff - SEND_POP - SEND_GLOBAL ; eax = send address
fmulp st1, st0 ; g*l (l)
fadd dword [ecx+su_unit.size+eax*4] ; g*l+L (l),where L is the current value
fstp dword [ecx+su_unit.size+eax*4] ; (l)
fadd dword [_CX+su_unit.size+_AX*4] ; g*l+L (l),where L is the current value
fstp dword [_CX+su_unit.size+_AX*4] ; (l)
ret
%endif ; SU_USE_SEND > -1

View File

@ -22,7 +22,7 @@ EXPORT MANGLE_FUNC(su_op_envelope,0)
su_op_envelope_mono:
%endif
kmENV_func_do:
mov eax, dword [ecx+su_unit.size-su_voice.workspace+su_voice.release] ; eax = su_instrument.release
mov eax, dword [_CX+su_unit.size-su_voice.workspace+su_voice.release] ; eax = su_instrument.release
test eax, eax ; if (eax == 0)
je kmENV_func_process ; goto process
mov dword [WRK+su_env_work.state], ENV_STATE_RELEASE ; [state]=RELEASE
@ -45,7 +45,7 @@ kmENV_func_decay:
jne short kmENV_func_release ; goto release
call su_env_map ; d x, where d=decay
fsubp st1, st0 ; x-d
fld dword [edx+su_env_ports.sustain] ; s x-d, where s=sustain
fld dword [INP+su_env_ports.sustain] ; s x-d, where s=sustain
fucomi st1 ; if (x-d>s) // is decay complete?
fcmovb st0, st1 ; x-d x-d
jnc short kmENV_func_statechange ; else goto statechange
@ -64,7 +64,7 @@ kmENV_func_leave:
fstp st1 ; x', where x' is the new value
fst dword [WRK+su_env_work.level] ; [level]=x'
kmENV_func_leave2:
fmul dword [edx+su_env_ports.gain] ; [gain]*x'
fmul dword [INP+su_env_ports.gain] ; [gain]*x'
ret
%endif ; SU_USE_ENVELOPE
@ -83,9 +83,9 @@ EXPORT MANGLE_FUNC(su_op_noise,0)
su_op_noise_mono:
%endif
call MANGLE_FUNC(FloatRandomNumber,0)
fld dword [edx+su_noise_ports.shape]
fld dword [INP+su_noise_ports.shape]
call su_waveshaper
fld dword [edx+su_noise_ports.gain]
fld dword [INP+su_noise_ports.gain]
fmulp st1, st0
ret
@ -102,8 +102,8 @@ SECT_TEXT(suoscill)
EXPORT MANGLE_FUNC(su_op_oscillat,0)
lodsb ; load the flags
fld dword [edx+su_osc_ports.detune] ; e, where e is the detune [0,1]
fsub dword [c_0_5] ; e-.5
fld dword [INP+su_osc_ports.detune] ; e, where e is the detune [0,1]
apply fsub dword,c_0_5 ; e-.5
fadd st0, st0 ; d=2*e-.5, where d is the detune [-1,1]
%ifdef INCLUDE_STEREO_OSCILLAT
jnc su_op_oscillat_mono
@ -115,49 +115,49 @@ EXPORT MANGLE_FUNC(su_op_oscillat,0)
su_op_oscillat_mono:
%endif
%ifdef INCLUDE_UNISONS
pushad ; push eax, WRK, WRK would suffice but this is shorter
push_registers _AX, WRK, _AX
fldz ; 0 d
fxch ; d a=0, "accumulated signal"
su_op_oscillat_unison_loop:
fst dword [esp] ; save the current detune, d. We could keep it in fpu stack but it was getting big.
fst dword [_SP] ; save the current detune, d. We could keep it in fpu stack but it was getting big.
call su_op_oscillat_single ; s a
faddp st1, st0 ; a+=s
test al, UNISON4
je su_op_oscillat_unison_out
je su_op_oscillat_unison_out
add WRK, 8
fld dword [edx+su_osc_ports.phaseofs] ; p s
fadd dword [c_i12] ; p s, add some little phase offset to unison oscillators so they don't start in sync
fstp dword [edx+su_osc_ports.phaseofs] ; s note that this changes the phase for second, possible stereo run. That's probably ok
fld dword [esp] ; d s
fmul dword [c_0_5] ; .5*d s // negate and halve the detune of each oscillator
fld dword [INP+su_osc_ports.phaseofs] ; p s
apply fadd dword, c_i12 ; p s, add some little phase offset to unison oscillators so they don't start in sync
fstp dword [INP+su_osc_ports.phaseofs] ; s note that this changes the phase for second, possible stereo run. That's probably ok
fld dword [_SP] ; d s
apply fmul dword, c_0_5 ; .5*d s // negate and halve the detune of each oscillator
fchs ; -.5*d s // negate and halve the detune of each oscillator
dec eax
jmp short su_op_oscillat_unison_loop
su_op_oscillat_unison_out:
popad ; similarly, pop WRK, WRK, eax would suffice
pop_registers _AX, WRK, _AX
ret
su_op_oscillat_single:
%endif
fld dword [edx+su_osc_ports.transpose]
fsub dword [c_0_5]
fdiv dword [c_i128]
fld dword [INP+su_osc_ports.transpose]
apply fsub dword,c_0_5
apply fdiv dword,c_i128
faddp st1
test al, byte LFO
jnz su_op_oscillat_skipnote
fiadd dword [ecx+su_unit.size-su_voice.workspace+su_voice.note] ; // st0 is note, st1 is t+d offset
fiadd dword [_CX+su_unit.size-su_voice.workspace+su_voice.note] ; // st0 is note, st1 is t+d offset
su_op_oscillat_skipnote:
fmul dword [c_i12]
apply fmul dword,c_i12
call MANGLE_FUNC(su_power,0)
test al, byte LFO
jz short su_op_oscillat_normalize_note
fmul dword [c_lfo_normalize] ; // st0 is now frequency for lfo
apply fmul dword,c_lfo_normalize ; // st0 is now frequency for lfo
jmp short su_op_oscillat_normalized
su_op_oscillat_normalize_note:
fmul dword [c_freq_normalize] ; // st0 is now frequency
apply fmul dword,c_freq_normalize ; // st0 is now frequency
su_op_oscillat_normalized:
fadd dword [WRK+su_osc_wrk.phase]
fst dword [WRK+su_osc_wrk.phase]
fadd dword [edx+su_osc_ports.phaseofs]
fadd dword [INP+su_osc_ports.phaseofs]
%ifdef INCLUDE_SAMPLES
test al, byte SAMPLE
jz short su_op_oscillat_not_sample
@ -170,7 +170,7 @@ su_op_oscillat_not_sample:
fxch
fprem
fstp st1
fld dword [edx+su_osc_ports.color] ; // c p
fld dword [INP+su_osc_ports.color] ; // c p
; every oscillator test included if needed
%ifdef INCLUDE_SINE
test al, byte SINE
@ -199,10 +199,10 @@ su_op_oscillat_not_gate:
%endif
su_op_oscillat_shaping:
; finally, shape the oscillator and apply gain
fld dword [edx+su_osc_ports.shape]
fld dword [INP+su_osc_ports.shape]
call su_waveshaper
su_op_oscillat_gain:
fld dword [edx+su_osc_ports.gain]
fld dword [INP+su_osc_ports.gain]
fmulp st1, st0
ret
%define SU_INCLUDE_WAVESHAPER
@ -281,12 +281,12 @@ SECT_TEXT(sugate)
su_oscillat_gate:
fxch ; p c
fstp st1 ; p
fmul dword [c_16] ; 16*p
push eax
push eax
fistp dword [esp] ; s=int(16*p), stack empty
apply fmul dword, c_16 ; 16*p
push _AX
push _AX
fistp dword [_SP] ; s=int(16*p), stack empty
fld1 ; 1
pop eax
pop _AX
and al, 0xf ; ax=int(16*p) & 15, stack: 1
bt word [VAL-4],ax ; if bit ax of the gate word is set
jc go4kVCO_gate_bit ; goto gate_bit
@ -294,10 +294,10 @@ su_oscillat_gate:
go4kVCO_gate_bit: ; stack: 0/1, let's call it x
fld dword [WRK+su_osc_wrk.gatestate] ; g x, g is gatestate, x is the input to this filter 0/1
fsub st1 ; g-x x
fmul dword [c_dc_const] ; c(g-x) x
apply fmul dword,c_dc_const ; c(g-x) x
faddp st1, st0 ; x+c(g-x)
fst dword [WRK+su_osc_wrk.gatestate] ; g'=x+c(g-x)
pop eax ; Another way to see this (c~0.996)
pop _AX ; Another way to see this (c~0.996)
ret ; g'=cg+(1-c)x
; This is a low-pass to smooth the gate transitions
@ -321,26 +321,26 @@ SECT_DATA(suconst)
SECT_TEXT(suoscsam)
su_oscillat_sample: ; p
pushad ; edx must be saved, eax & ecx if this is stereo osc
push edx
push_registers _AX,_DX,_CX,_BX ; edx must be saved, eax & ecx if this is stereo osc
push _AX
mov al, byte [VAL-4] ; reuse "color" as the sample number
lea edi, [MANGLE_DATA(su_sample_offsets) + eax*8] ; edi points now to the sample table entry
fmul dword [c_samplefreq_scaling] ; p*r
fistp dword [esp]
pop edx ; edx is now the sample number
movzx ebx, word [edi + su_sample_offset.loopstart] ; ecx = loopstart
apply {lea _DI,}, MANGLE_DATA(su_sample_offsets), _AX*8,{} ; edi points now to the sample table entry
apply fmul dword, c_samplefreq_scaling ; p*r
fistp dword [_SP]
pop _DX ; edx is now the sample number
movzx ebx, word [_DI + su_sample_offset.loopstart] ; ecx = loopstart
sub edx, ebx ; if sample number < loop start
jl su_oscillat_sample_not_looping ; then we're not looping yet
mov eax, edx ; eax = sample number
movzx ecx, word [edi + su_sample_offset.looplength] ; edi is now the loop length
movzx ecx, word [_DI + su_sample_offset.looplength] ; edi is now the loop length
xor edx, edx ; div wants edx to be empty
div ecx ; edx is now the remainder
su_oscillat_sample_not_looping:
add edx, ebx ; sampleno += loopstart
add edx, dword [edi + su_sample_offset.start]
fild word [MANGLE_DATA(su_sample_table) + edx*2]
fdiv dword [c_32767]
popad
add edx, dword [_DI + su_sample_offset.start]
apply fild word, MANGLE_DATA(su_sample_table), _DX*2,{}
apply fdiv dword, c_32767
pop_registers _AX,_DX,_CX,_BX
ret
SECT_DATA(suconst)
@ -369,8 +369,8 @@ EXPORT MANGLE_FUNC(su_op_loadval,0)
call su_op_loadval_mono
su_op_loadval_mono:
%endif
fld dword [edx+su_load_val_ports.value] ; v
fsub dword [c_0_5] ; v-.5
fld dword [INP+su_load_val_ports.value] ; v
apply fsub dword, c_0_5
fadd st0 ; 2*v-1
ret
@ -388,18 +388,18 @@ su_op_loadval_mono:
SECT_TEXT(sureceiv)
EXPORT MANGLE_FUNC(su_op_receive,0)
lea ecx, dword [WRK+su_unit.ports]
lea _CX, [WRK+su_unit.ports]
%ifdef INCLUDE_STEREO_RECEIVE
jnc su_op_receive_mono
xor eax,eax
fld dword [ecx+su_receive_ports.right]
mov dword [ecx+su_receive_ports.right],eax
fld dword [_CX+su_receive_ports.right]
mov dword [_CX+su_receive_ports.right],eax
su_op_receive_mono:
%else
xor eax,eax
%endif
fld dword [ecx+su_receive_ports.left]
mov dword [ecx+su_receive_ports.left],eax
fld dword [_CX+su_receive_ports.left]
mov dword [_CX+su_receive_ports.left],eax
ret
%endif ; RECEIVE_ID > -1