mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-04 01:28:45 -04:00
293 lines
9.6 KiB
NASM
293 lines
9.6 KiB
NASM
%if BITS == 64
|
|
%define WRK rbp ; alias for unit workspace
|
|
%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 do 2
|
|
mov r9, qword %2
|
|
%1 r9
|
|
%endmacro
|
|
|
|
%macro do 3
|
|
mov r9, qword %2
|
|
%1 r9 %3
|
|
%endmacro
|
|
|
|
%macro do 4
|
|
mov r9, qword %2
|
|
%1 r9+%3 %4
|
|
%endmacro
|
|
|
|
%macro do 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
|
|
|
|
%define PUSH_REG_SIZE(n) (n*8)
|
|
%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 do 2
|
|
%1 %2
|
|
%endmacro
|
|
|
|
%macro do 3
|
|
%1 %2 %3
|
|
%endmacro
|
|
|
|
%macro do 4
|
|
%1 %2+%3 %4
|
|
%endmacro
|
|
|
|
%macro do 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
|
|
|
|
%define PUSH_REG_SIZE(n) 32
|
|
%endif
|
|
|
|
struc su_stack ; the structure of stack _as the units see it_
|
|
.retaddr RESPTR 1
|
|
.voiceno RESPTR 1
|
|
.val RESPTR 1
|
|
.wrk RESPTR 1
|
|
%if BITS == 32 ; we dump everything with pushad, so this is unused in 32-bit
|
|
RESPTR 1
|
|
%endif
|
|
.com RESPTR 1
|
|
.synth RESPTR 1
|
|
.delaywrk RESPTR 1
|
|
%if BITS == 32 ; we dump everything with pushad, so this is unused in 32-bit
|
|
RESPTR 1
|
|
%endif
|
|
.retaddrvm RESPTR 1
|
|
%ifdef INCLUDE_POLYPHONY
|
|
.polyphony RESPTR 1
|
|
%endif
|
|
.output_sound
|
|
.rowtick RESPTR 1 ; which tick within this row are we at
|
|
.update_voices
|
|
.row RESPTR 1 ; which total row of the song are we at
|
|
.tick RESPTR 1 ; which total tick of the song are we at
|
|
.randseed RESPTR 1
|
|
%ifdef INCLUDE_MULTIVOICE_TRACKS
|
|
.voicetrack RESPTR 1
|
|
%endif
|
|
.render_epilogue
|
|
%if BITS == 32
|
|
RESPTR 8 ; registers
|
|
.retaddr_pl RESPTR 1
|
|
%elifidn __OUTPUT_FORMAT__,win64
|
|
RESPTR 4 ; registers
|
|
%else
|
|
RESPTR 2 ; registers
|
|
%endif
|
|
.bufferptr RESPTR 1
|
|
.size
|
|
endstruc
|
|
|
|
;===============================================================================
|
|
; The opcode table jump table. This is constructed to only include the opcodes
|
|
; that are used so that the jump table is as small as possible.
|
|
;===============================================================================
|
|
SECT_DATA(suoptabl)
|
|
|
|
su_synth_commands DPTR OPCODES
|
|
|
|
;===============================================================================
|
|
; The number of transformed parameters each opcode takes
|
|
;===============================================================================
|
|
SECT_DATA(suparcnt)
|
|
|
|
su_opcode_numparams db NUMPARAMS
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; Constants used by the common functions
|
|
;-------------------------------------------------------------------------------
|
|
SECT_DATA(suconst)
|
|
|
|
c_i128 dd 0.0078125
|
|
c_RandDiv dd 65536*32768
|
|
c_0_5 dd 0.5
|
|
c_24 dd 24
|
|
c_i12 dd 0x3DAAAAAA
|
|
EXPORT MANGLE_DATA(LFO_NORMALIZE)
|
|
dd DEF_LFO_NORMALIZE
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; su_run_vm function: runs the entire virtual machine once, creating 1 sample
|
|
;-------------------------------------------------------------------------------
|
|
; Input: su_synth_obj.left : Set to 0 before calling
|
|
; su_synth_obj.right : Set to 0 before calling
|
|
; _CX : Pointer to delay workspace (if needed)
|
|
; _DX : Pointer to synth object
|
|
; COM : Pointer to command stream
|
|
; VAL : Pointer to value stream
|
|
; WRK : Pointer to the last workspace processed
|
|
; _DI : Voice number (0 = starting from first voice)
|
|
; Output: su_synth_obj.left : left sample
|
|
; su_synth_obj.right : right sample
|
|
; Dirty: everything
|
|
;-------------------------------------------------------------------------------
|
|
SECT_TEXT(surunvm)
|
|
|
|
EXPORT MANGLE_FUNC(su_run_vm,0)
|
|
push_registers _CX, _DX, COM, WRK, VAL, _DI ; save everything to stack
|
|
su_run_vm_loop: ; loop until all voices done
|
|
movzx eax, byte [COM] ; eax = command byte
|
|
inc COM ; move to next instruction
|
|
add WRK, su_unit.size ; move WRK to next unit
|
|
push _AX
|
|
shr eax,1
|
|
do {mov al, byte [},su_opcode_numparams,_AX,]
|
|
push _AX
|
|
call su_transform_values
|
|
pop _AX
|
|
shr eax,1
|
|
do call [,su_synth_commands,_AX*PTRSIZE,] ; call the function corresponding to the instruction
|
|
cmp dword [_SP+su_stack.voiceno-PTRSIZE],MAX_VOICES ; if (voice < MAX_VOICES)
|
|
jl su_run_vm_loop ; goto vm_loop
|
|
pop_registers _CX, _DX, COM, WRK, VAL, _DI ; pop everything from stack
|
|
ret
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; su_transform_values function: transforms values and adds modulations
|
|
;-------------------------------------------------------------------------------
|
|
; Input: [esp] : number of bytes to transform
|
|
; VAL : pointer to byte stream
|
|
; Output: eax : last transformed byte (zero extended)
|
|
; edx : pointer to su_transformed_values, containing
|
|
; each byte transformed as x/128.0f+modulations
|
|
; VAL : updated to point after the transformed bytes
|
|
;-------------------------------------------------------------------------------
|
|
SECT_TEXT(sutransf)
|
|
|
|
su_transform_values:
|
|
xor ecx, ecx
|
|
xor eax, eax
|
|
mov INP, [_SP+su_stack.wrk+2*PTRSIZE]
|
|
add INP, su_voice.inputs
|
|
su_transform_values_loop:
|
|
cmp ecx, dword [_SP+PTRSIZE]
|
|
jnb su_transform_values_out
|
|
lodsb
|
|
push _AX
|
|
fild dword [_SP]
|
|
do fmul dword [,c_i128,]
|
|
fadd dword [WRK+su_unit.ports+_CX*4]
|
|
fstp dword [INP+_CX*4]
|
|
mov dword [WRK+su_unit.ports+_CX*4], 0
|
|
pop _AX
|
|
inc ecx
|
|
jmp su_transform_values_loop
|
|
su_transform_values_out:
|
|
ret PTRSIZE
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; su_env_map function: computes 2^(-24*x) of the envelope parameter
|
|
;-------------------------------------------------------------------------------
|
|
; Input: eax : envelope parameter (0 = attac, 1 = decay...)
|
|
; edx : pointer to su_transformed_values
|
|
; Output: st0 : 2^(-24*x), where x is the parameter in the range 0-1
|
|
;-------------------------------------------------------------------------------
|
|
SECT_TEXT(supower)
|
|
|
|
%if ENVELOPE_ID > -1 ; TODO: compressor also uses this, so should be compiled if either
|
|
su_env_map:
|
|
fld dword [INP+_AX*4] ; x, where x is the parameter in the range 0-1
|
|
do fimul dword [,c_24,] ; 24*x
|
|
fchs ; -24*x
|
|
; flow into Power function, which outputs 2^(-24*x)
|
|
%endif
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; su_power function: computes 2^x
|
|
;-------------------------------------------------------------------------------
|
|
; Input: st0 : x
|
|
; Output: st0 : 2^x
|
|
;-------------------------------------------------------------------------------
|
|
EXPORT MANGLE_FUNC(su_power,0)
|
|
fld1 ; 1 x
|
|
fld st1 ; x 1 x
|
|
fprem ; mod(x,1) 1 x
|
|
f2xm1 ; 2^mod(x,1)-1 1 x
|
|
faddp st1,st0 ; 2^mod(x,1) x
|
|
fscale ; 2^mod(x,1)*2^trunc(x) x
|
|
; Equal to:
|
|
; 2^x x
|
|
fstp st1 ; 2^x
|
|
ret
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; Include the rest of the code
|
|
;-------------------------------------------------------------------------------
|
|
%include "opcodes/arithmetic.asm"
|
|
%include "opcodes/flowcontrol.asm"
|
|
%include "opcodes/sources.asm"
|
|
%include "opcodes/sinks.asm"
|
|
; warning: at the moment effects has to be assembled after
|
|
; sources, as sources.asm defines SU_USE_WAVESHAPER
|
|
; if needed.
|
|
%include "opcodes/effects.asm"
|
|
%include "introspection.asm"
|
|
%include "player.asm"
|
|
|
|
%ifidn __OUTPUT_FORMAT__,win64
|
|
%include "win64/gmdls_win64.asm"
|
|
%endif
|
|
|
|
%ifidn __OUTPUT_FORMAT__,win32
|
|
%include "win32/gmdls_win32.asm"
|
|
%endif
|