mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 13:04:25 -04:00
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:
@ -23,6 +23,30 @@
|
|||||||
"ctestCommandArgs": "",
|
"ctestCommandArgs": "",
|
||||||
"inheritEnvironments": [ "msvc_x86" ],
|
"inheritEnvironments": [ "msvc_x86" ],
|
||||||
"variables": []
|
"variables": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "x64-Debug",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"configurationType": "Debug",
|
||||||
|
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||||
|
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||||
|
"cmakeCommandArgs": "",
|
||||||
|
"buildCommandArgs": "-v",
|
||||||
|
"ctestCommandArgs": "",
|
||||||
|
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||||
|
"variables": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "x64-Release",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"configurationType": "RelWithDebInfo",
|
||||||
|
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||||
|
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||||
|
"cmakeCommandArgs": "",
|
||||||
|
"buildCommandArgs": "-v",
|
||||||
|
"ctestCommandArgs": "",
|
||||||
|
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||||
|
"variables": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -77,6 +77,9 @@ New features since fork
|
|||||||
detuned and added up to together. Great for trance leads (supersaw). Unison
|
detuned and added up to together. Great for trance leads (supersaw). Unison
|
||||||
of up to 4, or 8 if you make stereo unison oscillator and add up both left
|
of up to 4, or 8 if you make stereo unison oscillator and add up both left
|
||||||
and right channels. See [this example](tests/test_oscillat_unison.asm).
|
and right channels. See [this example](tests/test_oscillat_unison.asm).
|
||||||
|
- **Supports 32 and 64 bit builds**. The 64-bit version is done with minimal
|
||||||
|
changes to get it work, mainly for the future prospect of running the MIDI
|
||||||
|
instrument in 64-bit mode. All the tests are passing so it seems to work.
|
||||||
|
|
||||||
Future goals
|
Future goals
|
||||||
------------
|
------------
|
||||||
@ -90,7 +93,6 @@ Future goals
|
|||||||
case the signal entering skip and the signal leaving out are both close to
|
case the signal entering skip and the signal leaving out are both close to
|
||||||
zero.
|
zero.
|
||||||
- **Even more opcodes**. Maybe an equalizer? DC-offset removal?
|
- **Even more opcodes**. Maybe an equalizer? DC-offset removal?
|
||||||
- **Support for 64-bit targets**.
|
|
||||||
- **Browser-based GUI and MIDI instrument**. Modern browsers support WebMIDI,
|
- **Browser-based GUI and MIDI instrument**. Modern browsers support WebMIDI,
|
||||||
WebAudio and, most importantly, they are cross-platform and come installed
|
WebAudio and, most importantly, they are cross-platform and come installed
|
||||||
on pretty much any computer. The only thing needed is to be able to
|
on pretty much any computer. The only thing needed is to be able to
|
||||||
|
@ -70,8 +70,8 @@ EXPORT MANGLE_FUNC(su_op_loadnote,0)
|
|||||||
call su_op_loadnote_mono
|
call su_op_loadnote_mono
|
||||||
su_op_loadnote_mono:
|
su_op_loadnote_mono:
|
||||||
%endif
|
%endif
|
||||||
fild dword [ecx+su_unit.size-su_voice.workspace+su_voice.note]
|
fild dword [_CX+su_unit.size-su_voice.workspace+su_voice.note]
|
||||||
fmul dword [c_i128]
|
apply fmul dword, c_i128
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif
|
%endif
|
||||||
|
@ -14,7 +14,7 @@ EXPORT MANGLE_FUNC(su_op_distort,0)
|
|||||||
call su_effects_stereohelper
|
call su_effects_stereohelper
|
||||||
%define INCLUDE_EFFECTS_STEREOHELPER
|
%define INCLUDE_EFFECTS_STEREOHELPER
|
||||||
%endif
|
%endif
|
||||||
fld dword [edx+su_distort_ports.drive]
|
fld dword [INP+su_distort_ports.drive]
|
||||||
%define SU_INCLUDE_WAVESHAPER
|
%define SU_INCLUDE_WAVESHAPER
|
||||||
; flow into waveshaper
|
; flow into waveshaper
|
||||||
%endif
|
%endif
|
||||||
@ -25,7 +25,7 @@ su_waveshaper:
|
|||||||
call su_clip
|
call su_clip
|
||||||
fxch ; a x' (from now on just called x)
|
fxch ; a x' (from now on just called x)
|
||||||
fld st0 ; a a 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
|
fadd st0 ; 2*a-1 a x
|
||||||
fld st2 ; x 2*a-1 a x
|
fld st2 ; x 2*a-1 a x
|
||||||
fabs ; abs(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
|
call su_effects_stereohelper
|
||||||
%define INCLUDE_EFFECTS_STEREOHELPER
|
%define INCLUDE_EFFECTS_STEREOHELPER
|
||||||
%endif
|
%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
|
fmul st0, st0 ; f^2 x
|
||||||
fchs ; -f^2 x
|
fchs ; -f^2 x
|
||||||
fadd dword [WRK+su_hold_wrk.phase] ; p-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
|
fst dword [WRK+su_hold_wrk.phase] ; p <- p-f^2
|
||||||
fldz ; 0 p x
|
fldz ; 0 p x
|
||||||
fucomip st1 ; 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
|
jc short su_op_hold_holding ; if (0 < p) goto holding
|
||||||
fld1 ; 1 x
|
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
|
fstp dword [WRK+su_hold_wrk.phase] ; x
|
||||||
fst dword [WRK+su_hold_wrk.holdval] ; save holded value
|
fst dword [WRK+su_hold_wrk.holdval] ; save holded value
|
||||||
ret ; x
|
ret ; x
|
||||||
@ -85,10 +85,10 @@ EXPORT MANGLE_FUNC(su_op_crush,0)
|
|||||||
%ifdef INCLUDE_STEREO_CRUSH
|
%ifdef INCLUDE_STEREO_CRUSH
|
||||||
call su_effects_stereohelper
|
call su_effects_stereohelper
|
||||||
%define INCLUDE_EFFECTS_STEREOHELPER
|
%define INCLUDE_EFFECTS_STEREOHELPER
|
||||||
%endif
|
%endif
|
||||||
fdiv dword [edx+su_crush_ports.resolution]
|
fdiv dword [INP+su_crush_ports.resolution]
|
||||||
frndint
|
frndint
|
||||||
fmul dword [edx+su_crush_ports.resolution]
|
fmul dword [INP+su_crush_ports.resolution]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif ; CRUSH_ID > -1
|
%endif ; CRUSH_ID > -1
|
||||||
@ -101,15 +101,15 @@ EXPORT MANGLE_FUNC(su_op_crush,0)
|
|||||||
SECT_TEXT(sugain)
|
SECT_TEXT(sugain)
|
||||||
%ifdef INCLUDE_STEREO_GAIN
|
%ifdef INCLUDE_STEREO_GAIN
|
||||||
EXPORT MANGLE_FUNC(su_op_gain,0)
|
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
|
jnc su_op_gain_mono
|
||||||
fmul st2, st0 ; g l r/g
|
fmul st2, st0 ; g l r/g
|
||||||
su_op_gain_mono:
|
su_op_gain_mono:
|
||||||
fmulp st1, st0 ; l/g (r/)
|
fmulp st1, st0 ; l/g (r/)
|
||||||
ret
|
ret
|
||||||
%else
|
%else
|
||||||
EXPORT MANGLE_FUNC(su_op_gain,0)
|
EXPORT MANGLE_FUNC(su_op_gain,0)
|
||||||
fmul dword [edx+su_gain_ports.gain]
|
fmul dword [INP+su_gain_ports.gain]
|
||||||
ret
|
ret
|
||||||
%endif
|
%endif
|
||||||
%endif ; GAIN_ID > -1
|
%endif ; GAIN_ID > -1
|
||||||
@ -122,7 +122,7 @@ SECT_TEXT(sugain)
|
|||||||
SECT_TEXT(suingain)
|
SECT_TEXT(suingain)
|
||||||
%ifdef INCLUDE_STEREO_INVGAIN
|
%ifdef INCLUDE_STEREO_INVGAIN
|
||||||
EXPORT MANGLE_FUNC(su_op_invgain,0)
|
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
|
jnc su_op_invgain_mono
|
||||||
fdiv st2, st0 ; g l r/g
|
fdiv st2, st0 ; g l r/g
|
||||||
su_op_invgain_mono:
|
su_op_invgain_mono:
|
||||||
@ -130,7 +130,7 @@ SECT_TEXT(suingain)
|
|||||||
ret
|
ret
|
||||||
%else
|
%else
|
||||||
EXPORT MANGLE_FUNC(su_op_invgain,0)
|
EXPORT MANGLE_FUNC(su_op_invgain,0)
|
||||||
fdiv dword [edx+su_invgain_ports.invgain]
|
fdiv dword [INP+su_invgain_ports.invgain]
|
||||||
ret
|
ret
|
||||||
%endif
|
%endif
|
||||||
%endif ; INVGAIN_ID > -1
|
%endif ; INVGAIN_ID > -1
|
||||||
@ -150,14 +150,14 @@ SECT_TEXT(sufilter)
|
|||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_op_filter,0)
|
EXPORT MANGLE_FUNC(su_op_filter,0)
|
||||||
lodsb ; load the flags to al
|
lodsb ; load the flags to al
|
||||||
%ifdef INCLUDE_STEREO_FILTER
|
%ifdef INCLUDE_STEREO_FILTER
|
||||||
call su_effects_stereohelper
|
call su_effects_stereohelper
|
||||||
%define INCLUDE_EFFECTS_STEREOHELPER
|
%define INCLUDE_EFFECTS_STEREOHELPER
|
||||||
%endif
|
%endif
|
||||||
fld dword [edx+su_filter_ports.res] ; r x
|
fld dword [INP+su_filter_ports.res] ; r x
|
||||||
fld dword [edx+su_filter_ports.freq]; f 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)
|
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
|
fmul dword [WRK+su_filter_wrk.band] ; f2*b r x
|
||||||
fadd dword [WRK+su_filter_wrk.low] ; f2*b+l 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
|
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'
|
fmul dword [WRK+su_filter_wrk.band] ; r*b x-l'
|
||||||
fsubp st1, st0 ; x-l'-r*b
|
fsubp st1, st0 ; x-l'-r*b
|
||||||
fst dword [WRK+su_filter_wrk.high] ; h'=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
|
fadd dword [WRK+su_filter_wrk.band] ; f2*h'+b
|
||||||
fstp dword [WRK+su_filter_wrk.band] ; b'=f2*h'+b
|
fstp dword [WRK+su_filter_wrk.band] ; b'=f2*h'+b
|
||||||
fldz ; 0
|
fldz ; 0
|
||||||
@ -212,9 +212,9 @@ SECT_TEXT(suclip)
|
|||||||
|
|
||||||
%if CLIP_ID > -1
|
%if CLIP_ID > -1
|
||||||
EXPORT MANGLE_FUNC(su_op_clip,0)
|
EXPORT MANGLE_FUNC(su_op_clip,0)
|
||||||
%ifdef INCLUDE_STEREO_CLIP
|
%ifdef INCLUDE_STEREO_CLIP
|
||||||
call su_effects_stereohelper
|
call su_effects_stereohelper
|
||||||
%define INCLUDE_EFFECTS_STEREOHELPER
|
%define INCLUDE_EFFECTS_STEREOHELPER
|
||||||
%endif
|
%endif
|
||||||
%define SU_INCLUDE_CLIP
|
%define SU_INCLUDE_CLIP
|
||||||
; flow into su_doclip
|
; 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...
|
jc su_op_pan_do ; this time, if this is mono op...
|
||||||
fld st0 ; ...we duplicate the mono into stereo first
|
fld st0 ; ...we duplicate the mono into stereo first
|
||||||
su_op_pan_do:
|
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
|
fld1 ; 1 p l r
|
||||||
fsub st1 ; 1-p p l r
|
fsub st1 ; 1-p p l r
|
||||||
fmulp st2 ; p (1-p)*l r
|
fmulp st2 ; p (1-p)*l r
|
||||||
@ -265,7 +265,7 @@ su_op_pan_do:
|
|||||||
%else ; ifndef INCLUDE_STEREO_PAN
|
%else ; ifndef INCLUDE_STEREO_PAN
|
||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_op_pan,0)
|
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
|
fmul st1 ; p*s s
|
||||||
fsub st1, st0 ; p*s s-p*s
|
fsub st1, st0 ; p*s s-p*s
|
||||||
; Equal to
|
; Equal to
|
||||||
@ -288,7 +288,7 @@ su_effects_stereohelper:
|
|||||||
jnc su_effects_stereohelper_mono ; carry is still the stereo bit
|
jnc su_effects_stereohelper_mono ; carry is still the stereo bit
|
||||||
add WRK, 16
|
add WRK, 16
|
||||||
fxch ; r l
|
fxch ; r l
|
||||||
call dword [esp] ; call whoever called me...
|
call [_SP] ; call whoever called me...
|
||||||
fxch ; l r
|
fxch ; l r
|
||||||
sub WRK, 16 ; move WRK back to where it was
|
sub WRK, 16 ; move WRK back to where it was
|
||||||
su_effects_stereohelper_mono:
|
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
|
add edi, eax ; the second delay is done with the delay time index added by count
|
||||||
su_op_delay_mono:
|
su_op_delay_mono:
|
||||||
%endif
|
%endif
|
||||||
pushad
|
push_registers _AX, _CX, _BX, WRK, _SI, _DI
|
||||||
mov ebx, edi; ugly register juggling, refactor
|
mov ebx, edi; ugly register juggling, refactor
|
||||||
%ifdef DELAY_NOTE_SYNC
|
%ifdef DELAY_NOTE_SYNC
|
||||||
test ebx, ebx ; note s
|
test ebx, ebx ; note s
|
||||||
jne su_op_delay_skipnotesync
|
jne su_op_delay_skipnotesync
|
||||||
fld1
|
fld1
|
||||||
fild dword [ecx+su_unit.size-su_voice.workspace+su_voice.note]
|
fild dword [_CX+su_unit.size-su_voice.workspace+su_voice.note]
|
||||||
fmul dword [c_i12]
|
apply fmul dword, c_i12
|
||||||
call MANGLE_FUNC(su_power,0)
|
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
|
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:
|
su_op_delay_skipnotesync:
|
||||||
%endif
|
%endif
|
||||||
kmDLL_func_process:
|
kmDLL_func_process:
|
||||||
mov ecx, eax ;// ecx is the number of parallel delays
|
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
|
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
|
fxch ; x dr*x
|
||||||
fmul dword [edx+su_delay_ports.pregain] ; p*x dr*x
|
fmul dword [INP+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^2*x dr*x
|
||||||
|
|
||||||
kmDLL_func_loop:
|
kmDLL_func_loop:
|
||||||
mov edi, dword [WRK + su_delayline_wrk.time]
|
mov edi, dword [WRK + su_delayline_wrk.time]
|
||||||
inc edi
|
inc edi
|
||||||
and edi, MAX_DELAY-1
|
and edi, MAX_DELAY-1
|
||||||
mov dword [WRK + su_delayline_wrk.time],edi
|
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
|
mov eax, edi
|
||||||
sub eax, esi
|
sub eax, esi
|
||||||
and eax, MAX_DELAY-1
|
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
|
;// add comb output to current output
|
||||||
fadd st2, st0 ; s p^2*x dr*x+s
|
fadd st2, st0 ; s p^2*x dr*x+s
|
||||||
fld1 ; 1 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
|
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
|
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
|
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
|
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
|
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
|
inc ebx ;// go to next delay lenkmh index
|
||||||
add WRK, su_delayline_wrk.size ;// go to next delay
|
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
|
loopne kmDLL_func_loop
|
||||||
fstp st0 ; dr*x+s1+s2+s3+...
|
fstp st0 ; dr*x+s1+s2+s3+...
|
||||||
; DC-filtering
|
; 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
|
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
|
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
|
fsub dword [WRK+su_delayline_wrk.dcin] ; c*o-i s
|
||||||
fxch ; s c*o-i
|
fxch ; s c*o-i
|
||||||
fst dword [WRK+su_delayline_wrk.dcin] ; i'=s, s c*o-i
|
fst dword [WRK+su_delayline_wrk.dcin] ; i'=s, s c*o-i
|
||||||
faddp st1 ; s+c*o-i
|
faddp st1 ; s+c*o-i
|
||||||
fadd dword [c_0_5] ;// add and sub small offset to prevent denormalization
|
apply fadd dword, c_0_5 ;// add and sub small offset to prevent denormalization
|
||||||
fsub dword [c_0_5]
|
apply fsub dword, c_0_5
|
||||||
fst dword [WRK+su_delayline_wrk.dcout] ; o'=s+c*o-i
|
fst dword [WRK+su_delayline_wrk.dcout] ; o'=s+c*o-i
|
||||||
popad
|
pop_registers _AX, _CX, _BX, WRK, _SI, _DI
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
@ -394,7 +394,8 @@ kmDLL_func_loop:
|
|||||||
SECT_BSS(sudelbuf)
|
SECT_BSS(sudelbuf)
|
||||||
|
|
||||||
EXPORT MANGLE_DATA(su_delay_buffer_ofs)
|
EXPORT MANGLE_DATA(su_delay_buffer_ofs)
|
||||||
resd 1
|
RESPTR 1
|
||||||
|
|
||||||
EXPORT MANGLE_DATA(su_delay_buffer)
|
EXPORT MANGLE_DATA(su_delay_buffer)
|
||||||
resb NUM_DELAY_LINES*su_delayline_wrk.size
|
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
|
fmulp st2, st0 ; l c*(x^2-l) x
|
||||||
faddp st1, 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
|
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
|
fmul st0, st0 ; t*t
|
||||||
fucomi st0, st1 ; if threshold < l'
|
fucomi st0, st1 ; if threshold < l'
|
||||||
jb su_op_compressor_compress ; then we actually do compression
|
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
|
ret ; return unity gain when we are below threshold
|
||||||
su_op_compressor_compress: ; l' x
|
su_op_compressor_compress: ; l' x
|
||||||
fdivrp st1, st0 ; t*t/l' x
|
fdivrp st1, st0 ; t*t/l' x
|
||||||
fld dword [edx+su_compres_ports.ratio] ; r t*t/l' x
|
fld dword [INP+su_compres_ports.ratio] ; r t*t/l' x
|
||||||
fmul dword [c_0_5] ; p=r/2 t*t/l' x
|
apply fmul dword, c_0_5 ; p=r/2 t*t/l' x
|
||||||
fxch ; t*t/l' p x
|
fxch ; t*t/l' p x
|
||||||
fyl2x ; p*log2(t*t/l') x
|
fyl2x ; p*log2(t*t/l') x
|
||||||
jmp MANGLE_FUNC(su_power,0) ; 2^(p*log2(t*t/l')) x
|
jmp MANGLE_FUNC(su_power,0) ; 2^(p*log2(t*t/l')) x
|
||||||
|
@ -21,31 +21,29 @@ SECT_TEXT(suopadvn)
|
|||||||
%ifdef INCLUDE_POLYPHONY
|
%ifdef INCLUDE_POLYPHONY
|
||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
|
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
|
add WRK, su_voice.size ; move to next voice
|
||||||
mov dword [esp+8], WRK ; update stack
|
mov [_SP+PTRSIZE*2], WRK ; update stack
|
||||||
mov ecx, dword [esp+4] ; ecx = voice
|
mov ecx, [_SP+PTRSIZE] ; ecx = voice
|
||||||
bt dword [su_polyphony_bitmask],ecx ; if voice bit of su_polyphonism not set
|
apply bt dword,su_polyphony_bitmask,{,ecx} ; if voice bit of su_polyphonism not set
|
||||||
jnc su_op_advance_next_instrument ; goto next_instrument
|
jnc su_op_advance_next_instrument ; goto next_instrument
|
||||||
mov VAL, dword [esp+12] ; rollback to where we were earlier
|
mov VAL, PTRWORD [_SP+PTRSIZE*3] ; rollback to where we were earlier
|
||||||
mov COM, dword [esp+16]
|
mov COM, PTRWORD [_SP+PTRSIZE*4]
|
||||||
jmp short su_op_advance_finish
|
jmp short su_op_advance_finish
|
||||||
su_op_advance_next_instrument:
|
su_op_advance_next_instrument:
|
||||||
mov dword [esp+12], VAL ; save current VAL as a checkpoint
|
mov PTRWORD [_SP+PTRSIZE*3], VAL ; save current VAL as a checkpoint
|
||||||
mov dword [esp+16], COM ; save current COM as a checkpoint
|
mov PTRWORD [_SP+PTRSIZE*4], COM ; save current COM as a checkpoint
|
||||||
su_op_advance_finish:
|
su_op_advance_finish:
|
||||||
inc dword [esp+4]
|
inc PTRWORD [_SP+PTRSIZE]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%else
|
%else
|
||||||
|
EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
|
||||||
EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
|
mov WRK, PTRWORD [_SP+PTRSIZE*2] ; WRK = wrkptr
|
||||||
mov WRK, dword [esp+8] ; WRK = wrkptr
|
add WRK, su_voice.size ; move to next voice
|
||||||
add WRK, su_voice.size ; move to next voice
|
mov PTRWORD [_SP+PTRSIZE*2], WRK ; update stack
|
||||||
mov dword [esp+8], WRK ; update stack
|
inc PTRWORD [_SP+PTRSIZE] ; voice++
|
||||||
inc dword [esp+4] ; voice++
|
ret
|
||||||
ret
|
|
||||||
|
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
@ -56,18 +54,18 @@ EXPORT MANGLE_FUNC(su_op_advance,0) ; Stack: addr voice wrkptr valptr comptr
|
|||||||
SECT_TEXT(suspeed)
|
SECT_TEXT(suspeed)
|
||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_op_speed,0)
|
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
|
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
|
call MANGLE_FUNC(su_power,0) ; 2^p, this is how many ticks we should be taking
|
||||||
fld1 ; 1 2^p
|
fld1 ; 1 2^p
|
||||||
fsubp st1, st0 ; 2^p-1, the player is advancing 1 tick by its own
|
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
|
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
|
push _AX
|
||||||
fist dword [esp] ; Main stack: k=int(t+2^p-1)
|
fist dword [_SP] ; Main stack: k=int(t+2^p-1)
|
||||||
fisub dword [esp] ; t+2^p-1-k, the remainder
|
fisub dword [_SP] ; t+2^p-1-k, the remainder
|
||||||
pop eax
|
pop _AX
|
||||||
add dword [esp+24], eax ; add the whole ticks to song tick count, [esp+24] is the current tick in the row
|
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
|
fstp dword [WRK+su_speed_wrk.remainder] ; save the remainder for future
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
@ -6,16 +6,16 @@
|
|||||||
SECT_TEXT(suopout)
|
SECT_TEXT(suopout)
|
||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_op_out,0) ; l r
|
EXPORT MANGLE_FUNC(su_op_out,0) ; l r
|
||||||
mov eax, su_synth_obj + su_synth.left
|
mov _AX, PTRWORD su_synth_obj + su_synth.left
|
||||||
%ifdef INCLUDE_STEREO_OUT
|
%ifdef INCLUDE_STEREO_OUT
|
||||||
jnc su_op_out_mono
|
jnc su_op_out_mono
|
||||||
call su_op_out_mono
|
call su_op_out_mono
|
||||||
add eax, 4
|
add _AX, 4
|
||||||
su_op_out_mono:
|
su_op_out_mono:
|
||||||
%endif
|
%endif
|
||||||
fmul dword [edx+su_out_ports.gain] ; g*l
|
fmul dword [INP+su_out_ports.gain] ; g*l
|
||||||
fadd dword [eax] ; g*l+o
|
fadd dword [_AX] ; g*l+o
|
||||||
fstp dword [eax] ; o'=g*l+o
|
fstp dword [_AX] ; o'=g*l+o
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif ; SU_OUT_ID > -1
|
%endif ; SU_OUT_ID > -1
|
||||||
@ -38,33 +38,33 @@ EXPORT MANGLE_FUNC(su_op_send,0)
|
|||||||
lodsw
|
lodsw
|
||||||
%ifdef INCLUDE_STEREO_SEND
|
%ifdef INCLUDE_STEREO_SEND
|
||||||
jnc su_op_send_mono
|
jnc su_op_send_mono
|
||||||
mov edi, eax
|
mov _DI, _AX
|
||||||
inc eax ; send the right channel first
|
inc _AX ; send the right channel first
|
||||||
fxch ; r l
|
fxch ; r l
|
||||||
call su_op_send_mono ; (r) l
|
call su_op_send_mono ; (r) l
|
||||||
mov eax, edi ; move back to original address
|
mov _AX, _DI ; move back to original address
|
||||||
test eax, SEND_POP ; if r was not popped and is still in the stack
|
test _AX, SEND_POP ; if r was not popped and is still in the stack
|
||||||
jnz su_op_send_mono
|
jnz su_op_send_mono
|
||||||
fxch ; swap them back: l r
|
fxch ; swap them back: l r
|
||||||
su_op_send_mono:
|
su_op_send_mono:
|
||||||
%endif
|
%endif
|
||||||
%ifdef INCLUDE_GLOBAL_SEND
|
%ifdef INCLUDE_GLOBAL_SEND
|
||||||
test eax, SEND_GLOBAL
|
test _AX, SEND_GLOBAL
|
||||||
jz su_op_send_skipglobal
|
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:
|
su_op_send_skipglobal:
|
||||||
%endif
|
%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
|
jnz su_op_send_skippush
|
||||||
fld st0 ; duplicate the signal on stack: s s
|
fld st0 ; duplicate the signal on stack: s s
|
||||||
su_op_send_skippush: ; there is signal s, but maybe also another: 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)
|
fld dword [INP+su_send_ports.amount] ; a l (l)
|
||||||
fsub dword [c_0_5] ; a-.5 l (l)
|
apply fsub dword, c_0_5 ; a-.5 l (l)
|
||||||
fadd st0 ; g=2*a-1 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)
|
fmulp st1, st0 ; g*l (l)
|
||||||
fadd dword [ecx+su_unit.size+eax*4] ; g*l+L (l),where L is the current value
|
fadd dword [_CX+su_unit.size+_AX*4] ; g*l+L (l),where L is the current value
|
||||||
fstp dword [ecx+su_unit.size+eax*4] ; (l)
|
fstp dword [_CX+su_unit.size+_AX*4] ; (l)
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif ; SU_USE_SEND > -1
|
%endif ; SU_USE_SEND > -1
|
||||||
|
@ -22,7 +22,7 @@ EXPORT MANGLE_FUNC(su_op_envelope,0)
|
|||||||
su_op_envelope_mono:
|
su_op_envelope_mono:
|
||||||
%endif
|
%endif
|
||||||
kmENV_func_do:
|
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)
|
test eax, eax ; if (eax == 0)
|
||||||
je kmENV_func_process ; goto process
|
je kmENV_func_process ; goto process
|
||||||
mov dword [WRK+su_env_work.state], ENV_STATE_RELEASE ; [state]=RELEASE
|
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
|
jne short kmENV_func_release ; goto release
|
||||||
call su_env_map ; d x, where d=decay
|
call su_env_map ; d x, where d=decay
|
||||||
fsubp st1, st0 ; x-d
|
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?
|
fucomi st1 ; if (x-d>s) // is decay complete?
|
||||||
fcmovb st0, st1 ; x-d x-d
|
fcmovb st0, st1 ; x-d x-d
|
||||||
jnc short kmENV_func_statechange ; else goto statechange
|
jnc short kmENV_func_statechange ; else goto statechange
|
||||||
@ -64,7 +64,7 @@ kmENV_func_leave:
|
|||||||
fstp st1 ; x', where x' is the new value
|
fstp st1 ; x', where x' is the new value
|
||||||
fst dword [WRK+su_env_work.level] ; [level]=x'
|
fst dword [WRK+su_env_work.level] ; [level]=x'
|
||||||
kmENV_func_leave2:
|
kmENV_func_leave2:
|
||||||
fmul dword [edx+su_env_ports.gain] ; [gain]*x'
|
fmul dword [INP+su_env_ports.gain] ; [gain]*x'
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif ; SU_USE_ENVELOPE
|
%endif ; SU_USE_ENVELOPE
|
||||||
@ -83,9 +83,9 @@ EXPORT MANGLE_FUNC(su_op_noise,0)
|
|||||||
su_op_noise_mono:
|
su_op_noise_mono:
|
||||||
%endif
|
%endif
|
||||||
call MANGLE_FUNC(FloatRandomNumber,0)
|
call MANGLE_FUNC(FloatRandomNumber,0)
|
||||||
fld dword [edx+su_noise_ports.shape]
|
fld dword [INP+su_noise_ports.shape]
|
||||||
call su_waveshaper
|
call su_waveshaper
|
||||||
fld dword [edx+su_noise_ports.gain]
|
fld dword [INP+su_noise_ports.gain]
|
||||||
fmulp st1, st0
|
fmulp st1, st0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@ -102,8 +102,8 @@ SECT_TEXT(suoscill)
|
|||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_op_oscillat,0)
|
EXPORT MANGLE_FUNC(su_op_oscillat,0)
|
||||||
lodsb ; load the flags
|
lodsb ; load the flags
|
||||||
fld dword [edx+su_osc_ports.detune] ; e, where e is the detune [0,1]
|
fld dword [INP+su_osc_ports.detune] ; e, where e is the detune [0,1]
|
||||||
fsub dword [c_0_5] ; e-.5
|
apply fsub dword,c_0_5 ; e-.5
|
||||||
fadd st0, st0 ; d=2*e-.5, where d is the detune [-1,1]
|
fadd st0, st0 ; d=2*e-.5, where d is the detune [-1,1]
|
||||||
%ifdef INCLUDE_STEREO_OSCILLAT
|
%ifdef INCLUDE_STEREO_OSCILLAT
|
||||||
jnc su_op_oscillat_mono
|
jnc su_op_oscillat_mono
|
||||||
@ -115,49 +115,49 @@ EXPORT MANGLE_FUNC(su_op_oscillat,0)
|
|||||||
su_op_oscillat_mono:
|
su_op_oscillat_mono:
|
||||||
%endif
|
%endif
|
||||||
%ifdef INCLUDE_UNISONS
|
%ifdef INCLUDE_UNISONS
|
||||||
pushad ; push eax, WRK, WRK would suffice but this is shorter
|
push_registers _AX, WRK, _AX
|
||||||
fldz ; 0 d
|
fldz ; 0 d
|
||||||
fxch ; d a=0, "accumulated signal"
|
fxch ; d a=0, "accumulated signal"
|
||||||
su_op_oscillat_unison_loop:
|
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
|
call su_op_oscillat_single ; s a
|
||||||
faddp st1, st0 ; a+=s
|
faddp st1, st0 ; a+=s
|
||||||
test al, UNISON4
|
test al, UNISON4
|
||||||
je su_op_oscillat_unison_out
|
je su_op_oscillat_unison_out
|
||||||
add WRK, 8
|
add WRK, 8
|
||||||
fld dword [edx+su_osc_ports.phaseofs] ; p s
|
fld dword [INP+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
|
apply 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
|
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 [esp] ; d s
|
fld dword [_SP] ; d s
|
||||||
fmul dword [c_0_5] ; .5*d s // negate and halve the detune of each oscillator
|
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
|
fchs ; -.5*d s // negate and halve the detune of each oscillator
|
||||||
dec eax
|
dec eax
|
||||||
jmp short su_op_oscillat_unison_loop
|
jmp short su_op_oscillat_unison_loop
|
||||||
su_op_oscillat_unison_out:
|
su_op_oscillat_unison_out:
|
||||||
popad ; similarly, pop WRK, WRK, eax would suffice
|
pop_registers _AX, WRK, _AX
|
||||||
ret
|
ret
|
||||||
su_op_oscillat_single:
|
su_op_oscillat_single:
|
||||||
%endif
|
%endif
|
||||||
fld dword [edx+su_osc_ports.transpose]
|
fld dword [INP+su_osc_ports.transpose]
|
||||||
fsub dword [c_0_5]
|
apply fsub dword,c_0_5
|
||||||
fdiv dword [c_i128]
|
apply fdiv dword,c_i128
|
||||||
faddp st1
|
faddp st1
|
||||||
test al, byte LFO
|
test al, byte LFO
|
||||||
jnz su_op_oscillat_skipnote
|
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:
|
su_op_oscillat_skipnote:
|
||||||
fmul dword [c_i12]
|
apply fmul dword,c_i12
|
||||||
call MANGLE_FUNC(su_power,0)
|
call MANGLE_FUNC(su_power,0)
|
||||||
test al, byte LFO
|
test al, byte LFO
|
||||||
jz short su_op_oscillat_normalize_note
|
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
|
jmp short su_op_oscillat_normalized
|
||||||
su_op_oscillat_normalize_note:
|
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:
|
su_op_oscillat_normalized:
|
||||||
fadd dword [WRK+su_osc_wrk.phase]
|
fadd dword [WRK+su_osc_wrk.phase]
|
||||||
fst 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
|
%ifdef INCLUDE_SAMPLES
|
||||||
test al, byte SAMPLE
|
test al, byte SAMPLE
|
||||||
jz short su_op_oscillat_not_sample
|
jz short su_op_oscillat_not_sample
|
||||||
@ -170,7 +170,7 @@ su_op_oscillat_not_sample:
|
|||||||
fxch
|
fxch
|
||||||
fprem
|
fprem
|
||||||
fstp st1
|
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
|
; every oscillator test included if needed
|
||||||
%ifdef INCLUDE_SINE
|
%ifdef INCLUDE_SINE
|
||||||
test al, byte SINE
|
test al, byte SINE
|
||||||
@ -199,10 +199,10 @@ su_op_oscillat_not_gate:
|
|||||||
%endif
|
%endif
|
||||||
su_op_oscillat_shaping:
|
su_op_oscillat_shaping:
|
||||||
; finally, shape the oscillator and apply gain
|
; finally, shape the oscillator and apply gain
|
||||||
fld dword [edx+su_osc_ports.shape]
|
fld dword [INP+su_osc_ports.shape]
|
||||||
call su_waveshaper
|
call su_waveshaper
|
||||||
su_op_oscillat_gain:
|
su_op_oscillat_gain:
|
||||||
fld dword [edx+su_osc_ports.gain]
|
fld dword [INP+su_osc_ports.gain]
|
||||||
fmulp st1, st0
|
fmulp st1, st0
|
||||||
ret
|
ret
|
||||||
%define SU_INCLUDE_WAVESHAPER
|
%define SU_INCLUDE_WAVESHAPER
|
||||||
@ -281,12 +281,12 @@ SECT_TEXT(sugate)
|
|||||||
su_oscillat_gate:
|
su_oscillat_gate:
|
||||||
fxch ; p c
|
fxch ; p c
|
||||||
fstp st1 ; p
|
fstp st1 ; p
|
||||||
fmul dword [c_16] ; 16*p
|
apply fmul dword, c_16 ; 16*p
|
||||||
push eax
|
push _AX
|
||||||
push eax
|
push _AX
|
||||||
fistp dword [esp] ; s=int(16*p), stack empty
|
fistp dword [_SP] ; s=int(16*p), stack empty
|
||||||
fld1 ; 1
|
fld1 ; 1
|
||||||
pop eax
|
pop _AX
|
||||||
and al, 0xf ; ax=int(16*p) & 15, stack: 1
|
and al, 0xf ; ax=int(16*p) & 15, stack: 1
|
||||||
bt word [VAL-4],ax ; if bit ax of the gate word is set
|
bt word [VAL-4],ax ; if bit ax of the gate word is set
|
||||||
jc go4kVCO_gate_bit ; goto gate_bit
|
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
|
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
|
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
|
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)
|
faddp st1, st0 ; x+c(g-x)
|
||||||
fst dword [WRK+su_osc_wrk.gatestate] ; g'=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
|
ret ; g'=cg+(1-c)x
|
||||||
; This is a low-pass to smooth the gate transitions
|
; This is a low-pass to smooth the gate transitions
|
||||||
|
|
||||||
@ -321,26 +321,26 @@ SECT_DATA(suconst)
|
|||||||
SECT_TEXT(suoscsam)
|
SECT_TEXT(suoscsam)
|
||||||
|
|
||||||
su_oscillat_sample: ; p
|
su_oscillat_sample: ; p
|
||||||
pushad ; edx must be saved, eax & ecx if this is stereo osc
|
push_registers _AX,_DX,_CX,_BX ; edx must be saved, eax & ecx if this is stereo osc
|
||||||
push edx
|
push _AX
|
||||||
mov al, byte [VAL-4] ; reuse "color" as the sample number
|
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
|
apply {lea _DI,}, MANGLE_DATA(su_sample_offsets), _AX*8,{} ; edi points now to the sample table entry
|
||||||
fmul dword [c_samplefreq_scaling] ; p*r
|
apply fmul dword, c_samplefreq_scaling ; p*r
|
||||||
fistp dword [esp]
|
fistp dword [_SP]
|
||||||
pop edx ; edx is now the sample number
|
pop _DX ; edx is now the sample number
|
||||||
movzx ebx, word [edi + su_sample_offset.loopstart] ; ecx = loopstart
|
movzx ebx, word [_DI + su_sample_offset.loopstart] ; ecx = loopstart
|
||||||
sub edx, ebx ; if sample number < loop start
|
sub edx, ebx ; if sample number < loop start
|
||||||
jl su_oscillat_sample_not_looping ; then we're not looping yet
|
jl su_oscillat_sample_not_looping ; then we're not looping yet
|
||||||
mov eax, edx ; eax = sample number
|
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
|
xor edx, edx ; div wants edx to be empty
|
||||||
div ecx ; edx is now the remainder
|
div ecx ; edx is now the remainder
|
||||||
su_oscillat_sample_not_looping:
|
su_oscillat_sample_not_looping:
|
||||||
add edx, ebx ; sampleno += loopstart
|
add edx, ebx ; sampleno += loopstart
|
||||||
add edx, dword [edi + su_sample_offset.start]
|
add edx, dword [_DI + su_sample_offset.start]
|
||||||
fild word [MANGLE_DATA(su_sample_table) + edx*2]
|
apply fild word, MANGLE_DATA(su_sample_table), _DX*2,{}
|
||||||
fdiv dword [c_32767]
|
apply fdiv dword, c_32767
|
||||||
popad
|
pop_registers _AX,_DX,_CX,_BX
|
||||||
ret
|
ret
|
||||||
|
|
||||||
SECT_DATA(suconst)
|
SECT_DATA(suconst)
|
||||||
@ -369,8 +369,8 @@ EXPORT MANGLE_FUNC(su_op_loadval,0)
|
|||||||
call su_op_loadval_mono
|
call su_op_loadval_mono
|
||||||
su_op_loadval_mono:
|
su_op_loadval_mono:
|
||||||
%endif
|
%endif
|
||||||
fld dword [edx+su_load_val_ports.value] ; v
|
fld dword [INP+su_load_val_ports.value] ; v
|
||||||
fsub dword [c_0_5] ; v-.5
|
apply fsub dword, c_0_5
|
||||||
fadd st0 ; 2*v-1
|
fadd st0 ; 2*v-1
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@ -388,18 +388,18 @@ su_op_loadval_mono:
|
|||||||
SECT_TEXT(sureceiv)
|
SECT_TEXT(sureceiv)
|
||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_op_receive,0)
|
EXPORT MANGLE_FUNC(su_op_receive,0)
|
||||||
lea ecx, dword [WRK+su_unit.ports]
|
lea _CX, [WRK+su_unit.ports]
|
||||||
%ifdef INCLUDE_STEREO_RECEIVE
|
%ifdef INCLUDE_STEREO_RECEIVE
|
||||||
jnc su_op_receive_mono
|
jnc su_op_receive_mono
|
||||||
xor eax,eax
|
xor eax,eax
|
||||||
fld dword [ecx+su_receive_ports.right]
|
fld dword [_CX+su_receive_ports.right]
|
||||||
mov dword [ecx+su_receive_ports.right],eax
|
mov dword [_CX+su_receive_ports.right],eax
|
||||||
su_op_receive_mono:
|
su_op_receive_mono:
|
||||||
%else
|
%else
|
||||||
xor eax,eax
|
xor eax,eax
|
||||||
%endif
|
%endif
|
||||||
fld dword [ecx+su_receive_ports.left]
|
fld dword [_CX+su_receive_ports.left]
|
||||||
mov dword [ecx+su_receive_ports.left],eax
|
mov dword [_CX+su_receive_ports.left],eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif ; RECEIVE_ID > -1
|
%endif ; RECEIVE_ID > -1
|
||||||
|
137
src/player.asm
137
src/player.asm
@ -1,3 +1,26 @@
|
|||||||
|
%if BITS == 32
|
||||||
|
%define BUFFER_STACK_LOC 44
|
||||||
|
%define render_prologue pushad ; stdcall & everything nonvolatile except eax, ecx, edx
|
||||||
|
%macro render_epilogue 0
|
||||||
|
popad
|
||||||
|
ret 4 ; clean the passed parameter from stack.
|
||||||
|
%endmacro
|
||||||
|
%elifidn __OUTPUT_FORMAT__,win64
|
||||||
|
%define BUFFER_STACK_LOC 48
|
||||||
|
%define render_prologue push_registers rcx,rdi,rsi,rbx,rbp ; rcx = ptr to buf. rdi,rsi,rbx,rbp nonvolatile
|
||||||
|
%macro render_epilogue 0
|
||||||
|
pop_registers rcx,rdi,rsi,rbx,rbp
|
||||||
|
ret
|
||||||
|
%endmacro
|
||||||
|
%else ; 64 bit mac & linux
|
||||||
|
%define BUFFER_STACK_LOC 48
|
||||||
|
%define render_prologue push_registers rdi,rbx,rbp ; rdi = ptr to buf. rbx & rbp nonvolatile
|
||||||
|
%macro render_epilogue 0
|
||||||
|
pop_registers rdi,rbx,rbp
|
||||||
|
ret
|
||||||
|
%endmacro
|
||||||
|
%endif
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; Uninitialized data
|
; Uninitialized data
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
@ -35,46 +58,46 @@ SECT_DATA(suconst)
|
|||||||
%macro output_sound 0
|
%macro output_sound 0
|
||||||
%ifndef SU_USE_16BIT_OUTPUT
|
%ifndef SU_USE_16BIT_OUTPUT
|
||||||
%ifndef SU_CLIP_OUTPUT ; The modern way. No need to clip; OS can do it.
|
%ifndef SU_CLIP_OUTPUT ; The modern way. No need to clip; OS can do it.
|
||||||
mov edi, dword [esp+44] ; edi containts ptr
|
mov _DI, [_SP+BUFFER_STACK_LOC] ; edi containts ptr
|
||||||
mov esi, su_synth_obj+su_synth.left
|
mov _SI, PTRWORD su_synth_obj + su_synth.left
|
||||||
movsd ; copy left channel to output buffer
|
movsd ; copy left channel to output buffer
|
||||||
movsd ; copy right channel to output buffer
|
movsd ; copy right channel to output buffer
|
||||||
mov dword [esp+44], edi ; save back the updated ptr
|
mov [_SP+BUFFER_STACK_LOC], _DI ; save back the updated ptr
|
||||||
lea edi, [esi-8]
|
lea _DI, [_SI-8]
|
||||||
xor eax,eax
|
xor eax, eax
|
||||||
stosd ; clear left channel so the VM is ready to write them again
|
stosd ; clear left channel so the VM is ready to write them again
|
||||||
stosd ; clear right channel so the VM is ready to write them again
|
stosd ; clear right channel so the VM is ready to write them again
|
||||||
%else
|
%else
|
||||||
mov esi, dword [esp+44] ; esi points to the output buffer
|
mov _SI, qword [_SP+BUFFER_STACK_LOC] ; esi points to the output buffer
|
||||||
xor ecx,ecx
|
xor _CX,_CX
|
||||||
xor eax,eax
|
xor eax,eax
|
||||||
%%loop: ; loop over two channels, left & right
|
%%loop: ; loop over two channels, left & right
|
||||||
fld dword [su_synth_obj+su_synth.left+ecx*4]
|
apply fld dword,su_synth_obj+su_synth.left,_CX*4,{}
|
||||||
call su_clip
|
call su_clip
|
||||||
fstp dword [esi]
|
fstp dword [_SI]
|
||||||
mov dword [su_synth_obj+su_synth.left+ecx*4],eax ; clear the sample so the VM is ready to write it
|
apply mov dword,su_synth_obj+su_synth.left,_CX*4,{,eax} ; clear the sample so the VM is ready to write it
|
||||||
add esi,4
|
add _SI,4
|
||||||
cmp ecx,2
|
cmp ecx,2
|
||||||
jl %%loop
|
jl %%loop
|
||||||
mov dword [esp+44], esi ; save esi back to stack
|
mov dword [_SP+BUFFER_STACK_LOC], _SI ; save esi back to stack
|
||||||
%endif
|
%endif
|
||||||
%else ; 16-bit output, always clipped. This is a bit legacy method.
|
%else ; 16-bit output, always clipped. This is a bit legacy method.
|
||||||
mov esi, dword [esp+44] ; esi points to the output buffer
|
mov _SI, [_SP+BUFFER_STACK_LOC] ; esi points to the output buffer
|
||||||
mov edi, su_synth_obj+su_synth.left
|
mov _DI, PTRWORD su_synth_obj+su_synth.left
|
||||||
mov ecx, 2
|
mov ecx, 2
|
||||||
%%loop: ; loop over two channels, left & right
|
%%loop: ; loop over two channels, left & right
|
||||||
fld dword [edi]
|
fld dword [_DI]
|
||||||
call su_clip
|
call su_clip
|
||||||
fmul dword [c_32767]
|
apply fmul dword, c_32767
|
||||||
push eax
|
push _AX
|
||||||
fistp dword [esp]
|
fistp dword [_SP]
|
||||||
pop eax
|
pop _AX
|
||||||
mov word [esi],ax ; // store integer converted right sample
|
mov word [_SI],ax ; // store integer converted right sample
|
||||||
xor eax,eax
|
xor eax,eax
|
||||||
stosd
|
stosd
|
||||||
add esi,2
|
add _SI,2
|
||||||
loop %%loop
|
loop %%loop
|
||||||
mov dword [esp+44], esi ; save esi back to stack
|
mov [_SP+BUFFER_STACK_LOC], _SI ; save esi back to stack
|
||||||
%endif
|
%endif
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|
||||||
@ -87,30 +110,29 @@ SECT_DATA(suconst)
|
|||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
SECT_TEXT(surender)
|
SECT_TEXT(surender)
|
||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_render,4) ; Stack: ptr
|
EXPORT MANGLE_FUNC(su_render,PTRSIZE) ; Stack: ptr
|
||||||
pushad ; Stack: pushad ptr
|
render_prologue
|
||||||
%ifdef INCLUDE_GMDLS
|
%ifdef INCLUDE_GMDLS
|
||||||
call su_gmdls_load
|
call su_gmdls_load
|
||||||
%endif
|
%endif
|
||||||
xor eax, eax ; ecx is the current row
|
xor eax, eax ; ecx is the current row
|
||||||
su_render_rowloop: ; loop through every row in the song
|
su_render_rowloop: ; loop through every row in the song
|
||||||
push eax ; Stack: row pushad ptr
|
push _AX ; Stack: row pushad ptr
|
||||||
call su_update_voices ; update instruments for the new row
|
call su_update_voices ; update instruments for the new row
|
||||||
xor eax, eax ; ecx is the current sample within row
|
xor eax, eax ; ecx is the current sample within row
|
||||||
su_render_sampleloop: ; loop through every sample in the row
|
su_render_sampleloop: ; loop through every sample in the row
|
||||||
push eax ; Stack: sample row pushad ptr
|
push _AX ; Stack: sample row pushad ptr
|
||||||
call MANGLE_FUNC(su_run_vm,0) ; run through the VM code
|
call MANGLE_FUNC(su_run_vm,0) ; run through the VM code
|
||||||
output_sound ; *ptr++ = left, *ptr++ = right
|
output_sound ; *ptr++ = left, *ptr++ = right
|
||||||
pop eax ; Stack: row pushad ptr
|
pop _AX ; Stack: row pushad ptr
|
||||||
inc eax
|
inc eax
|
||||||
cmp eax, SAMPLES_PER_ROW
|
cmp eax, SAMPLES_PER_ROW
|
||||||
jl su_render_sampleloop
|
jl su_render_sampleloop
|
||||||
pop eax ; Stack: pushad ptr
|
pop _AX ; Stack: pushad ptr
|
||||||
inc eax
|
inc eax
|
||||||
cmp eax, TOTAL_ROWS
|
cmp eax, TOTAL_ROWS
|
||||||
jl su_render_rowloop
|
jl su_render_rowloop
|
||||||
popad ; Stack: ptr
|
render_epilogue
|
||||||
ret 4 ; Stack emptied by ret
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; su_update_voices function: polyphonic & chord implementation
|
; su_update_voices function: polyphonic & chord implementation
|
||||||
@ -126,30 +148,30 @@ su_update_voices: ; Stack: retaddr row
|
|||||||
xor edx, edx
|
xor edx, edx
|
||||||
mov ebx, PATTERN_SIZE ; we could do xor ebx,ebx; mov bl,PATTERN_SIZE, but that would limit patternsize to 256...
|
mov ebx, PATTERN_SIZE ; we could do xor ebx,ebx; mov bl,PATTERN_SIZE, but that would limit patternsize to 256...
|
||||||
div ebx ; eax = current pattern, edx = current row in pattern
|
div ebx ; eax = current pattern, edx = current row in pattern
|
||||||
lea esi, [MANGLE_DATA(su_tracks)+eax] ; esi points to the pattern data for current track
|
apply {lea _SI,},MANGLE_DATA(su_tracks),_AX,{} ; esi points to the pattern data for current track
|
||||||
xor eax, eax ; eax is the first voice of next track
|
xor eax, eax ; eax is the first voice of next track
|
||||||
xor ebx, ebx ; ebx is the first voice of current track
|
xor ebx, ebx ; ebx is the first voice of current track
|
||||||
mov ebp, su_current_voiceno ; ebp points to the current_voiceno array
|
mov _BP, PTRWORD su_current_voiceno ; ebp points to the current_voiceno array
|
||||||
su_update_voices_trackloop:
|
su_update_voices_trackloop:
|
||||||
movzx eax, byte [esi] ; eax = current pattern
|
movzx eax, byte [_SI] ; eax = current pattern
|
||||||
imul eax, PATTERN_SIZE ; eax = offset to current pattern data
|
imul eax, PATTERN_SIZE ; eax = offset to current pattern data
|
||||||
movzx eax, byte [MANGLE_DATA(su_patterns)+eax+edx] ; eax = note
|
apply {movzx eax,byte},MANGLE_DATA(su_patterns),_AX,_DX,{} ; eax = note
|
||||||
push edx ; Stack: ptrnrow
|
push _DX ; Stack: ptrnrow
|
||||||
xor edx, edx ; edx=0
|
xor edx, edx ; edx=0
|
||||||
mov ecx, ebx ; ecx=first voice of the track to be done
|
mov ecx, ebx ; ecx=first voice of the track to be done
|
||||||
su_calculate_voices_loop: ; do {
|
su_calculate_voices_loop: ; do {
|
||||||
bt dword [su_voicetrack_bitmask],ecx ; // notice that the incs don't set carry
|
apply bt dword, su_voicetrack_bitmask,{,ecx}; // notice that the incs don't set carry
|
||||||
inc edx ; edx++ // edx=numvoices
|
inc edx ; edx++ // edx=numvoices
|
||||||
inc ecx ; ecx++ // ecx=the first voice of next track
|
inc ecx ; ecx++ // ecx=the first voice of next track
|
||||||
jc su_calculate_voices_loop ; } while bit ecx-1 of bitmask is on
|
jc su_calculate_voices_loop ; } while bit ecx-1 of bitmask is on
|
||||||
push ecx ; Stack: next_instr ptrnrow
|
push _CX ; Stack: next_instr ptrnrow
|
||||||
cmp al, HLD ; anything but hold causes action
|
cmp al, HLD ; anything but hold causes action
|
||||||
je short su_update_voices_nexttrack
|
je short su_update_voices_nexttrack
|
||||||
mov ecx, dword [ebp]
|
mov ecx, dword [_BP]
|
||||||
mov edi, ecx
|
mov edi, ecx
|
||||||
add edi, ebx
|
add edi, ebx
|
||||||
shl edi, MAX_UNITS_SHIFT + 6 ; each unit = 64 bytes and there are 1<<MAX_UNITS_SHIFT units + small header
|
shl edi, MAX_UNITS_SHIFT + 6 ; each unit = 64 bytes and there are 1<<MAX_UNITS_SHIFT units + small header
|
||||||
inc dword [su_synth_obj+su_synth.voices+edi+su_voice.release] ; set the voice currently active to release; notice that it could increment any number of times
|
apply inc dword, su_synth_obj+su_synth.voices+su_voice.release,_DI,{} ; set the voice currently active to release; notice that it could increment any number of times
|
||||||
cmp al, HLD ; if cl < HLD (no new note triggered)
|
cmp al, HLD ; if cl < HLD (no new note triggered)
|
||||||
jl su_update_voices_nexttrack ; goto nexttrack
|
jl su_update_voices_nexttrack ; goto nexttrack
|
||||||
inc ecx ; curvoice++
|
inc ecx ; curvoice++
|
||||||
@ -157,52 +179,53 @@ su_calculate_voices_loop: ; do {
|
|||||||
jl su_update_voices_skipreset
|
jl su_update_voices_skipreset
|
||||||
xor ecx,ecx ; curvoice = 0
|
xor ecx,ecx ; curvoice = 0
|
||||||
su_update_voices_skipreset:
|
su_update_voices_skipreset:
|
||||||
mov dword [ebp],ecx
|
mov dword [_BP],ecx
|
||||||
add ecx, ebx
|
add ecx, ebx
|
||||||
shl ecx, MAX_UNITS_SHIFT + 6 ; each unit = 64 bytes and there are 1<<MAX_UNITS_SHIFT units + small header
|
shl ecx, MAX_UNITS_SHIFT + 6 ; each unit = 64 bytes and there are 1<<MAX_UNITS_SHIFT units + small header
|
||||||
lea edi, [su_synth_obj+su_synth.voices+ecx]
|
apply {lea _DI,},su_synth_obj+su_synth.voices,_CX,{}
|
||||||
stosd ; save note
|
stosd ; save note
|
||||||
mov ecx, (su_voice.size - su_voice.release)/4
|
mov ecx, (su_voice.size - su_voice.release)/4
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
rep stosd ; clear the workspace of the new voice, retriggering oscillators
|
rep stosd ; clear the workspace of the new voice, retriggering oscillators
|
||||||
su_update_voices_nexttrack:
|
su_update_voices_nexttrack:
|
||||||
pop ebx ; ebx=first voice of next instrument, Stack: ptrnrow
|
pop _BX ; ebx=first voice of next instrument, Stack: ptrnrow
|
||||||
pop edx ; edx=patrnrow
|
pop _DX ; edx=patrnrow
|
||||||
add esi, MAX_PATTERNS
|
add _SI, MAX_PATTERNS
|
||||||
add ebp, 4
|
add _BP, 4
|
||||||
cmp ebp, su_current_voiceno+MAX_TRACKS*4
|
apply {cmp _BP,},su_current_voiceno,MAX_TRACKS*4,{}
|
||||||
jl short su_update_voices_trackloop
|
jl su_update_voices_trackloop
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%else ; INCLUDE_MULTIVOICE_TRACKS not defined -> one voice per track version
|
|
||||||
|
%else ; INCLUDE_MULTIVOICE_TRACKS not defined -> one voice per track ve_SIon
|
||||||
|
|
||||||
su_update_voices: ; Stack: retaddr row
|
su_update_voices: ; Stack: retaddr row
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
xor ebx, ebx
|
xor ebx, ebx
|
||||||
mov bl, PATTERN_SIZE
|
mov bl, PATTERN_SIZE
|
||||||
div ebx ; eax = current pattern, edx = current row in pattern
|
div ebx ; eax = current pattern, edx = current row in pattern
|
||||||
lea esi, [MANGLE_DATA(su_tracks)+eax] ; esi points to the pattern data for current track
|
apply {lea _SI,},MANGLE_DATA(su_tracks),_AX,{}; esi points to the pattern data for current track
|
||||||
lea edi, [su_synth_obj+su_synth.voices]
|
mov _DI, PTRWORD su_synth_obj+su_synth.voices
|
||||||
mov bl, MAX_TRACKS ; MAX_TRACKS is always <= 32 so this is ok
|
mov bl, MAX_TRACKS ; MAX_TRACKS is always <= 32 so this is ok
|
||||||
su_update_voices_trackloop:
|
su_update_voices_trackloop:
|
||||||
movzx eax, byte [esi] ; eax = current pattern
|
movzx eax, byte [_SI] ; eax = current pattern
|
||||||
imul eax, PATTERN_SIZE ; eax = offset to current pattern data
|
imul eax, PATTERN_SIZE ; eax = offset to current pattern data
|
||||||
movzx eax, byte [MANGLE_DATA(su_patterns)+eax+edx] ; ecx = note
|
apply {movzx eax, byte}, MANGLE_DATA(su_patterns), _AX, _DX, {} ; ecx = note
|
||||||
cmp al, HLD ; anything but hold causes action
|
cmp al, HLD ; anything but hold causes action
|
||||||
je short su_update_voices_nexttrack
|
je short su_update_voices_nexttrack
|
||||||
inc dword [edi+su_voice.release] ; set the voice currently active to release; notice that it could increment any number of times
|
inc dword [_DI+su_voice.release] ; set the voice currently active to release; notice that it could increment any number of times
|
||||||
cmp al, HLD
|
cmp al, HLD
|
||||||
jl su_update_voices_nexttrack ; if cl < HLD (no new note triggered) goto nexttrack
|
jl su_update_voices_nexttrack ; if cl < HLD (no new note triggered) goto nexttrack
|
||||||
su_update_voices_retrigger:
|
su_update_voices_retrigger:
|
||||||
stosd ; save note
|
stosd ; save note
|
||||||
mov ecx, (su_voice.size - su_voice.release)/4 ; could be xor ecx, ecx; mov ch,...>>8, but will it actually be smaller after compression?
|
mov ecx, (su_voice.size - su_voice.release)/4 ; could be xor ecx, ecx; mov ch,...>>8, but will it actually be smaller after compression?
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
rep stosd ; clear the workspace of the new voice, retriggering oscillators
|
rep stosd ; clear the workspace of the new voice, retriggering oscillators
|
||||||
jmp short su_update_voices_skipadd
|
jmp short su_update_voices_skipadd
|
||||||
su_update_voices_nexttrack:
|
su_update_voices_nexttrack:
|
||||||
add edi, su_voice.size
|
add _DI, su_voice.size
|
||||||
su_update_voices_skipadd:
|
su_update_voices_skipadd:
|
||||||
add esi, MAX_PATTERNS
|
add _SI, MAX_PATTERNS
|
||||||
dec ebx
|
dec ebx
|
||||||
jnz short su_update_voices_trackloop
|
jnz short su_update_voices_trackloop
|
||||||
ret
|
ret
|
||||||
|
193
src/sointu.asm
193
src/sointu.asm
@ -1,6 +1,97 @@
|
|||||||
%define WRK ebp ; // alias for unit workspace
|
%if BITS == 64
|
||||||
%define VAL esi ; // alias for unit values (transformed/untransformed)
|
%define WRK rbp ; alias for unit workspace
|
||||||
%define COM ebx ; // alias for instrument opcodes
|
%define VAL rsi ; alias for unit values (transformed/untransformed)
|
||||||
|
%define COM rbx ; alias for instrument opcodes
|
||||||
|
%define INP rdx ; alias for transformed inputs
|
||||||
|
%define _AX rax ; push and offsets have to be r* on 64-bit and e* on 32-bit
|
||||||
|
%define _BX rbx
|
||||||
|
%define _CX rcx
|
||||||
|
%define _DX rdx
|
||||||
|
%define _SP rsp
|
||||||
|
%define _SI rsi
|
||||||
|
%define _DI rdi
|
||||||
|
%define _BP rbp
|
||||||
|
%define PTRSIZE 8
|
||||||
|
%define PTRWORD qword
|
||||||
|
%define RESPTR resq
|
||||||
|
%define DPTR dq
|
||||||
|
|
||||||
|
%macro apply 2
|
||||||
|
mov r9, qword %2
|
||||||
|
%1 [r9]
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro apply 3
|
||||||
|
mov r9, qword %2
|
||||||
|
%1 [r9] %3
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro apply 4
|
||||||
|
mov r9, qword %2
|
||||||
|
%1 [r9+%3] %4
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro apply 5
|
||||||
|
mov r9, qword %2
|
||||||
|
lea r9, [r9+%3]
|
||||||
|
%1 [r9+%4] %5
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro push_registers 1-*
|
||||||
|
%rep %0
|
||||||
|
push %1
|
||||||
|
%rotate 1
|
||||||
|
%endrep
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro pop_registers 1-*
|
||||||
|
%rep %0
|
||||||
|
%rotate -1
|
||||||
|
pop %1
|
||||||
|
%endrep
|
||||||
|
%endmacro
|
||||||
|
%else
|
||||||
|
%define WRK ebp ; alias for unit workspace
|
||||||
|
%define VAL esi ; alias for unit values (transformed/untransformed)
|
||||||
|
%define COM ebx ; alias for instrument opcodes
|
||||||
|
%define INP edx ; alias for transformed inputs
|
||||||
|
%define _AX eax
|
||||||
|
%define _BX ebx
|
||||||
|
%define _CX ecx
|
||||||
|
%define _DX edx
|
||||||
|
%define _SP esp
|
||||||
|
%define _SI esi
|
||||||
|
%define _DI edi
|
||||||
|
%define _BP ebp
|
||||||
|
%define PTRSIZE 4
|
||||||
|
%define PTRWORD dword
|
||||||
|
%define RESPTR resd
|
||||||
|
%define DPTR dd
|
||||||
|
|
||||||
|
%macro apply 2
|
||||||
|
%1 [%2]
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro apply 3
|
||||||
|
%1 [%2] %3
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro apply 4
|
||||||
|
%1 [%2+%3] %4
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro apply 5
|
||||||
|
%1 [%2+%3+%4] %5
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro push_registers 1-*
|
||||||
|
pushad ; in 32-bit mode, this is the easiest way to store all the registers
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro pop_registers 1-*
|
||||||
|
popad
|
||||||
|
%endmacro
|
||||||
|
%endif
|
||||||
|
|
||||||
;===============================================================================
|
;===============================================================================
|
||||||
; Uninitialized data: The one and only synth object
|
; Uninitialized data: The one and only synth object
|
||||||
@ -16,16 +107,14 @@ su_transformed_values resd 16
|
|||||||
;===============================================================================
|
;===============================================================================
|
||||||
SECT_DATA(suoptabl)
|
SECT_DATA(suoptabl)
|
||||||
|
|
||||||
su_synth_commands
|
su_synth_commands DPTR OPCODES
|
||||||
dd OPCODES
|
|
||||||
|
|
||||||
;===============================================================================
|
;===============================================================================
|
||||||
; The number of transformed parameters each opcode takes
|
; The number of transformed parameters each opcode takes
|
||||||
;===============================================================================
|
;===============================================================================
|
||||||
SECT_DATA(suparcnt)
|
SECT_DATA(suparcnt)
|
||||||
|
|
||||||
su_opcode_numparams
|
su_opcode_numparams db NUMPARAMS
|
||||||
db NUMPARAMS
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; Constants used by the common functions
|
; Constants used by the common functions
|
||||||
@ -58,34 +147,40 @@ su_polyphony_bitmask dd POLYPHONY_BITMASK ; does the next voice reuse th
|
|||||||
SECT_TEXT(surunvm)
|
SECT_TEXT(surunvm)
|
||||||
|
|
||||||
EXPORT MANGLE_FUNC(su_run_vm,0)
|
EXPORT MANGLE_FUNC(su_run_vm,0)
|
||||||
mov COM, MANGLE_DATA(su_commands) ; COM points to vm code
|
mov COM, PTRWORD MANGLE_DATA(su_commands) ; COM points to vm code
|
||||||
mov VAL, MANGLE_DATA(su_params) ; VAL points to unit params
|
mov VAL, PTRWORD MANGLE_DATA(su_params) ; VAL points to unit params
|
||||||
; su_unit.size will be added back before WRK is used
|
; su_unit.size will be added back before WRK is used
|
||||||
mov WRK, su_synth_obj + su_synth.voices + su_voice.workspace - su_unit.size
|
mov WRK, PTRWORD su_synth_obj + su_synth.voices + su_voice.workspace - su_unit.size
|
||||||
push COM ; Stack: COM
|
push COM ; Stack: COM
|
||||||
push VAL ; Stack: VAL COM
|
push VAL ; Stack: VAL COM
|
||||||
push WRK ; Stack: WRK VAL COM
|
push WRK ; Stack: WRK VAL COM
|
||||||
%if DELAY_ID > -1
|
%if DELAY_ID > -1
|
||||||
mov dword [MANGLE_DATA(su_delay_buffer_ofs)], MANGLE_DATA(su_delay_buffer) ; reset delaywrk to first delayline
|
%if BITS == 64 ; TODO: find a way to do this with a macro
|
||||||
|
mov r9,PTRWORD MANGLE_DATA(su_delay_buffer_ofs)
|
||||||
|
mov _AX,PTRWORD MANGLE_DATA(su_delay_buffer)
|
||||||
|
mov qword [r9],_AX ; reset delaywrk to first delayline
|
||||||
|
%else
|
||||||
|
mov dword [MANGLE_DATA(su_delay_buffer_ofs)],MANGLE_DATA(su_delay_buffer) ; reset delaywrk to first
|
||||||
|
%endif
|
||||||
%endif
|
%endif
|
||||||
xor ecx, ecx ; voice = 0
|
xor ecx, ecx ; voice = 0
|
||||||
push ecx ; Stack: voice WRK VAL COM
|
push _CX ; Stack: voice WRK VAL COM
|
||||||
su_run_vm_loop: ; loop until all voices done
|
su_run_vm_loop: ; loop until all voices done
|
||||||
movzx eax, byte [COM] ; eax = command byte
|
movzx eax, byte [COM] ; eax = command byte
|
||||||
inc COM ; move to next instruction
|
inc COM ; move to next instruction
|
||||||
add WRK, su_unit.size ; move WRK to next unit
|
add WRK, su_unit.size ; move WRK to next unit
|
||||||
push eax
|
push _AX
|
||||||
shr eax,1
|
shr eax,1
|
||||||
mov al,byte [eax+su_opcode_numparams]
|
apply {mov al,byte},su_opcode_numparams,_AX,{}
|
||||||
push eax
|
push _AX
|
||||||
call su_transform_values
|
call su_transform_values
|
||||||
mov ecx, dword [esp+8]
|
mov _CX, PTRWORD [_SP+2*PTRSIZE]
|
||||||
pop eax
|
pop _AX
|
||||||
shr eax,1
|
shr eax,1
|
||||||
call dword [eax*4+su_synth_commands] ; call the function corresponding to the instruction
|
apply call,su_synth_commands,_AX*PTRSIZE,{} ; call the function corresponding to the instruction
|
||||||
cmp dword [esp],MAX_VOICES ; if (voice < MAX_VOICES)
|
cmp dword [_SP],MAX_VOICES ; if (voice < MAX_VOICES)
|
||||||
jl su_run_vm_loop ; goto vm_loop
|
jl su_run_vm_loop ; goto vm_loop
|
||||||
add esp, 16 ; Stack cleared
|
add _SP, 4*PTRSIZE ; Stack cleared
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
@ -96,12 +191,12 @@ su_run_vm_loop: ; loop until all voices done
|
|||||||
SECT_TEXT(surandom)
|
SECT_TEXT(surandom)
|
||||||
|
|
||||||
EXPORT MANGLE_FUNC(FloatRandomNumber,0)
|
EXPORT MANGLE_FUNC(FloatRandomNumber,0)
|
||||||
push eax
|
push _AX
|
||||||
imul eax,dword [MANGLE_DATA(RandSeed)],16007
|
apply {imul eax,},MANGLE_DATA(RandSeed),{,16007}
|
||||||
mov dword [MANGLE_DATA(RandSeed)], eax
|
apply mov,MANGLE_DATA(RandSeed),{, eax}
|
||||||
fild dword [MANGLE_DATA(RandSeed)]
|
apply fild dword,MANGLE_DATA(RandSeed)
|
||||||
fidiv dword [c_RandDiv]
|
apply fidiv dword,c_RandDiv
|
||||||
pop eax
|
pop _AX
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
@ -117,31 +212,26 @@ EXPORT MANGLE_FUNC(FloatRandomNumber,0)
|
|||||||
SECT_TEXT(sutransf)
|
SECT_TEXT(sutransf)
|
||||||
|
|
||||||
su_transform_values:
|
su_transform_values:
|
||||||
push ecx
|
push _CX
|
||||||
xor ecx, ecx
|
xor ecx, ecx
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
mov edx, su_transformed_values
|
mov INP, PTRWORD su_transformed_values
|
||||||
su_transform_values_loop:
|
su_transform_values_loop:
|
||||||
cmp ecx, dword [esp+8]
|
cmp ecx, dword [_SP+2*PTRSIZE]
|
||||||
jge su_transform_values_out
|
jge su_transform_values_out
|
||||||
lodsb
|
lodsb
|
||||||
push eax
|
push _AX
|
||||||
fild dword [esp]
|
fild dword [_SP]
|
||||||
fmul dword [c_i128]
|
apply fmul dword, c_i128
|
||||||
fadd dword [WRK+su_unit.ports+ecx*4]
|
fadd dword [WRK+su_unit.ports+_CX*4]
|
||||||
fstp dword [edx+ecx*4]
|
fstp dword [INP+_CX*4]
|
||||||
mov dword [WRK+su_unit.ports+ecx*4], 0
|
mov dword [WRK+su_unit.ports+_CX*4], 0
|
||||||
pop eax
|
pop _AX
|
||||||
inc ecx
|
inc ecx
|
||||||
jmp su_transform_values_loop
|
jmp su_transform_values_loop
|
||||||
su_transform_values_out:
|
su_transform_values_out:
|
||||||
pop ecx
|
pop _CX
|
||||||
ret 4
|
ret PTRSIZE
|
||||||
|
|
||||||
%macro TRANSFORM_VALUES 1
|
|
||||||
push %1 %+ .params/4
|
|
||||||
call su_transform_values
|
|
||||||
%endmacro
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; su_env_map function: computes 2^(-24*x) of the envelope parameter
|
; su_env_map function: computes 2^(-24*x) of the envelope parameter
|
||||||
@ -154,8 +244,8 @@ SECT_TEXT(supower)
|
|||||||
|
|
||||||
%if ENVELOPE_ID > -1 ; TODO: compressor also uses this, so should be compiled if either
|
%if ENVELOPE_ID > -1 ; TODO: compressor also uses this, so should be compiled if either
|
||||||
su_env_map:
|
su_env_map:
|
||||||
fld dword [edx+eax*4] ; x, where x is the parameter in the range 0-1
|
fld dword [INP+_AX*4] ; x, where x is the parameter in the range 0-1
|
||||||
fimul dword [c_24] ; 24*x
|
apply fimul dword,c_24 ; 24*x
|
||||||
fchs ; -24*x
|
fchs ; -24*x
|
||||||
; flow into Power function, which outputs 2^(-24*x)
|
; flow into Power function, which outputs 2^(-24*x)
|
||||||
%endif
|
%endif
|
||||||
@ -189,6 +279,13 @@ EXPORT MANGLE_FUNC(su_power,0)
|
|||||||
; sources, as sources.asm defines SU_USE_WAVESHAPER
|
; sources, as sources.asm defines SU_USE_WAVESHAPER
|
||||||
; if needed.
|
; if needed.
|
||||||
%include "opcodes/effects.asm"
|
%include "opcodes/effects.asm"
|
||||||
%include "player.asm"
|
|
||||||
%include "introspection.asm"
|
%include "introspection.asm"
|
||||||
%include "gmdls.asm"
|
%include "player.asm"
|
||||||
|
|
||||||
|
%ifidn __OUTPUT_FORMAT__,win64
|
||||||
|
%include "win64/gmdls_win64.asm"
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifidn __OUTPUT_FORMAT__,win32
|
||||||
|
%include "win32/gmdls_win32.asm"
|
||||||
|
%endif
|
@ -19,17 +19,33 @@
|
|||||||
; on win32, function f with n parameters is mangled as "_f@n"
|
; on win32, function f with n parameters is mangled as "_f@n"
|
||||||
%define MANGLE_FUNC(f,n) _ %+ f %+ @ %+ n
|
%define MANGLE_FUNC(f,n) _ %+ f %+ @ %+ n
|
||||||
%define WIN_OR_MAC
|
%define WIN_OR_MAC
|
||||||
|
%assign BITS 32
|
||||||
|
; On windows and mac, data label d is mangled as "_d"
|
||||||
|
%define MANGLE_DATA(d) _ %+ d
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifidn __OUTPUT_FORMAT__,win64
|
||||||
|
; on win32, function f with n parameters is mangled as "_f@n"
|
||||||
|
%define MANGLE_FUNC(f,n) f
|
||||||
|
%define WIN_OR_MAC
|
||||||
|
%assign BITS 64
|
||||||
|
; On windows and mac, data label d is mangled as "_d"
|
||||||
|
%define MANGLE_DATA(d) d
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%ifidn __OUTPUT_FORMAT__,elf32
|
%ifidn __OUTPUT_FORMAT__,elf32
|
||||||
; on linux, function f with n parameters is mangled as "f"
|
; on linux, function f with n parameters is mangled as "f"
|
||||||
%define MANGLE_FUNC(f,n) f
|
%define MANGLE_FUNC(f,n) f
|
||||||
|
; On linux, data label d is mangled as "d"
|
||||||
|
%define MANGLE_DATA(d) d
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%ifidn __OUTPUT_FORMAT__,macho32
|
%ifidn __OUTPUT_FORMAT__,macho32
|
||||||
; on mac, function f with x parameters is mangled as "_f"
|
; on mac, function f with x parameters is mangled as "_f"
|
||||||
%define MANGLE_FUNC(f,n) _f
|
%define MANGLE_FUNC(f,n) _f
|
||||||
%define WIN_OR_MAC
|
%define WIN_OR_MAC
|
||||||
|
; On windows and mac, data label d is mangled as "_d"
|
||||||
|
%define MANGLE_DATA(d) _ %+ d
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%ifdef WIN_OR_MAC
|
%ifdef WIN_OR_MAC
|
||||||
@ -44,8 +60,6 @@
|
|||||||
%define SECT_DATA(n) section .data align=1
|
%define SECT_DATA(n) section .data align=1
|
||||||
%define SECT_TEXT(n) section .code align=1
|
%define SECT_TEXT(n) section .code align=1
|
||||||
%endif
|
%endif
|
||||||
; On windows and mac, data label d is mangled as "_d"
|
|
||||||
%define MANGLE_DATA(d) _ %+ d
|
|
||||||
%else
|
%else
|
||||||
; Linux
|
; Linux
|
||||||
%ifdef USE_SECTIONS
|
%ifdef USE_SECTIONS
|
||||||
@ -57,8 +71,6 @@
|
|||||||
%define SECT_DATA(n) section .data. progbits alloc noexec write align=1
|
%define SECT_DATA(n) section .data. progbits alloc noexec write align=1
|
||||||
%define SECT_TEXT(n) section .text. progbits alloc exec nowrite align=1
|
%define SECT_TEXT(n) section .text. progbits alloc exec nowrite align=1
|
||||||
%endif
|
%endif
|
||||||
; On linux, data label d is mangled as "d"
|
|
||||||
%define MANGLE_DATA(d) d
|
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%ifdef SU_USE_ALL
|
%ifdef SU_USE_ALL
|
||||||
|
@ -8,15 +8,15 @@ extern _ReadFile@20 ; requires windows
|
|||||||
SECT_TEXT(sugmdls)
|
SECT_TEXT(sugmdls)
|
||||||
|
|
||||||
su_gmdls_load:
|
su_gmdls_load:
|
||||||
mov edi, MANGLE_DATA(su_sample_table)
|
mov edi, MANGLE_DATA(su_sample_table)
|
||||||
mov esi, su_gmdls_path1
|
mov esi, su_gmdls_path1
|
||||||
su_gmdls_pathloop:
|
su_gmdls_pathloop:
|
||||||
push 0 ; OF_READ
|
push 0 ; OF_READ
|
||||||
push edi ; &ofstruct, blatantly reuse the sample table
|
push edi ; &ofstruct, blatantly reuse the sample table
|
||||||
push esi ; path
|
push esi ; path
|
||||||
call _OpenFile@12 ; eax = OpenFile(path,&ofstruct,OF_READ)
|
call _OpenFile@12 ; eax = OpenFile(path,&ofstruct,OF_READ)
|
||||||
add esi, su_gmdls_path2 - su_gmdls_path1 ; if we ever get to third, then crash
|
add esi, su_gmdls_path2 - su_gmdls_path1 ; if we ever get to third, then crash
|
||||||
cmp eax, -1 ; eax == INVALID?
|
cmp eax, -1 ; eax == INVALID?
|
||||||
je su_gmdls_pathloop
|
je su_gmdls_pathloop
|
||||||
push 0 ; NULL
|
push 0 ; NULL
|
||||||
push edi ; &bytes_read, reusing sample table again; it does not matter that the first four bytes are trashed
|
push edi ; &bytes_read, reusing sample table again; it does not matter that the first four bytes are trashed
|
||||||
@ -31,7 +31,7 @@ SECT_DATA(sugmpath)
|
|||||||
su_gmdls_path1:
|
su_gmdls_path1:
|
||||||
db 'drivers/gm.dls',0
|
db 'drivers/gm.dls',0
|
||||||
su_gmdls_path2:
|
su_gmdls_path2:
|
||||||
db 'drivers/etc/gm.dls',0
|
db 'drivers/etc/gm.dls',0
|
||||||
|
|
||||||
SECT_DATA(suconst)
|
SECT_DATA(suconst)
|
||||||
c_samplefreq_scaling dd 84.28074964676522 ; o = 0.000092696138, n = 72, f = 44100*o*2**(n/12), scaling = 22050/f <- so note 72 plays at the "normal rate"
|
c_samplefreq_scaling dd 84.28074964676522 ; o = 0.000092696138, n = 72, f = 44100*o*2**(n/12), scaling = 22050/f <- so note 72 plays at the "normal rate"
|
44
src/win64/gmdls_win64.asm
Normal file
44
src/win64/gmdls_win64.asm
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
%ifdef INCLUDE_GMDLS
|
||||||
|
|
||||||
|
%define SAMPLE_TABLE_SIZE 3440660 ; size of gmdls
|
||||||
|
|
||||||
|
extern OpenFile ; requires windows
|
||||||
|
extern ReadFile ; requires windows
|
||||||
|
|
||||||
|
SECT_TEXT(sugmdls)
|
||||||
|
; Win64 ABI: RCX, RDX, R8, and R9
|
||||||
|
su_gmdls_load:
|
||||||
|
sub rsp, 40 ; Win64 ABI requires "shadow space" + space for one parameter.
|
||||||
|
mov rdi, PTRWORD MANGLE_DATA(su_sample_table)
|
||||||
|
mov rsi, PTRWORD su_gmdls_path1
|
||||||
|
su_gmdls_pathloop:
|
||||||
|
xor r8,r8 ; OF_READ
|
||||||
|
mov rdx, rdi ; &ofstruct, blatantly reuse the sample table
|
||||||
|
mov rcx, rsi ; path
|
||||||
|
call OpenFile ; eax = OpenFile(path,&ofstruct,OF_READ)
|
||||||
|
add rsi, su_gmdls_path2 - su_gmdls_path1 ; if we ever get to third, then crash
|
||||||
|
movsxd rcx,eax
|
||||||
|
cmp rcx, -1 ; ecx == INVALID?
|
||||||
|
je su_gmdls_pathloop
|
||||||
|
mov qword [rsp+32],0
|
||||||
|
mov r9, rdi
|
||||||
|
mov r8d, SAMPLE_TABLE_SIZE ; number of bytes to read
|
||||||
|
mov rdx, rdi
|
||||||
|
call ReadFile ; Readfile(handle,&su_sample_table,SAMPLE_TABLE_SIZE,&bytes_read,NULL)
|
||||||
|
add rsp, 40 ; shadow space, as required by Win64 ABI
|
||||||
|
ret
|
||||||
|
|
||||||
|
SECT_DATA(sugmpath)
|
||||||
|
|
||||||
|
su_gmdls_path1:
|
||||||
|
db 'drivers/gm.dls',0
|
||||||
|
su_gmdls_path2:
|
||||||
|
db 'drivers/etc/gm.dls',0
|
||||||
|
|
||||||
|
SECT_DATA(suconst)
|
||||||
|
c_samplefreq_scaling dd 84.28074964676522 ; o = 0.000092696138, n = 72, f = 44100*o*2**(n/12), scaling = 22050/f <- so note 72 plays at the "normal rate"
|
||||||
|
|
||||||
|
SECT_BSS(susamtbl)
|
||||||
|
EXPORT MANGLE_DATA(su_sample_table) resb SAMPLE_TABLE_SIZE ; size of gmdls.
|
||||||
|
|
||||||
|
%endif
|
@ -8,7 +8,14 @@ function(regression_test testname)
|
|||||||
add_executable(${testname} ${source}.asm test_renderer.c)
|
add_executable(${testname} ${source}.asm test_renderer.c)
|
||||||
|
|
||||||
# the tests include the entire ASM but we still want to rebuild when they change
|
# the tests include the entire ASM but we still want to rebuild when they change
|
||||||
file(GLOB SOINTU ${PROJECT_SOURCE_DIR}/src/*.inc ${PROJECT_SOURCE_DIR}/src/*.asm ${PROJECT_SOURCE_DIR}/src/opcodes/*.asm ${PROJECT_SOURCE_DIR}/src/opcodes/*.inc)
|
file(GLOB SOINTU ${PROJECT_SOURCE_DIR}/src/*.inc
|
||||||
|
${PROJECT_SOURCE_DIR}/src/*.asm
|
||||||
|
${PROJECT_SOURCE_DIR}/src/opcodes/*.asm
|
||||||
|
${PROJECT_SOURCE_DIR}/src/opcodes/*.inc
|
||||||
|
${PROJECT_SOURCE_DIR}/src/win32/*.asm
|
||||||
|
${PROJECT_SOURCE_DIR}/src/win32/*.inc
|
||||||
|
${PROJECT_SOURCE_DIR}/src/win64/*.asm
|
||||||
|
${PROJECT_SOURCE_DIR}/src/win64/*.inc)
|
||||||
set_source_files_properties(${source}.asm PROPERTIES OBJECT_DEPENDS "${SOINTU}")
|
set_source_files_properties(${source}.asm PROPERTIES OBJECT_DEPENDS "${SOINTU}")
|
||||||
set_source_files_properties(${FOURKLANG} PROPERTIES HEADER_FILE_ONLY TRUE)
|
set_source_files_properties(${FOURKLANG} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user