mirror of
https://github.com/vsariola/sointu.git
synced 2025-05-28 03:10:24 -04:00
1758 lines
50 KiB
NASM
1758 lines
50 KiB
NASM
bits 32
|
|
|
|
%define WRK ebp ; // alias for unit workspace
|
|
%define VAL esi ; // alias for unit values (transformed/untransformed)
|
|
%define COM ebx ; // alias for instrument opcodes
|
|
|
|
%include "4klang.inc"
|
|
|
|
;// conditional defines
|
|
|
|
%ifdef GO4K_USE_VCO_SHAPE
|
|
%define INCLUDE_WAVESHAPER
|
|
%endif
|
|
%ifdef GO4K_USE_DST
|
|
%define INCLUDE_WAVESHAPER
|
|
%endif
|
|
|
|
%ifdef GO4K_USE_VCO_MOD_PM
|
|
%define PHASE_RENORMALIZE
|
|
%endif
|
|
%ifdef GO4K_USE_VCO_PHASE_OFFSET
|
|
%define PHASE_RENORMALIZE
|
|
%endif
|
|
|
|
%ifdef GO4K_USE_ENVELOPE_RECORDINGS
|
|
%define GO4K_USE_BUFFER_RECORDINGS
|
|
%endif
|
|
%ifdef GO4K_USE_NOTE_RECORDINGS
|
|
%define GO4K_USE_BUFFER_RECORDINGS
|
|
%endif
|
|
|
|
; //========================================================================================
|
|
; // .bss section
|
|
; //========================================================================================
|
|
%ifdef USE_SECTIONS
|
|
section .g4kbss1 bss align=1
|
|
%else
|
|
section .bss
|
|
%endif
|
|
|
|
; // the one and only synth object
|
|
%if MAX_VOICES > 1
|
|
go4k_voiceindex resd 16
|
|
%endif
|
|
go4k_transformed_values resd 16
|
|
go4k_synth_wrk resb go4k_synth.size
|
|
global _go4k_delay_buffer_ofs
|
|
_go4k_delay_buffer_ofs resd 1
|
|
global _go4k_delay_buffer
|
|
_go4k_delay_buffer resd 16*16*go4kDLL_wrk.size
|
|
|
|
%ifdef AUTHORING
|
|
global __4klang_current_tick
|
|
__4klang_current_tick resd 0
|
|
%endif
|
|
|
|
%ifdef GO4K_USE_ENVELOPE_RECORDINGS
|
|
global __4klang_envelope_buffer
|
|
__4klang_envelope_buffer resd ((MAX_SAMPLES)/8) ; // samples every 256 samples and stores 16*2 = 32 values
|
|
%endif
|
|
%ifdef GO4K_USE_NOTE_RECORDINGS
|
|
global __4klang_note_buffer
|
|
__4klang_note_buffer resd ((MAX_SAMPLES)/8) ; // samples every 256 samples and stores 16*2 = 32 values
|
|
%endif
|
|
|
|
; //========================================================================================
|
|
; // .g4kdat section (initialized data for go4k)
|
|
; //========================================================================================
|
|
%ifdef USE_SECTIONS
|
|
section .g4kdat1 data align=1
|
|
%else
|
|
section .data
|
|
%endif
|
|
|
|
; // some synth constants
|
|
go4k_synth_commands dd 0
|
|
dd _go4kENV_func@0
|
|
dd _go4kVCO_func@0
|
|
dd _go4kVCF_func@0
|
|
dd _go4kDST_func@0
|
|
dd _go4kDLL_func@0
|
|
dd _go4kFOP_func@0
|
|
dd _go4kFST_func@0
|
|
dd _go4kPAN_func@0
|
|
dd _go4kOUT_func@0
|
|
dd _go4kACC_func@0
|
|
dd _go4kFLD_func@0
|
|
%ifdef GO4K_USE_GLITCH
|
|
dd _go4kGLITCH_func@0
|
|
%else
|
|
dd _go4kFLD_func@0
|
|
%endif
|
|
%ifdef GO4K_USE_FSTG
|
|
dd _go4kFSTG_func@0
|
|
%endif
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kdat2 data align=1
|
|
%else
|
|
section .data
|
|
%endif
|
|
|
|
%ifdef GO4K_USE_16BIT_OUTPUT
|
|
c_32767 dd 32767.0
|
|
%endif
|
|
c_i128 dd 0.0078125
|
|
c_RandDiv dd 65536*32768
|
|
c_0_5 dd 0.5
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
c_16 dd 16.0
|
|
%endif
|
|
%ifdef GO4K_USE_DLL_CHORUS
|
|
DLL_DEPTH dd 1024.0
|
|
%endif
|
|
%ifdef GO4K_USE_DLL_DC_FILTER
|
|
c_dc_const dd 0.99609375 ; R = 1 - (pi*2 * frequency /samplerate)
|
|
%else
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
c_dc_const dd 0.99609375 ; R = 1 - (pi*2 * frequency /samplerate)
|
|
%endif
|
|
%endif
|
|
global _RandSeed
|
|
_RandSeed dd 1
|
|
c_24 dd 24
|
|
c_i12 dd 0x3DAAAAAA
|
|
FREQ_NORMALIZE dd 0.000092696138 ; // 220.0/(2^(69/12)) / 44100.0
|
|
global _LFO_NORMALIZE
|
|
_LFO_NORMALIZE dd DEF_LFO_NORMALIZE
|
|
%ifdef GO4K_USE_GROOVE_PATTERN
|
|
go4k_groove_pattern dw 0011100111001110b
|
|
%endif
|
|
|
|
; //========================================================================================
|
|
; // .crtemui section (emulates crt functions)
|
|
; //========================================================================================
|
|
%ifdef USE_SECTIONS
|
|
section .crtemui code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
|
|
export_func FloatRandomNumber@0
|
|
push eax
|
|
imul eax,dword [_RandSeed],16007
|
|
mov dword [_RandSeed], eax
|
|
fild dword [_RandSeed]
|
|
fidiv dword [c_RandDiv]
|
|
pop eax
|
|
ret
|
|
|
|
; //========================================================================================
|
|
; // .g4kcod* sections (code for go4k)
|
|
; //========================================================================================
|
|
|
|
%ifdef INCLUDE_WAVESHAPER
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcod2 code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // Waveshaper function
|
|
; //----------------------------------------------------------------------------------------
|
|
; // Input : st0 : shaping coeff
|
|
; // st1 : input
|
|
; // Output: st0 : result
|
|
; //----------------------------------------------------------------------------------------
|
|
|
|
go4kWaveshaper:
|
|
%ifdef GO4K_USE_WAVESHAPER_CLIP
|
|
fxch
|
|
fld1 ; // 1 val
|
|
fucomi st1 ; // 1 val
|
|
jbe short go4kWaveshaper_clip
|
|
fchs ; // -1 val
|
|
fucomi st1 ; // -1 val
|
|
fcmovb st0, st1 ; // val -1 (if val > -1)
|
|
go4kWaveshaper_clip:
|
|
fstp st1 ; // newval
|
|
fxch
|
|
%endif
|
|
fsub dword [c_0_5]
|
|
fadd st0
|
|
fst dword [esp-4] ; // amnt in
|
|
fadd st0 ; // 2*amnt in
|
|
fld1 ; // 1 2*amnt in
|
|
fsub dword [esp-4] ; // 1-amnt 2*amnt in
|
|
fdivp st1, st0 ; // k in
|
|
fld st1 ; // sin k in
|
|
fabs ; // a(in) k in
|
|
fmul st1 ; // k*a(in) k in
|
|
fld1
|
|
faddp st1, st0 ; // 1+k*a(in) k in
|
|
fxch st1 ; // k 1+k*a(in) in
|
|
fld1
|
|
faddp st1, st0 ; // 1+k 1+k*a(in) in
|
|
fmulp st2 ; // 1+k*a(in) (1+k)*in
|
|
fdivp st1, st0 ; // out
|
|
ret
|
|
|
|
%endif
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcod3 code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // unit values preparation/transform
|
|
; //----------------------------------------------------------------------------------------
|
|
go4kTransformValues:
|
|
push ecx
|
|
xor ecx, ecx
|
|
xor eax, eax
|
|
mov edx, go4k_transformed_values
|
|
go4kTransformValues_loop:
|
|
lodsb
|
|
push eax
|
|
fild dword [esp]
|
|
fmul dword [c_i128]
|
|
fstp dword [edx+ecx*4]
|
|
pop eax
|
|
inc ecx
|
|
cmp ecx, dword [esp+8]
|
|
jl go4kTransformValues_loop
|
|
pop ecx
|
|
ret 4
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcod4 code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // Envelope param mapping
|
|
; //----------------------------------------------------------------------------------------
|
|
go4kENVMap:
|
|
fld dword [edx+eax*4]
|
|
%ifdef GO4K_USE_ENV_MOD_ADR
|
|
fadd dword [WRK+go4kENV_wrk.am+eax*4]
|
|
%endif
|
|
fimul dword [c_24]
|
|
fchs
|
|
; //----------------------------------------------------------------------------------------
|
|
; // Power function (2^x)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // Input : st0 : base
|
|
; // st1 : exponent
|
|
; // Output: st0 : result
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func Power@0 ; // base exp
|
|
fld1
|
|
fadd st0
|
|
fyl2x ; // log2_base
|
|
fld1 ; // 1 log2_base
|
|
fld st1 ; // log2_base 1 log2_base
|
|
fprem ; // (frac)log2_base 1 log2_base
|
|
f2xm1 ; // 2 ^ '' - 1 1 log2_base
|
|
faddp st1, st0 ; // 2 ^ '' (int)log2_base
|
|
fscale
|
|
fstp st1
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcoda code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // ENV Tick
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY : eax
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kENV_func@0
|
|
push 5
|
|
call go4kTransformValues
|
|
%ifdef GO4K_USE_ENV_CHECK
|
|
; check if current note still active
|
|
mov eax, dword [ecx-4]
|
|
test eax, eax
|
|
jne go4kENV_func_do
|
|
fldz
|
|
ret
|
|
%endif
|
|
go4kENV_func_do:
|
|
mov eax, dword [ecx-8] ; // is the instrument in release mode (note off)?
|
|
test eax, eax
|
|
je go4kENV_func_process
|
|
mov dword [WRK+go4kENV_wrk.state], ENV_STATE_RELEASE
|
|
go4kENV_func_process:
|
|
mov eax, dword [WRK+go4kENV_wrk.state]
|
|
fld dword [WRK+go4kENV_wrk.level] ; // val -
|
|
; // check for sustain state
|
|
cmp al, ENV_STATE_SUSTAIN
|
|
je short go4kENV_func_leave2
|
|
go4kENV_func_attac:
|
|
cmp al, ENV_STATE_ATTAC
|
|
jne short go4kENV_func_decay
|
|
call go4kENVMap ; // newval
|
|
faddp st1, st0
|
|
; // check for end of attac
|
|
fld1 ; // 1 newval
|
|
fucomi st1 ; // 1 newval
|
|
fcmovnb st0, st1 ; // newval 1 (if newval < 1)
|
|
jbe short go4kENV_func_statechange
|
|
go4kENV_func_decay:
|
|
cmp al, ENV_STATE_DECAY
|
|
jne short go4kENV_func_release
|
|
call go4kENVMap ; // newval
|
|
fsubp st1, st0
|
|
; // check for end of decay
|
|
fld dword [edx+go4kENV_val.sustain] ; // sustain newval
|
|
fucomi st1 ; // sustain newval
|
|
fcmovb st0, st1 ; // newval sustain (if newval > sustain)
|
|
jnc short go4kENV_func_statechange
|
|
go4kENV_func_release:
|
|
; // release state?
|
|
cmp al, ENV_STATE_RELEASE
|
|
jne short go4kENV_func_leave
|
|
call go4kENVMap ; // newval
|
|
fsubp st1, st0
|
|
; // check for end of release
|
|
fldz ; // 0 newval
|
|
fucomi st1 ; // 0 newval
|
|
fcmovb st0, st1 ; // newval 0 (if newval > 0)
|
|
jc short go4kENV_func_leave
|
|
go4kENV_func_statechange: ; // newval
|
|
inc dword [WRK+go4kENV_wrk.state]
|
|
go4kENV_func_leave: ; // newval bla
|
|
fstp st1
|
|
; // store new env value
|
|
fst dword [WRK+go4kENV_wrk.level]
|
|
go4kENV_func_leave2:
|
|
; // mul by gain
|
|
%ifdef GO4K_USE_ENV_MOD_GM
|
|
fld dword [edx+go4kENV_val.gain]
|
|
fadd dword [WRK+go4kENV_wrk.gm]
|
|
fmulp st1, st0
|
|
%else
|
|
fmul dword [edx+go4kENV_val.gain]
|
|
%endif
|
|
ret
|
|
|
|
|
|
; //----------------------------------------------------------------------------------------
|
|
; // VCO Tick
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY : eax
|
|
; //----------------------------------------------------------------------------------------
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodp code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
go4kVCO_pulse:
|
|
fucomi st1 ; // c p
|
|
fld1
|
|
jnc short go4kVCO_func_pulse_up ; // +1 c p
|
|
fchs ; // -1 c p
|
|
go4kVCO_func_pulse_up:
|
|
fstp st1 ; // +-1 p
|
|
fstp st1 ; // +-1
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodt code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
go4kVCO_trisaw:
|
|
fucomi st1 ; // c p
|
|
jnc short go4kVCO_func_trisaw_up
|
|
fld1 ; // 1 c p
|
|
fsubr st2, st0 ; // 1 c 1-p
|
|
fsubrp st1, st0 ; // 1-c 1-p
|
|
go4kVCO_func_trisaw_up:
|
|
fdivp st1, st0 ; // tp'/tc
|
|
fadd st0 ; // 2*''
|
|
fld1 ; // 1 2*''
|
|
fsubp st1, st0 ; // 2*''-1
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcods code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
go4kVCO_sine:
|
|
fucomi st1 ; // c p
|
|
jnc short go4kVCO_func_sine_do
|
|
fstp st1
|
|
fsub st0, st0 ; // 0
|
|
ret
|
|
go4kVCO_func_sine_do
|
|
fdivp st1, st0 ; // p/c
|
|
fldpi ; // pi p
|
|
fadd st0 ; // 2*pi p
|
|
fmulp st1, st0 ; // 2*pi*p
|
|
fsin ; // sin(2*pi*p)
|
|
ret
|
|
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodq code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
go4kVCO_gate:
|
|
fxch ; // p c
|
|
fstp st1 ; // p
|
|
fmul dword [c_16] ; // p'
|
|
push eax
|
|
push eax
|
|
fistp dword [esp] ; // -
|
|
fld1 ; // 1
|
|
pop eax
|
|
and al, 0xf
|
|
bt word [VAL-5],ax
|
|
jc go4kVCO_gate_bit
|
|
fsub st0, st0 ; // 0
|
|
go4kVCO_gate_bit:
|
|
fld dword [WRK+go4kVCO_wrk.cm] ; // f x
|
|
fsub st1 ; // f-x x
|
|
fmul dword [c_dc_const] ; // c(f-x) x
|
|
faddp st1, st0 ; // x'
|
|
fst dword [WRK+go4kVCO_wrk.cm]
|
|
pop eax
|
|
ret
|
|
%endif
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodb code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
export_func go4kVCO_func@0
|
|
%ifdef GO4K_USE_VCO_PHASE_OFFSET
|
|
%ifdef GO4K_USE_VCO_SHAPE
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
push 8
|
|
%else
|
|
push 7
|
|
%endif
|
|
%else
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
push 7
|
|
%else
|
|
push 6
|
|
%endif
|
|
%endif
|
|
%else
|
|
%ifdef GO4K_USE_VCO_SHAPE
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
push 7
|
|
%else
|
|
push 6
|
|
%endif
|
|
%else
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
push 6
|
|
%else
|
|
push 5
|
|
%endif
|
|
%endif
|
|
%endif
|
|
call go4kTransformValues
|
|
%ifdef GO4K_USE_VCO_CHECK
|
|
; check if current note still active
|
|
mov eax, dword [ecx-4]
|
|
test eax, eax
|
|
jne go4kVCO_func_do
|
|
%ifdef GO4K_USE_VCO_STEREO
|
|
movzx eax, byte [VAL-1] ; // get flags and check for stereo
|
|
test al, byte VCO_STEREO
|
|
jz short go4kVCO_func_nostereoout
|
|
fldz
|
|
go4kVCO_func_nostereoout:
|
|
%endif
|
|
fldz
|
|
ret
|
|
go4kVCO_func_do:
|
|
%endif
|
|
movzx eax, byte [VAL-1] ; // get flags
|
|
%ifdef GO4K_USE_VCO_STEREO
|
|
test al, byte VCO_STEREO
|
|
jz short go4kVCO_func_nopswap
|
|
fld dword [WRK+go4kVCO_wrk.phase] ;// swap left/right phase values for first stereo run
|
|
fld dword [WRK+go4kVCO_wrk.phase2]
|
|
fstp dword [WRK+go4kVCO_wrk.phase]
|
|
fstp dword [WRK+go4kVCO_wrk.phase2]
|
|
go4kVCO_func_nopswap:
|
|
%endif
|
|
go4kVCO_func_process:
|
|
fld dword [edx+go4kVCO_val.transpose]
|
|
fsub dword [c_0_5]
|
|
%ifdef GO4K_USE_VCO_MOD_TM
|
|
fadd dword [WRK+go4kVCO_wrk.tm]
|
|
%endif
|
|
fdiv dword [c_i128]
|
|
fld dword [edx+go4kVCO_val.detune]
|
|
fsub dword [c_0_5]
|
|
fadd st0
|
|
%ifdef GO4K_USE_VCO_STEREO
|
|
test al, byte VCO_STEREO
|
|
jz short go4kVCO_func_nodswap
|
|
fchs ;// negate detune for stereo
|
|
go4kVCO_func_nodswap:
|
|
%endif
|
|
faddp st1
|
|
%ifdef GO4K_USE_VCO_MOD_DM
|
|
fadd dword [WRK+go4kVCO_wrk.dm]
|
|
%endif
|
|
; // st0 now contains the transpose+detune offset
|
|
test al, byte LFO
|
|
jnz go4kVCO_func_skipnote
|
|
fiadd dword [ecx-4] ; // st0 is note, st1 is t+d offset
|
|
go4kVCO_func_skipnote:
|
|
fmul dword [c_i12]
|
|
call _Power@0
|
|
test al, byte LFO
|
|
jz short go4kVCO_func_normalize_note
|
|
fmul dword [_LFO_NORMALIZE] ; // st0 is now frequency for lfo
|
|
jmp short go4kVCO_func_normalized
|
|
go4kVCO_func_normalize_note:
|
|
fmul dword [FREQ_NORMALIZE] ; // st0 is now frequency
|
|
go4kVCO_func_normalized:
|
|
fadd dword [WRK+go4kVCO_wrk.phase]
|
|
%ifdef GO4K_USE_VCO_MOD_FM
|
|
fadd dword [WRK+go4kVCO_wrk.fm]
|
|
%endif
|
|
fld1
|
|
fadd st1, st0
|
|
fxch
|
|
fprem
|
|
fstp st1
|
|
fst dword [WRK+go4kVCO_wrk.phase]
|
|
%ifdef GO4K_USE_VCO_MOD_PM
|
|
fadd dword [WRK+go4kVCO_wrk.pm]
|
|
%endif
|
|
%ifdef GO4K_USE_VCO_PHASE_OFFSET
|
|
fadd dword [edx+go4kVCO_val.phaseofs]
|
|
%endif
|
|
%ifdef PHASE_RENORMALIZE
|
|
fld1
|
|
fadd st1, st0
|
|
fxch
|
|
fprem
|
|
fstp st1 ; // p
|
|
%endif
|
|
fld dword [edx+go4kVCO_val.color] ; // c p
|
|
%ifdef GO4K_USE_VCO_MOD_CM
|
|
fadd dword [WRK+go4kVCO_wrk.cm] ; // c p
|
|
%endif
|
|
go4kVCO_func_sine:
|
|
test al, byte SINE
|
|
jz short go4kVCO_func_trisaw
|
|
call go4kVCO_sine
|
|
go4kVCO_func_trisaw:
|
|
test al, byte TRISAW
|
|
jz short go4kVCO_func_pulse
|
|
call go4kVCO_trisaw
|
|
go4kVCO_func_pulse:
|
|
test al, byte PULSE
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
jz short go4kVCO_func_gate
|
|
%else
|
|
jz short go4kVCO_func_noise
|
|
%endif
|
|
call go4kVCO_pulse
|
|
%ifdef GO4K_USE_VCO_GATE
|
|
go4kVCO_func_gate:
|
|
test al, byte GATE
|
|
jz short go4kVCO_func_noise
|
|
call go4kVCO_gate
|
|
%endif
|
|
go4kVCO_func_noise:
|
|
test al, byte NOISE
|
|
jz short go4kVCO_func_end
|
|
call _FloatRandomNumber@0
|
|
fstp st1
|
|
fstp st1
|
|
go4kVCO_func_end:
|
|
%ifdef GO4K_USE_VCO_SHAPE
|
|
fld dword [edx+go4kVCO_val.shape]
|
|
%ifdef GO4K_USE_VCO_MOD_SM
|
|
fadd dword [WRK+go4kVCO_wrk.sm]
|
|
%endif
|
|
call go4kWaveshaper
|
|
%endif
|
|
fld dword [edx+go4kVCO_val.gain]
|
|
%ifdef GO4K_USE_VCO_MOD_GM
|
|
fadd dword [WRK+go4kVCO_wrk.gm]
|
|
%endif
|
|
fmulp st1, st0
|
|
|
|
%ifdef GO4K_USE_VCO_STEREO
|
|
test al, byte VCO_STEREO
|
|
jz short go4kVCO_func_stereodone
|
|
sub al, byte VCO_STEREO
|
|
fld dword [WRK+go4kVCO_wrk.phase] ;// swap left/right phase values again for second stereo run
|
|
fld dword [WRK+go4kVCO_wrk.phase2]
|
|
fstp dword [WRK+go4kVCO_wrk.phase]
|
|
fstp dword [WRK+go4kVCO_wrk.phase2]
|
|
jmp go4kVCO_func_process
|
|
go4kVCO_func_stereodone:
|
|
%endif
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodc code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // VCF Tick
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY : eax
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kVCF_func@0
|
|
push 3
|
|
call go4kTransformValues
|
|
%ifdef GO4K_USE_VCF_CHECK
|
|
; check if current note still active
|
|
mov eax, dword [ecx-4]
|
|
test eax, eax
|
|
jne go4kVCF_func_do
|
|
ret
|
|
go4kVCF_func_do:
|
|
%endif
|
|
movzx eax, byte [VAL-1] ; // get type flag
|
|
|
|
fld dword [edx+go4kVCF_val.res] ; // r in
|
|
%ifdef GO4K_USE_VCF_MOD_RM
|
|
fadd dword [WRK+go4kVCF_wrk.rm]
|
|
%endif
|
|
fstp dword [esp-8]
|
|
|
|
fld dword [edx+go4kVCF_val.freq] ; // f in
|
|
%ifdef GO4K_USE_VCF_MOD_FM
|
|
fadd dword [WRK+go4kVCF_wrk.fm]
|
|
%endif
|
|
fmul st0, st0 ; // square the input so we never get negative and also have a smoother behaviour in the lower frequencies
|
|
fstp dword [esp-4] ; // in
|
|
|
|
%ifdef GO4K_USE_VCF_STEREO
|
|
test al, byte STEREO
|
|
jz short go4kVCF_func_process
|
|
add WRK, go4kVCF_wrk.low2
|
|
go4kVCF_func_stereoloop: ; // switch channels
|
|
fxch st1 ; // inr inl
|
|
%endif
|
|
|
|
go4kVCF_func_process:
|
|
fld dword [esp-8]
|
|
fld dword [esp-4]
|
|
fmul dword [WRK+go4kVCF_wrk.band] ; // f*b r in
|
|
fadd dword [WRK+go4kVCF_wrk.low] ; // l' r in
|
|
fst dword [WRK+go4kVCF_wrk.low] ; // l' r in
|
|
fsubp st2, st0 ; // r in-l'
|
|
fmul dword [WRK+go4kVCF_wrk.band] ; // r*b in-l'
|
|
fsubp st1, st0 ; // h'
|
|
fst dword [WRK+go4kVCF_wrk.high] ; // h'
|
|
fmul dword [esp-4] ; // h'*f
|
|
fadd dword [WRK+go4kVCF_wrk.band] ; // b'
|
|
fstp dword [WRK+go4kVCF_wrk.band]
|
|
fldz
|
|
go4kVCF_func_low:
|
|
test al, byte LOWPASS
|
|
jz short go4kVCF_func_high
|
|
fadd dword [WRK+go4kVCF_wrk.low]
|
|
go4kVCF_func_high:
|
|
%ifdef GO4K_USE_VCF_HIGH
|
|
test al, byte HIGHPASS
|
|
jz short go4kVCF_func_band
|
|
fadd dword [WRK+go4kVCF_wrk.high]
|
|
%endif
|
|
go4kVCF_func_band:
|
|
%ifdef GO4K_USE_VCF_BAND
|
|
test al, byte BANDPASS
|
|
jz short go4kVCF_func_peak
|
|
fadd dword [WRK+go4kVCF_wrk.band]
|
|
%endif
|
|
go4kVCF_func_peak:
|
|
%ifdef GO4K_USE_VCF_PEAK
|
|
test al, byte PEAK
|
|
jz short go4kVCF_func_processdone
|
|
fadd dword [WRK+go4kVCF_wrk.low]
|
|
fsub dword [WRK+go4kVCF_wrk.high]
|
|
%endif
|
|
go4kVCF_func_processdone:
|
|
|
|
%ifdef GO4K_USE_VCF_STEREO
|
|
test al, byte STEREO ; // outr inl
|
|
jz short go4kVCF_func_end
|
|
sub al, byte STEREO
|
|
sub WRK, go4kVCF_wrk.low2
|
|
jmp go4kVCF_func_stereoloop
|
|
%endif
|
|
|
|
go4kVCF_func_end: ; // value - - - -
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodd code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // DST Tick
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY : eax
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kDST_func@0
|
|
%ifdef GO4K_USE_DST
|
|
%ifdef GO4K_USE_DST_SH
|
|
%ifdef GO4K_USE_DST_STEREO
|
|
push 3
|
|
%else
|
|
push 2
|
|
%endif
|
|
%else
|
|
%ifdef GO4K_USE_DST_STEREO
|
|
push 2
|
|
%else
|
|
push 1
|
|
%endif
|
|
%endif
|
|
call go4kTransformValues
|
|
%ifdef GO4K_USE_DST_CHECK
|
|
; check if current note still active
|
|
mov eax, dword [ecx-4]
|
|
test eax, eax
|
|
jne go4kDST_func_do
|
|
ret
|
|
go4kDST_func_do:
|
|
%endif
|
|
movzx eax, byte [VAL-1] ; // get type flag
|
|
%ifdef GO4K_USE_DST_SH
|
|
fld dword [edx+go4kDST_val.snhfreq] ; // snh in (inr)
|
|
%ifdef GO4K_USE_DST_MOD_SH
|
|
fadd dword [WRK+go4kDST_wrk.sm] ; // snh' in (inr)
|
|
%endif
|
|
fmul st0, st0 ; // square the input so we never get negative and also have a smoother behaviour in the lower frequencies
|
|
fchs
|
|
fadd dword [WRK+go4kDST_wrk.snhphase]; // snh' in (inr)
|
|
fst dword [WRK+go4kDST_wrk.snhphase]
|
|
fldz ; // 0 snh' in (inr)
|
|
fucomip st1 ; // snh' in (inr)
|
|
fstp dword [esp-4] ; // in (inr)
|
|
jc short go4kDST_func_hold
|
|
fld1 ; // 1 in (inr)
|
|
fadd dword [esp-4] ; // 1+snh' in (inr)
|
|
fstp dword [WRK+go4kDST_wrk.snhphase]; // in (inr)
|
|
%endif
|
|
; // calc pregain and postgain
|
|
%ifdef GO4K_USE_DST_STEREO
|
|
test al, byte STEREO
|
|
jz short go4kDST_func_mono
|
|
fxch st1 ; // inr inl
|
|
fld dword [edx+go4kDST_val.drive] ; // drive inr inl
|
|
%ifdef GO4K_USE_DST_MOD_DM
|
|
fadd dword [WRK+go4kDST_wrk.dm]
|
|
%endif
|
|
call go4kWaveshaper ; // outr inl
|
|
%ifdef GO4K_USE_DST_SH
|
|
fst dword [WRK+go4kDST_wrk.out2] ; // outr inl
|
|
%endif
|
|
fxch st1 ; // inl outr
|
|
go4kDST_func_mono:
|
|
%endif
|
|
fld dword [edx+go4kDST_val.drive] ; // drive in (outr)
|
|
%ifdef GO4K_USE_DST_MOD_DM
|
|
fadd dword [WRK+go4kDST_wrk.dm]
|
|
%endif
|
|
call go4kWaveshaper ; // out (outr)
|
|
%ifdef GO4K_USE_DST_SH
|
|
fst dword [WRK+go4kDST_wrk.out] ; // out' (outr)
|
|
%endif
|
|
ret ; // out' (outr)
|
|
%ifdef GO4K_USE_DST_SH
|
|
go4kDST_func_hold: ; // in (inr)
|
|
fstp st0 ; // (inr)
|
|
%ifdef GO4K_USE_DST_STEREO
|
|
test al, byte STEREO
|
|
jz short go4kDST_func_monohold ; // (inr)
|
|
fstp st0 ; //
|
|
fld dword [WRK+go4kDST_wrk.out2] ; // outr
|
|
go4kDST_func_monohold:
|
|
%endif
|
|
fld dword [WRK+go4kDST_wrk.out] ; // out (outr)
|
|
ret
|
|
%endif
|
|
|
|
%endif
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodf code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // DLL Tick
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY : eax
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kDLL_func@0
|
|
%ifdef GO4K_USE_DLL
|
|
%ifdef GO4K_USE_DLL_CHORUS
|
|
%ifdef GO4K_USE_DLL_DAMP
|
|
push 8
|
|
%else
|
|
push 7
|
|
%endif
|
|
%else
|
|
%ifdef GO4K_USE_DLL_DAMP
|
|
push 6
|
|
%else
|
|
push 5
|
|
%endif
|
|
%endif
|
|
call go4kTransformValues
|
|
pushad
|
|
movzx ebx, byte [VAL-(go4kDLL_val.size-go4kDLL_val.delay)/4] ;// delay length index
|
|
%ifdef GO4K_USE_DLL_NOTE_SYNC
|
|
test ebx, ebx
|
|
jne go4kDLL_func_process
|
|
fld1
|
|
fild dword [ecx-4] ; // load note freq
|
|
fmul dword [c_i12]
|
|
call _Power@0
|
|
fmul dword [FREQ_NORMALIZE] ; // normalize
|
|
fdivp st1, st0 ; // invert to get numer of samples
|
|
fistp word [_go4k_delay_times+ebx*2] ; store current comb size
|
|
%endif
|
|
go4kDLL_func_process:
|
|
mov ecx, eax ;// ecx is delay counter
|
|
%ifdef GO4K_USE_DLL_MOD
|
|
mov edi, WRK ;// edi is modulation workspace
|
|
%endif
|
|
mov WRK, dword [_go4k_delay_buffer_ofs] ;// ebp is current delay
|
|
fld st0 ;// in in
|
|
%ifdef GO4K_USE_DLL_MOD_IM
|
|
fld dword [edx+go4kDLL_val.dry] ;// dry in in
|
|
fadd dword [edi+go4kDLL_wrk2.im] ;// dry' in in
|
|
fmulp st1, st0 ;// out in
|
|
%else
|
|
fmul dword [edx+go4kDLL_val.dry] ;// out in
|
|
%endif
|
|
fxch ;// in out
|
|
%ifdef GO4K_USE_DLL_MOD_PM
|
|
fld dword [edx+go4kDLL_val.pregain] ;// pg in out
|
|
fadd dword [edi+go4kDLL_wrk2.pm] ;// pg' in out
|
|
fmul st0, st0 ;// pg'' in out
|
|
fmulp st1, st0 ;// in' out
|
|
%else
|
|
fmul dword [edx+go4kDLL_val.pregain] ;// in' out
|
|
fmul dword [edx+go4kDLL_val.pregain] ;// in' out
|
|
%endif
|
|
|
|
%ifdef GO4K_USE_DLL_CHORUS
|
|
;// update saw lfo for chorus/flanger
|
|
fld dword [edx+go4kDLL_val.freq] ;// f in' out
|
|
%ifdef GO4K_USE_DLL_MOD_SM
|
|
fadd dword [edi+go4kDLL_wrk2.sm] ;// f' in' out
|
|
%endif
|
|
fmul st0, st0
|
|
fmul st0, st0
|
|
fdiv dword [DLL_DEPTH]
|
|
fadd dword [WRK+go4kDLL_wrk.phase] ;// p' in' out
|
|
;// clamp phase to 0,1 (only in editor, since delay can be active quite long)
|
|
%ifdef GO4K_USE_DLL_CHORUS_CLAMP
|
|
fld1 ;// 1 p' in' out
|
|
fadd st1, st0 ;// 1 1+p' in' out
|
|
fxch ;// 1+p' 1 in' out
|
|
fprem ;// p'' 1 in' out
|
|
fstp st1 ;// p'' in' out
|
|
%endif
|
|
fst dword [WRK+go4kDLL_wrk.phase]
|
|
;// get current sine value
|
|
fldpi ; // pi p in' out
|
|
fadd st0 ; // 2*pi p in' out
|
|
fmulp st1, st0 ; // 2*pi*p in' out
|
|
fsin ; // sin in' out
|
|
fld1 ; // 1 sin in' out
|
|
faddp st1, st0 ; // 1+sin in' out
|
|
;// mul with depth and convert to samples
|
|
fld dword [edx+go4kDLL_val.depth] ; // d 1+sin in' out
|
|
%ifdef GO4K_USE_DLL_MOD_AM
|
|
fadd dword [edi+go4kDLL_wrk2.am] ; // d' 1+sin in' out
|
|
%endif
|
|
fmul st0, st0
|
|
fmul st0, st0
|
|
fmul dword [DLL_DEPTH]
|
|
fmulp st1, st0
|
|
fistp dword [esp-4] ; // in' out
|
|
%endif
|
|
|
|
go4kDLL_func_loop:
|
|
movzx esi, word [_go4k_delay_times+ebx*2] ; fetch comb size
|
|
mov eax, dword [WRK+go4kDLL_wrk.index] ;// eax is current comb index
|
|
|
|
%ifdef GO4K_USE_DLL_CHORUS
|
|
;// add lfo offset and wrap buffer
|
|
add eax, dword [esp-4]
|
|
cmp eax, esi
|
|
jl short go4kDLL_func_buffer_nowrap1
|
|
sub eax, esi
|
|
go4kDLL_func_buffer_nowrap1:
|
|
%endif
|
|
|
|
fld dword [WRK+eax*4+go4kDLL_wrk.buffer];// cout in' out
|
|
|
|
%ifdef GO4K_USE_DLL_CHORUS
|
|
mov eax, dword [WRK+go4kDLL_wrk.index]
|
|
%endif
|
|
|
|
;// add comb output to current output
|
|
fadd st2, st0 ;// cout in' out'
|
|
%ifdef GO4K_USE_DLL_DAMP
|
|
fld1 ;// 1 cout in' out'
|
|
fsub dword [edx+go4kDLL_val.damp] ;// 1-damp cout in' out'
|
|
%ifdef GO4K_USE_DLL_MOD_DM
|
|
fsub dword [edi+go4kDLL_wrk2.dm] ;// 1-damp' cout in' out'
|
|
%endif
|
|
fmulp st1, st0 ;// cout*d2 in' out'
|
|
fld dword [edx+go4kDLL_val.damp] ;// d1 cout*d2 in' out'
|
|
%ifdef GO4K_USE_DLL_MOD_DM
|
|
fadd dword [edi+go4kDLL_wrk2.dm] ;// d1' cout*d2 in' out'
|
|
%endif
|
|
fmul dword [WRK+go4kDLL_wrk.store] ;// store*d1 cout*d2 in' out'
|
|
faddp st1, st0 ;// store' in' out'
|
|
fst dword [WRK+go4kDLL_wrk.store] ;// store' in' out'
|
|
%endif
|
|
%ifdef GO4K_USE_DLL_MOD_FM
|
|
fld dword [edx+go4kDLL_val.feedback] ;// fb cout in' out'
|
|
fadd dword [edi+go4kDLL_wrk2.fm] ;// fb' cout in' out'
|
|
fmulp st1, st0 ;// cout*fb' in' out'
|
|
%else
|
|
fmul dword [edx+go4kDLL_val.feedback] ;// cout*fb in' out'
|
|
%endif
|
|
%ifdef GO4K_USE_DLL_DC_FILTER
|
|
fadd st0, st1 ;// store in' out'
|
|
fstp dword [WRK+eax*4+go4kDLL_wrk.buffer];// in' out'
|
|
%else
|
|
fsub st0, st1 ;// store in' out'
|
|
fstp dword [WRK+eax*4+go4kDLL_wrk.buffer];// in' out'
|
|
fneg
|
|
%endif
|
|
;// wrap comb buffer pos
|
|
inc eax
|
|
cmp eax, esi
|
|
jl short go4kDLL_func_buffer_nowrap2
|
|
%ifdef GO4K_USE_DLL_CHORUS
|
|
sub eax, esi
|
|
%else
|
|
xor eax, eax
|
|
%endif
|
|
go4kDLL_func_buffer_nowrap2:
|
|
mov dword [WRK+go4kDLL_wrk.index], eax
|
|
;// increment buffer pointer to next buffer
|
|
inc ebx ;// go to next delay length index
|
|
add WRK, go4kDLL_wrk.size ;// go to next delay
|
|
mov dword [_go4k_delay_buffer_ofs], WRK ;// store next delay offset
|
|
loopne go4kDLL_func_loop
|
|
fstp st0 ;// out'
|
|
;// process a dc filter to prevent heavy offsets in reverb
|
|
%ifdef GO4K_USE_DLL_DC_FILTER
|
|
; y(n) = x(n) - x(n-1) + R * y(n-1)
|
|
sub WRK, go4kDLL_wrk.size
|
|
fld dword [WRK+go4kDLL_wrk.dcout] ;// dco out'
|
|
fmul dword [c_dc_const] ;// dcc*dco out'
|
|
fsub dword [WRK+go4kDLL_wrk.dcin] ;// dcc*dco-dci out'
|
|
fxch ;// out' dcc*dco-dci
|
|
fst dword [WRK+go4kDLL_wrk.dcin] ;// out' dcc*dco-dci
|
|
faddp st1 ;// out'
|
|
%ifdef GO4K_USE_UNDENORMALIZE
|
|
fadd dword [c_0_5] ;// add and sub small offset to prevent denormalization
|
|
fsub dword [c_0_5]
|
|
%endif
|
|
fst dword [WRK+go4kDLL_wrk.dcout]
|
|
%endif
|
|
popad
|
|
ret
|
|
%endif
|
|
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodu code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // GLITCH Tick
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY : eax
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kGLITCH_func@0
|
|
%ifdef GO4K_USE_GLITCH
|
|
push 5
|
|
call go4kTransformValues
|
|
pushad
|
|
|
|
mov edi, WRK
|
|
mov WRK, dword [_go4k_delay_buffer_ofs] ;// ebp is current delay
|
|
|
|
; mov eax, dword [edx+go4kGLITCH_val.active]
|
|
; or eax, dword [edi+go4kGLITCH_wrk2.am]
|
|
; test eax, eax
|
|
; je go4kGLITCH_func_notactive ;// out
|
|
|
|
fld dword [edx+go4kGLITCH_val.active] ;// a in
|
|
fadd dword [edi+go4kGLITCH_wrk2.am] ;// a' in
|
|
; // check for activity
|
|
fldz ;// 0 a' in
|
|
fucomip st1 ;// a' in
|
|
fstp st0 ;// in
|
|
jnc go4kGLITCH_func_notactive ;// out
|
|
|
|
;// check for first call and init if so init (using slizesize slot)
|
|
mov eax, dword [WRK+go4kGLITCH_wrk.slizesize]
|
|
and eax, eax
|
|
jnz go4kGLITCH_func_process
|
|
mov dword [WRK+go4kGLITCH_wrk.index], eax
|
|
mov dword [WRK+go4kGLITCH_wrk.store], eax
|
|
movzx ebx, byte [VAL-(go4kGLITCH_val.size-go4kGLITCH_val.slicesize)/4] ;// slicesize index
|
|
movzx eax, word [_go4k_delay_times+ebx*2] ;// fetch slicesize
|
|
push eax
|
|
fld1
|
|
fild dword [esp]
|
|
fstp dword [WRK+go4kGLITCH_wrk.slizesize]
|
|
fstp dword [WRK+go4kGLITCH_wrk.slicepitch]
|
|
pop eax
|
|
go4kGLITCH_func_process:
|
|
;// fill buffer until full
|
|
mov eax, dword [WRK+go4kGLITCH_wrk.store]
|
|
cmp eax, MAX_DELAY
|
|
jae go4kGLITCH_func_filldone
|
|
fst dword [WRK+eax*4+go4kDLL_wrk.buffer] ;// in
|
|
inc dword [WRK+go4kGLITCH_wrk.store]
|
|
go4kGLITCH_func_filldone:
|
|
;// save input
|
|
push eax
|
|
fstp dword [esp] ;// -
|
|
|
|
;// read from buffer
|
|
push eax
|
|
fld dword [WRK+go4kGLITCH_wrk.index] ;// idx
|
|
fist dword [esp]
|
|
pop eax
|
|
fld dword [WRK+eax*4+go4kDLL_wrk.buffer] ;// out idx
|
|
fxch ;// idx out
|
|
;// progress readindex with current play speed
|
|
fadd dword [WRK+go4kGLITCH_wrk.slicepitch] ;// idx' out
|
|
fst dword [WRK+go4kGLITCH_wrk.index]
|
|
|
|
;// check for slice done
|
|
fld dword [WRK+go4kGLITCH_wrk.slizesize] ;// size idx' out
|
|
fxch ;// idx' size out
|
|
fucomip st1 ;// idx' out
|
|
fstp st0 ;// out
|
|
jc go4kGLITCH_func_process_done
|
|
;// reinit for next loop
|
|
xor eax, eax
|
|
mov dword [WRK+go4kGLITCH_wrk.index], eax
|
|
|
|
fld dword [edx+go4kGLITCH_val.dsize]
|
|
fadd dword [edi+go4kGLITCH_wrk2.sm]
|
|
fsub dword [c_0_5]
|
|
fmul dword [c_0_5]
|
|
call _Power@0
|
|
fmul dword [WRK+go4kGLITCH_wrk.slizesize]
|
|
fstp dword [WRK+go4kGLITCH_wrk.slizesize]
|
|
|
|
fld dword [edx+go4kGLITCH_val.dpitch]
|
|
fadd dword [edi+go4kGLITCH_wrk2.pm]
|
|
fsub dword [c_0_5]
|
|
fmul dword [c_0_5]
|
|
call _Power@0
|
|
fmul dword [WRK+go4kGLITCH_wrk.slicepitch]
|
|
fstp dword [WRK+go4kGLITCH_wrk.slicepitch]
|
|
go4kGLITCH_func_process_done:
|
|
|
|
;// dry wet mix
|
|
fld dword [edx+go4kGLITCH_val.dry] ;// dry out
|
|
fadd dword [edi+go4kGLITCH_wrk2.dm] ;// dry' out
|
|
fld1 ;// 1 dry' out
|
|
fsub st1 ;// 1-dry' dry' out
|
|
fmulp st2 ;// dry' out'
|
|
fmul dword [esp] ;// in' out'
|
|
faddp st1, st0 ;// out'
|
|
|
|
pop eax
|
|
jmp go4kGLITCH_func_leave
|
|
go4kGLITCH_func_notactive:
|
|
;// mark as uninitialized again (using slizesize slot)
|
|
xor eax,eax
|
|
mov dword [WRK+go4kGLITCH_wrk.slizesize], eax
|
|
go4kGLITCH_func_leave:
|
|
add WRK, go4kDLL_wrk.size ;// go to next delay
|
|
mov dword [_go4k_delay_buffer_ofs], WRK ;// store next delay offset
|
|
popad
|
|
ret
|
|
%endif
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodg code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // FOP Tick (various fp stack based operations)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kFOP_func@0
|
|
push 1
|
|
call go4kTransformValues
|
|
go4kFOP_func_pop:
|
|
dec eax
|
|
jnz go4kFOP_func_addp
|
|
fstp st0
|
|
ret
|
|
go4kFOP_func_addp:
|
|
dec eax
|
|
jnz go4kFOP_func_mulp
|
|
faddp st1, st0
|
|
ret
|
|
go4kFOP_func_mulp:
|
|
dec eax
|
|
jnz go4kFOP_func_push
|
|
fmulp st1, st0
|
|
ret
|
|
go4kFOP_func_push:
|
|
dec eax
|
|
jnz go4kFOP_func_xch
|
|
fld st0
|
|
ret
|
|
go4kFOP_func_xch:
|
|
dec eax
|
|
jnz go4kFOP_func_add
|
|
fxch
|
|
ret
|
|
go4kFOP_func_add:
|
|
dec eax
|
|
jnz go4kFOP_func_mul
|
|
fadd st1
|
|
ret
|
|
go4kFOP_func_mul:
|
|
dec eax
|
|
jnz go4kFOP_func_addp2
|
|
fmul st1
|
|
ret
|
|
go4kFOP_func_addp2:
|
|
dec eax
|
|
jnz go4kFOP_func_loadnote
|
|
faddp st2, st0
|
|
faddp st2, st0
|
|
ret
|
|
go4kFOP_func_loadnote:
|
|
dec eax
|
|
jnz go4kFOP_func_mulp2
|
|
fild dword [ecx-4]
|
|
fmul dword [c_i128]
|
|
ret
|
|
go4kFOP_func_mulp2:
|
|
fmulp st2, st0
|
|
fmulp st2, st0
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodh code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // FST Tick (stores a value somewhere in the local workspace)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kFST_func@0
|
|
push 1
|
|
call go4kTransformValues
|
|
fld dword [edx+go4kFST_val.amount]
|
|
fsub dword [c_0_5]
|
|
fadd st0
|
|
fmul st1
|
|
lodsw
|
|
and eax, 0x00003fff ; // eax is destination slot
|
|
test word [VAL-2], FST_ADD
|
|
jz go4kFST_func_set
|
|
fadd dword [ecx+eax*4]
|
|
go4kFST_func_set:
|
|
fstp dword [ecx+eax*4]
|
|
test word [VAL-2], FST_POP
|
|
jz go4kFST_func_done
|
|
fstp st0
|
|
go4kFST_func_done:
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodm code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // FLD Tick (load a value on stack, optionally add a modulation signal beforehand)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT : signal-signal*pan , signal*pan
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kFLD_func@0 ;// in main env
|
|
%ifdef GO4K_USE_FLD
|
|
push 1
|
|
call go4kTransformValues
|
|
fld dword [edx+go4kFLD_val.value] ;// value in
|
|
fsub dword [c_0_5]
|
|
fadd st0
|
|
%ifdef GO4K_USE_FLD_MOD_VM
|
|
fadd dword [WRK+go4kFLD_wrk.vm] ;// value' in
|
|
%endif
|
|
%endif
|
|
ret
|
|
|
|
%ifdef GO4K_USE_FSTG
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodi code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // FSTG Tick (stores a value anywhere in the synth (and in each voice))
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kFSTG_func@0
|
|
push 1
|
|
call go4kTransformValues
|
|
%ifdef GO4K_USE_FSTG_CHECK
|
|
; check if current note still active
|
|
mov eax, dword [ecx-4]
|
|
test eax, eax
|
|
jne go4kFSTG_func_do
|
|
lodsw
|
|
jmp go4kFSTG_func_testpop
|
|
go4kFSTG_func_do:
|
|
%endif
|
|
fld dword [edx+go4kFST_val.amount]
|
|
fsub dword [c_0_5]
|
|
fadd st0
|
|
fmul st1
|
|
lodsw
|
|
and eax, 0x00003fff ; // eax is destination slot
|
|
test word [VAL-2], FST_ADD
|
|
jz go4kFSTG_func_set
|
|
fadd dword [go4k_synth_wrk+eax*4]
|
|
go4kFSTG_func_set:
|
|
%if MAX_VOICES > 1
|
|
fst dword [go4k_synth_wrk+eax*4]
|
|
fstp dword [go4k_synth_wrk+eax*4+go4k_instrument.size]
|
|
%else
|
|
fstp dword [go4k_synth_wrk+eax*4]
|
|
%endif
|
|
go4kFSTG_func_testpop:
|
|
test word [VAL-2], FST_POP
|
|
jz go4kFSTG_func_done
|
|
fstp st0
|
|
go4kFSTG_func_done:
|
|
ret
|
|
%endif
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodj code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // PAN Tick (multiplies signal with main envelope and converts to stereo)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT : signal-signal*pan , signal*pan
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kPAN_func@0 ;// in main env
|
|
%ifdef GO4K_USE_PAN
|
|
push 1
|
|
call go4kTransformValues
|
|
fld dword [edx+go4kPAN_val.panning] ;// pan in
|
|
%ifdef GO4K_USE_PAN_MOD
|
|
fadd dword [WRK+go4kPAN_wrk.pm] ;// pan in
|
|
%endif
|
|
fmul st1 ;// r in
|
|
fsub st1, st0 ;// r l
|
|
fxch ;// l r
|
|
%else
|
|
fmul dword [c_0_5]
|
|
fld st0
|
|
%endif
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodk code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // OUT Tick ( stores stereo signal pair in temp buffers of the instrument)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kOUT_func@0 ;// l r
|
|
%ifdef GO4K_USE_GLOBAL_DLL
|
|
push 2
|
|
call go4kTransformValues
|
|
pushad
|
|
lea edi, [ecx+MAX_UNITS*MAX_UNIT_SLOTS*4]
|
|
fld st1 ;// r l r
|
|
fld st1 ;// l r l r
|
|
fld dword [edx+go4kOUT_val.auxsend] ;// as l r l r
|
|
%ifdef GO4K_USE_OUT_MOD_AM
|
|
fadd dword [WRK+go4kOUT_wrk.am] ;// am l r l r
|
|
%endif
|
|
fmulp st1, st0 ;// l' r l r
|
|
fstp dword [edi] ;// r l r
|
|
scasd
|
|
fld dword [edx+go4kOUT_val.auxsend] ;// as r l r
|
|
%ifdef GO4K_USE_OUT_MOD_AM
|
|
fadd dword [WRK+go4kOUT_wrk.am] ;// am r l r
|
|
%endif
|
|
fmulp st1, st0 ;// r' l r
|
|
fstp dword [edi] ;// l r
|
|
scasd
|
|
fld dword [edx+go4kOUT_val.gain] ;// g l r
|
|
%ifdef GO4K_USE_OUT_MOD_GM
|
|
fadd dword [WRK+go4kOUT_wrk.gm] ;// gm l r
|
|
%endif
|
|
fmulp st1, st0 ;// l' r
|
|
fstp dword [edi] ;// r
|
|
scasd
|
|
fld dword [edx+go4kOUT_val.gain] ;// g r
|
|
%ifdef GO4K_USE_OUT_MOD_GM
|
|
fadd dword [WRK+go4kOUT_wrk.gm] ;// gm r
|
|
%endif
|
|
fmulp st1, st0 ;// r'
|
|
fstp dword [edi] ;// -
|
|
scasd
|
|
popad
|
|
%else
|
|
push 1
|
|
call go4kTransformValues
|
|
|
|
fld dword [edx+go4kOUT_val.gain] ;// g l r
|
|
%ifdef GO4K_USE_OUT_MOD_GM
|
|
fadd dword [WRK+go4kOUT_wrk.gm] ;// gm l r
|
|
%endif
|
|
fmulp st1, st0 ;// l' r
|
|
fstp dword [ecx+MAX_UNITS*MAX_UNIT_SLOTS*4+0] ;// r
|
|
fld dword [edx+go4kOUT_val.gain] ;// g r
|
|
%ifdef GO4K_USE_OUT_MOD_GM
|
|
fadd dword [WRK+go4kOUT_wrk.gm] ;// gm r
|
|
%endif
|
|
fmulp st1, st0 ;// r'
|
|
fstp dword [ecx+MAX_UNITS*MAX_UNIT_SLOTS*4+4] ;// -
|
|
|
|
%endif
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodl code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // ACC Tick (stereo signal accumulation for synth commands only -> dont use in instrument commands)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : WRK = unit workspace
|
|
; // IN : VAL = unit values
|
|
; // IN : ecx = global workspace
|
|
; // OUT :
|
|
; // DIRTY : eax
|
|
; //----------------------------------------------------------------------------------------
|
|
export_func go4kACC_func@0
|
|
push 1
|
|
call go4kTransformValues
|
|
pushad
|
|
mov edi, go4k_synth_wrk
|
|
add edi, go4k_instrument.size
|
|
sub edi, eax ; // eax already contains the accumulation offset from the go4kTransformValues call
|
|
mov cl, MAX_INSTRUMENTS*MAX_VOICES
|
|
fldz ;// 0
|
|
fldz ;// 0 0
|
|
go4kACC_func_loop:
|
|
fadd dword [edi-8] ;// l 0
|
|
fxch ;// 0 l
|
|
fadd dword [edi-4] ;// r l
|
|
fxch ;// l r
|
|
add edi, go4k_instrument.size
|
|
dec cl
|
|
jnz go4kACC_func_loop
|
|
popad
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodw code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // Update Instrument (allocate voices, set voice to release)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN :
|
|
; // IN :
|
|
; // OUT :
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
go4kUpdateInstrument:
|
|
; // get new note
|
|
mov eax, dword [esp+4+4] ; // eax = current tick
|
|
shr eax, PATTERN_SIZE_SHIFT ; // eax = current pattern
|
|
imul edx, ecx, dword MAX_PATTERNS ; // edx = instrument pattern list index
|
|
movzx edx, byte [edx+eax+go4k_pattern_lists] ; // edx = pattern index
|
|
mov eax, dword [esp+4+4] ; // eax = current tick
|
|
shl edx, PATTERN_SIZE_SHIFT
|
|
and eax, PATTERN_SIZE-1
|
|
movzx edx, byte [edx+eax+go4k_patterns] ; // edx = requested note in new patterntick
|
|
; // apply note changes
|
|
cmp dl, HLD ; // anything but hold causes action
|
|
je short go4kUpdateInstrument_done
|
|
inc dword [edi] ; // set release flag if needed
|
|
%if MAX_VOICES > 1
|
|
inc dword [edi+go4k_instrument.size] ; // set release flag if needed
|
|
%endif
|
|
cmp dl, HLD ; // check for new note
|
|
jl short go4kUpdateInstrument_done
|
|
%if MAX_VOICES > 1
|
|
pushad
|
|
xchg eax, dword [go4k_voiceindex + ecx*4]
|
|
test eax, eax
|
|
je go4kUpdateInstrument_newNote
|
|
add edi, go4k_instrument.size
|
|
go4kUpdateInstrument_newNote:
|
|
xor al,1
|
|
xchg dword [go4k_voiceindex + ecx*4], eax
|
|
%endif
|
|
pushad
|
|
xor eax, eax
|
|
mov ecx, (8+MAX_UNITS*MAX_UNIT_SLOTS*4)/4 ; // clear only relase, note and workspace
|
|
rep stosd
|
|
popad
|
|
mov dword [edi+4], edx ; // set requested note as current note
|
|
%if MAX_VOICES > 1
|
|
popad
|
|
%endif
|
|
jmp short go4kUpdateInstrument_done
|
|
go4kUpdateInstrument_done:
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodx code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // Render Voices
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN :
|
|
; // IN :
|
|
; // OUT :
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
go4kRenderVoices:
|
|
push ecx ; // save current instrument counter
|
|
%if MAX_VOICES > 1
|
|
push COM ; // save current instrument command index
|
|
push VAL ; // save current instrument values index
|
|
%endif
|
|
call go4k_VM_process ; // call synth vm for instrument voices
|
|
mov eax, dword [ecx+go4kENV_wrk.state]
|
|
cmp al, byte ENV_STATE_OFF
|
|
jne go4kRenderVoices_next
|
|
xor eax, eax
|
|
mov dword [ecx-4], eax ; // kill note if voice is done
|
|
go4kRenderVoices_next:
|
|
%if MAX_VOICES > 1
|
|
pop VAL ; // restore instrument value index
|
|
pop COM ; // restore instrument command index
|
|
%endif
|
|
|
|
%ifdef GO4K_USE_BUFFER_RECORDINGS
|
|
mov eax, dword [esp+16] ; // get current tick
|
|
shr eax, 8 ; // every 256th sample = ~ 172 hz
|
|
shl eax, 5 ; // for 16 instruments a 2 voices
|
|
add eax, dword [esp]
|
|
add eax, dword [esp] ; // + 2*currentinstrument+0
|
|
%ifdef GO4K_USE_ENVELOPE_RECORDINGS
|
|
mov edx, dword [ecx+go4kENV_wrk.level]
|
|
mov dword [__4klang_envelope_buffer+eax*4], edx
|
|
%endif
|
|
%ifdef GO4K_USE_NOTE_RECORDINGS
|
|
mov edx, dword [ecx-4]
|
|
mov dword [__4klang_note_buffer+eax*4], edx
|
|
%endif
|
|
%endif
|
|
|
|
%if MAX_VOICES > 1
|
|
call go4k_VM_process ; // call synth vm for instrument voices
|
|
mov eax, dword [ecx+go4kENV_wrk.state]
|
|
cmp al, byte ENV_STATE_OFF
|
|
jne go4k_render_instrument_next2
|
|
xor eax, eax
|
|
mov dword [ecx-4], eax ; // kill note if voice is done
|
|
go4k_render_instrument_next2:
|
|
|
|
%ifdef GO4K_USE_BUFFER_RECORDINGS
|
|
mov eax, dword [esp+16] ; // get current tick
|
|
shr eax, 8 ; // every 256th sample = ~ 172 hz
|
|
shl eax, 5 ; // for 16 instruments a 2 voices
|
|
add eax, dword [esp]
|
|
add eax, dword [esp] ; // + 2*currentinstrument+0
|
|
%ifdef GO4K_USE_ENVELOPE_RECORDINGS
|
|
mov edx, dword [ecx+go4kENV_wrk.level]
|
|
mov dword [__4klang_envelope_buffer+eax*4+4], edx
|
|
%endif
|
|
%ifdef GO4K_USE_NOTE_RECORDINGS
|
|
mov edx, dword [ecx-4]
|
|
mov dword [__4klang_note_buffer+eax*4+4], edx
|
|
%endif
|
|
%endif
|
|
|
|
%endif
|
|
pop ecx ; // restore instrument counter
|
|
ret
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcody code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // the entry point for the synth
|
|
; //----------------------------------------------------------------------------------------
|
|
%ifdef USE_SECTIONS
|
|
export_func _4klang_render@4
|
|
%else
|
|
export_func _4klang_render
|
|
%endif
|
|
pushad
|
|
xor ecx, ecx
|
|
%ifdef GO4K_USE_BUFFER_RECORDINGS
|
|
push ecx
|
|
%endif
|
|
; loop all ticks
|
|
go4k_render_tickloop:
|
|
push ecx
|
|
xor ecx, ecx
|
|
; loop all samples per tick
|
|
go4k_render_sampleloop:
|
|
push ecx
|
|
xor ecx, ecx
|
|
mov ebx, go4k_synth_instructions ; // ebx = instrument command index
|
|
mov VAL, go4k_synth_parameter_values; // VAL = instrument values index
|
|
mov edi, _go4k_delay_buffer ; // get offset of first delay buffer
|
|
mov dword [_go4k_delay_buffer_ofs], edi ; // store offset in delaybuffer offset variable
|
|
mov edi, go4k_synth_wrk ; // edi = first instrument
|
|
; loop all instruments
|
|
go4k_render_instrumentloop:
|
|
mov eax, dword [esp] ; // eax = current tick sample
|
|
and eax, eax
|
|
jnz go4k_render_instrument_process ; // tick change? (first sample in current tick)
|
|
call go4kUpdateInstrument ; // update instrument state
|
|
; process instrument
|
|
go4k_render_instrument_process:
|
|
call go4kRenderVoices
|
|
inc ecx
|
|
cmp cl, byte MAX_INSTRUMENTS
|
|
jl go4k_render_instrumentloop
|
|
mov dword [edi+4], ecx ; // move a value != 0 into note slot, so processing will be done
|
|
call go4k_VM_process ; // call synth vm for synth
|
|
go4k_render_output_sample:
|
|
%ifdef GO4K_USE_BUFFER_RECORDINGS
|
|
inc dword [esp+8]
|
|
xchg esi, dword [esp+48] ; // edx = destbuffer
|
|
%else
|
|
xchg esi, dword [esp+44] ; // edx = destbuffer
|
|
%endif
|
|
%ifdef GO4K_CLIP_OUTPUT
|
|
fld dword [edi-8]
|
|
fld1 ; // 1 val
|
|
fucomi st1 ; // 1 val
|
|
jbe short go4k_render_clip1
|
|
fchs ; // -1 val
|
|
fucomi st1 ; // -1 val
|
|
fcmovb st0, st1 ; // val -1 (if val > -1)
|
|
go4k_render_clip1:
|
|
fstp st1 ; // newval
|
|
%ifdef GO4K_USE_16BIT_OUTPUT
|
|
push eax
|
|
fmul dword [c_32767]
|
|
fistp dword [esp]
|
|
pop eax
|
|
mov word [esi],ax ; // store integer converted left sample
|
|
lodsw
|
|
%else
|
|
fstp dword [esi] ; // store left sample
|
|
lodsd
|
|
%endif
|
|
fld dword [edi-4]
|
|
fld1 ; // 1 val
|
|
fucomi st1 ; // 1 val
|
|
jbe short go4k_render_clip2
|
|
fchs ; // -1 val
|
|
fucomi st1 ; // -1 val
|
|
fcmovb st0, st1 ; // val -1 (if val > -1)
|
|
go4k_render_clip2:
|
|
fstp st1 ; // newval
|
|
%ifdef GO4K_USE_16BIT_OUTPUT
|
|
push eax
|
|
fmul dword [c_32767]
|
|
fistp dword [esp]
|
|
pop eax
|
|
mov word [esi],ax ; // store integer converted right sample
|
|
lodsw
|
|
%else
|
|
fstp dword [esi] ; // store right sample
|
|
lodsd
|
|
%endif
|
|
%else
|
|
fld dword [edi-8]
|
|
%ifdef GO4K_USE_16BIT_OUTPUT
|
|
push eax
|
|
fmul dword [c_32767]
|
|
fistp dword [esp]
|
|
pop eax
|
|
mov word [esi],ax ; // store integer converted left sample
|
|
lodsw
|
|
%else
|
|
fstp dword [esi] ; // store left sample
|
|
lodsd
|
|
%endif
|
|
fld dword [edi-4]
|
|
%ifdef GO4K_USE_16BIT_OUTPUT
|
|
push eax
|
|
fmul dword [c_32767]
|
|
fistp dword [esp]
|
|
pop eax
|
|
mov word [esi],ax ; // store integer converted right sample
|
|
lodsw
|
|
%else
|
|
fstp dword [esi] ; // store right sample
|
|
lodsd
|
|
%endif
|
|
%endif
|
|
%ifdef GO4K_USE_BUFFER_RECORDINGS
|
|
xchg esi, dword [esp+48]
|
|
%else
|
|
xchg esi, dword [esp+44]
|
|
%endif
|
|
pop ecx
|
|
inc ecx
|
|
%ifdef GO4K_USE_GROOVE_PATTERN
|
|
mov ebx, dword SAMPLES_PER_TICK
|
|
mov eax, dword [esp]
|
|
and eax, 0x0f
|
|
bt dword [go4k_groove_pattern],eax
|
|
jnc go4k_render_nogroove
|
|
sub ebx, dword 3000
|
|
go4k_render_nogroove:
|
|
cmp ecx, ebx
|
|
%else
|
|
cmp ecx, dword SAMPLES_PER_TICK
|
|
%endif
|
|
jl go4k_render_sampleloop
|
|
pop ecx
|
|
inc ecx
|
|
%ifdef AUTHORING
|
|
mov dword[__4klang_current_tick], ecx
|
|
%endif
|
|
cmp ecx, dword MAX_TICKS
|
|
jl go4k_render_tickloop
|
|
%ifdef GO4K_USE_BUFFER_RECORDINGS
|
|
pop ecx
|
|
%endif
|
|
popad
|
|
ret 4
|
|
|
|
%ifdef USE_SECTIONS
|
|
section .g4kcodz code align=1
|
|
%else
|
|
section .text
|
|
%endif
|
|
; //----------------------------------------------------------------------------------------
|
|
; // the magic behind it :)
|
|
; //----------------------------------------------------------------------------------------
|
|
; // IN : edi = instrument pointer
|
|
; // IN : esi = instrumet values
|
|
; // IN : ebx = instrument instructions
|
|
; // OUT :
|
|
; // DIRTY :
|
|
; //----------------------------------------------------------------------------------------
|
|
go4k_VM_process:
|
|
lea WRK, [edi+8] ; // get current workspace pointer
|
|
mov ecx, WRK ; // ecx = workspace start
|
|
go4k_VM_process_loop:
|
|
movzx eax, byte [ebx] ; // get command byte
|
|
inc ebx
|
|
test eax, eax
|
|
je go4k_VM_process_done ; // command byte = 0? so done
|
|
call dword [eax*4+go4k_synth_commands]
|
|
add WRK, MAX_UNIT_SLOTS*4 ; // go to next workspace slot
|
|
jmp short go4k_VM_process_loop
|
|
go4k_VM_process_done:
|
|
add edi, go4k_instrument.size ; // go to next instrument voice
|
|
ret |