sample testailuja

This commit is contained in:
2024-06-04 17:07:01 +03:00
parent 1c6b4cdc7e
commit 878e57b057
16 changed files with 1346 additions and 599 deletions

View File

@ -1,6 +1,6 @@
%define SU_LENGTH_IN_SAMPLES 3335488
%define SU_LENGTH_IN_SAMPLES 1550944
%define SU_SAMPLE_RATE 44100
%define SU_BPM 165.
%define SU_BPM 116.
;-------------------------------------------------------------------------------
; unit struct
@ -61,7 +61,7 @@ endstruc
section .synth_object bss align=256
su_synth_obj:
resb su_synthworkspace.size
resb 34*su_delayline_wrk.size
resb 20*su_delayline_wrk.size
;-------------------------------------------------------------------------------
@ -76,23 +76,26 @@ global _su_render_song@4
_su_render_song@4:
pushad ; Stack: edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
xor eax, eax
push 1 ; Stack: RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
push eax ; Stack: GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
push 16 ; Stack: VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
push 1 ; Stack: RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
push eax ; Stack: GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
su_render_rowloop: ; loop through every row in the song
push eax ; Stack: Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
push eax ; Stack: Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
call su_update_voices ; update instruments for the new row
xor eax, eax ; ecx is the current sample within row
su_render_sampleloop: ; loop through every sample in the row
push eax ; Stack: Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
push 7 ; Stack: VoicesRemain, Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
push eax ; Stack: Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
push 8 ; Stack: PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr ; does the next voice reuse the current opcodes?
push 8 ; Stack: VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
mov edx, dword su_synth_obj ; edx points to the synth object
mov ebx, dword su_patch_opcodes ; COM points to vm code
mov esi, dword su_patch_operands ; VAL points to unit params
mov ecx, dword su_synth_obj + su_synthworkspace.size - su_delayline_wrk.filtstate
lea ebp, [edx + su_synthworkspace.voices] ; WRK points to the first voice
call su_run_vm ; run through the VM code
pop eax ; eax = VoicesRemain, Stack: Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
mov esi, [esp + 52] ; esi points to the output buffer
pop eax ; eax = VoicesRemain, Stack: PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
pop eax ; eax = PolyphonyBitmask, Stack: Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
mov esi, [esp + 56] ; esi points to the output buffer
mov edi, dword su_synth_obj+su_synthworkspace.left
mov ecx, 2
output_sound16bit_loop: ; loop over two channels, left & right
@ -107,19 +110,20 @@ su_render_sampleloop: ; loop through every sample in the row
stosd
add esi,2
loop output_sound16bit_loop
mov [esp + 52], esi ; save esi back to stack ; *ptr++ = left, *ptr++ = right
pop eax ; eax = Sample, Stack: Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
mov [esp + 56], esi ; save esi back to stack ; *ptr++ = left, *ptr++ = right
pop eax ; eax = Sample, Stack: Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
inc dword [esp + 4] ; increment global time, used by delays
inc eax
cmp eax, 4009
cmp eax, 5702
jl su_render_sampleloop
pop eax ; eax = Row, Stack: GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr ; Stack: pushad ptr
pop eax ; eax = Row, Stack: GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr ; Stack: pushad ptr
inc eax
cmp eax, 832
cmp eax, 272
jl su_render_rowloop
; rewind the stack the entropy of multiple pop eax is probably lower than add
pop eax ; eax = GlobalTick, Stack: RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
pop eax ; eax = RandSeed, Stack: edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
pop eax ; eax = GlobalTick, Stack: RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
pop eax ; eax = RandSeed, Stack: VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
pop eax ; eax = VoiceTrackBitmask, Stack: edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
popad ; Popped: eax, ecx, edx, ebx, esp, ebp, esi, edi. Stack: retaddr_su_render_song, OutputBufPtr
ret 4
@ -131,35 +135,58 @@ su_render_sampleloop: ; loop through every sample in the row
;-------------------------------------------------------------------------------
section .su_update_voices code align=1
su_update_voices:
; The simple implementation: each track triggers always the same voice
; The more complicated implementation: one track can trigger multiple voices
xor edx, edx
xor ebx, ebx
mov bl, 16 ; rows per pattern
div ebx ; eax = current pattern, edx = current row in pattern
lea esi, [su_tracks+eax]; esi points to the pattern data for current track
mov edi, dword su_synth_obj+su_synthworkspace.voices
mov bl, 6 ; MAX_TRACKS is always <= 32 so this is ok
mov ebx, 16 ; 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
lea esi, [su_tracks+eax] ; esi points to the pattern data for current track
xor eax, eax ; eax is the first voice of next track
xor ebx, ebx ; ebx is the first voice of current track
mov ebp, dword su_synth_obj ; ebp points to the current_voiceno array
su_update_voices_trackloop:
movzx eax, byte [esi] ; eax = current pattern
imul eax, 16 ; multiply by rows per pattern, eax = offset to current pattern data
movzx eax, byte [su_patterns + eax + edx] ; ecx = note
cmp al, 1 ; anything but hold causes action
imul eax, 16 ; eax = offset to current pattern data
movzx eax,byte [su_patterns + eax + edx] ; eax = note
push edx ; Stack: ptrnrow
xor edx, edx ; edx=0
mov ecx, ebx ; ecx=first voice of the track to be done
su_calculate_voices_loop: ; do {
bt dword [esp + 16 + 4],ecx ; test voicetrack_bitmask// notice that the incs don't set carry
inc edx ; edx++ // edx=numvoices
inc ecx ; ecx++ // ecx=the first voice of next track
jc su_calculate_voices_loop ; } while bit ecx-1 of bitmask is on
push ecx ; Stack: next_instr ptrnrow
cmp al, 1 ; anything but hold causes action
je short su_update_voices_nexttrack
mov dword [edi+su_voice.sustain], eax ; set the voice currently active to release
jb su_update_voices_nexttrack ; if cl < HLD (no new note triggered) goto nexttrack
su_update_voices_retrigger:
mov cl, byte [ebp]
mov edi, ecx
add edi, ebx
shl edi, 12 ; each unit = 64 bytes and there are 1<<MAX_UNITS_SHIFT units + small header
and dword [su_synth_obj + su_synthworkspace.voices + su_voice.sustain + edi], 0 ; set the voice currently active to release; notice that it could increment any number of times
cmp al, 1 ; if cl < HLD (no new note triggered)
jl su_update_voices_nexttrack ; goto nexttrack
inc ecx ; curvoice++
cmp ecx, edx ; if (curvoice >= num_voices)
jl su_update_voices_skipreset
xor ecx,ecx ; curvoice = 0
su_update_voices_skipreset:
mov byte [ebp],cl
add ecx, ebx
shl ecx, 12 ; each unit = 64 bytes and there are 1<<6 units + small header
lea edi,[su_synth_obj + su_synthworkspace.voices + ecx]
stosd ; save note
stosd ; save sustain
mov ecx, (su_voice.size - su_voice.inputs)/4 ; could be xor ecx, ecx; mov ch,...>>8, but will it actually be smaller after compression?
stosd ; save release
mov ecx, (su_voice.size - su_voice.inputs)/4
xor eax, eax
rep stosd ; clear the workspace of the new voice, retriggering oscillators
jmp short su_update_voices_skipadd
su_update_voices_nexttrack:
add edi, su_voice.size
su_update_voices_skipadd:
add esi, 52
dec ebx
jnz short su_update_voices_trackloop
pop ebx ; ebx=first voice of next instrument, Stack: ptrnrow
pop edx ; edx=patrnrow
add esi, 17
inc ebp
cmp ebp,su_synth_obj + 6
jl su_update_voices_trackloop
ret
;-------------------------------------------------------------------------------
@ -178,7 +205,7 @@ su_update_voices_skipadd:
;-------------------------------------------------------------------------------
section .su_run_vm code align=1
su_run_vm:
pushad ; Stack: edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
pushad ; Stack: edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
su_run_vm_loop: ; loop until all voices done
movzx edi, byte [ebx] ; edi = command byte
inc ebx ; move to next instruction
@ -209,12 +236,22 @@ su_transform_operands_out:
call [su_vm_jumptable-4+edi*4] ; call the function corresponding to the instruction
jmp su_run_vm_loop
su_run_vm_advance:
mov ebp, dword [esp + 8] ; load pointer to voice to register
add ebp, su_voice.size ; shift it to point to following voice
mov dword [esp + 8], ebp ; save back to stack
dec dword [esp + 36] ; voices--
jne su_run_vm_loop ; if there's more voices to process, goto vm_loop
popad ; Popped: eax, ecx = DelayWorkSpace, edx = Synth, ebx = OpcodeStream, esp, ebp = Voice, esi = OperandStream, edi. Stack: retaddr_su_run_vm, VoicesRemain, Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
mov ebp, [esp + 8] ; WRK points to start of current voice
add ebp, su_voice.size ; move to next voice
mov [esp + 8], ebp ; update the pointer in the stack to point to the new voice
mov ecx, [esp + 36] ; ecx = how many voices remain to process
dec ecx ; decrement number of voices to process
bt dword [esp + 40], ecx ; if voice bit of su_polyphonism not set
jnc su_op_advance_next_instrument ; goto next_instrument
mov esi, [esp + 4] ; if it was set, then repeat the opcodes for the current voice
mov ebx, [esp + 16]
su_op_advance_next_instrument:
mov [esp + 4], esi ; save current VAL as a checkpoint
mov [esp + 16], ebx ; save current COM as a checkpoint
su_op_advance_finish:
mov [esp + 36], ecx
jne su_run_vm_loop ; ZF was set by dec ecx
popad ; Popped: eax, ecx = DelayWorkSpace, edx = Synth, ebx = OpcodeStream, esp, ebp = Voice, esi = OperandStream, edi. Stack: retaddr_su_run_vm, VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
ret
;-------------------------------------------------------------------------------
; ADDP opcode: add the two top most signals on the stack and pop
@ -224,11 +261,6 @@ su_run_vm_advance:
;-------------------------------------------------------------------------------
section .su_op_addp code align=1
su_op_addp:
jnc su_op_addp_mono
faddp st2, st0
faddp st2, st0
ret
su_op_addp_mono:
faddp st1, st0
ret
@ -248,44 +280,6 @@ su_op_mulp_mono:
fmulp st1
ret
;-------------------------------------------------------------------------------
; XCH opcode: exchange the signals on the stack
;-------------------------------------------------------------------------------
; Mono: a b -> b a
; stereo: a b c d -> c d a b
;-------------------------------------------------------------------------------
section .su_op_xch code align=1
su_op_xch:
fxch st0, st1
ret
;-------------------------------------------------------------------------------
; HOLD opcode: sample and hold the signal, reducing sample rate
;-------------------------------------------------------------------------------
; Mono version: holds the signal at a rate defined by the freq parameter
; Stereo version: holds both channels
;-------------------------------------------------------------------------------
section .su_op_hold code align=1
su_op_hold:
fld dword [edx] ; f x
fmul st0, st0 ; f^2 x
fchs ; -f^2 x
fadd dword [ebp] ; p-f^2 x
fst dword [ebp] ; p <- p-f^2
fldz ; 0 p x
fucomip st1 ; p x
fstp dword [esp-4] ; t=p, x
jc short su_op_hold_holding ; if (0 < p) goto holding
fld1 ; 1 x
fadd dword [esp-4] ; 1+t x
fstp dword [ebp] ; x
fst dword [ebp+4] ; save holded value
ret ; x
su_op_hold_holding:
fstp st0 ;
fld dword [ebp+4] ; x
ret
;-------------------------------------------------------------------------------
; FILTER opcode: perform low/high/band-pass/notch etc. filtering on the signal
@ -316,10 +310,6 @@ su_op_filter:
jz short su_op_filter_skiplowpass
fadd dword [ebp]
su_op_filter_skiplowpass:
test al, byte 0x20
jz short su_op_filter_skipbandpass
fadd dword [ebp+8]
su_op_filter_skipbandpass:
test al, byte 0x10
jz short su_op_filter_skiphighpass
fadd dword [ebp+4]
@ -343,12 +333,14 @@ su_op_filter_skipneghighpass:
;-------------------------------------------------------------------------------
section .su_op_pan code align=1
su_op_pan:
fld dword [edx] ; p s
fmul st1 ; p*s s
fsub st1, st0 ; p*s s-p*s
; Equal to
; s*p s*(1-p)
fxch ; s*(1-p) s*p SHOULD PROBABLY DELETE, WHY BOTHER
jc su_op_pan_do ; this time, if this is mono op...
fld st0 ; ...we duplicate the mono into stereo first
su_op_pan_do:
fld dword [edx] ; p l r
fld1 ; 1 p l r
fsub st1 ; 1-p p l r
fmulp st2 ; p (1-p)*l r
fmulp st2 ; (1-p)*l p*r
ret
;-------------------------------------------------------------------------------
@ -363,10 +355,10 @@ su_op_pan:
section .su_op_delay code align=1
su_op_delay:
lodsw ; al = delay index, ah = delay count
pushad ; Stack: edi, DelayVal, ebp, esp, DelayCom, edx, ecx, eax, retaddr_su_op_delay, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
pushad ; Stack: edi, DelayVal, ebp, esp, DelayCom, edx, ecx, eax, retaddr_su_op_delay, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
movzx ebx, al
lea ebx,[su_delay_times + ebx*2] ; BX now points to the right position within delay time table
movzx esi, word [esp + 84] ; notice that we load word, so we wrap at 65536
movzx esi, word [esp + 88] ; notice that we load word, so we wrap at 65536
mov ecx, dword [esp + 60] ; ebp is now the separate delay workspace, as they require a lot more space
jnc su_op_delay_mono
push eax ; save _ah (delay count)
@ -377,7 +369,7 @@ su_op_delay:
su_op_delay_mono: ; flow into mono delay
call su_op_delay_do ; when stereo delay is not enabled, we could inline this to save 5 bytes, but I expect stereo delay to be farely popular so maybe not worth the hassle
mov dword [esp + 60],ecx ; move delay workspace pointer back to stack.
popad ; Popped: eax, ecx, edx, ebx = DelayCom, esp, ebp, esi = DelayVal, edi. Stack: retaddr_su_op_delay, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
popad ; Popped: eax, ecx, edx, ebx = DelayCom, esp, ebp, esi = DelayVal, edi. Stack: retaddr_su_op_delay, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
ret
;-------------------------------------------------------------------------------
@ -445,10 +437,6 @@ section .su_op_compressor code align=1
su_op_compressor:
fld st0 ; x x
fmul st0, st0 ; x^2 x
fld st2 ; r x^2 l r
fst st3 ; y x^2 l r
fmul st0, st0 ; y^2 x^2 l r
faddp st1, st0 ; y^2+x^2 l r
fld dword [ebp] ; l x^2 x
fucomi st0, st1
setnb al ; if (st0 >= st1) al = 1; else al = 0;
@ -477,7 +465,6 @@ su_op_compressor:
; if ratio is at minimum => p=0 => 1 x
; if ratio is at maximum => p=0.5 => t/x => t/x*x=t
fdiv dword [edx + 8]; this used to be pregain but that ran into problems with getting back up to 0 dB so postgain should be better at that
fld st0 ; and return the computed gain two times, ready for MULP STEREO
ret
@ -528,12 +515,6 @@ section .su_op_send code align=1
su_op_send:
lodsw
mov ecx, [esp + 12] ; load pointer to voice
pushf ; uh ugly: we save the flags just for the stereo carry bit. Doing the .CX loading later crashed the synth for stereo sends as loading the synth address from stack was f'd up by the "call su_op_send_mono"
test ah, 0x80
jz su_op_send_skipglobal
mov ecx, [esp + 24 + 4]
su_op_send_skipglobal:
popf
test al, 0x8 ; if the SEND_POP bit is not set
jnz su_op_send_skippush
fld st0 ; duplicate the signal on stack: s s
@ -615,7 +596,7 @@ su_op_envelope_leave2:
;-------------------------------------------------------------------------------
section .su_op_noise code align=1
su_op_noise:
lea ecx,[esp + 56]
lea ecx,[esp + 60]
imul eax, [ecx],16007
mov [ecx],eax
fild dword [ecx]
@ -646,7 +627,7 @@ su_op_oscillator:
fchs ; -d r, negate the detune for second round
su_op_oscillat_mono:
pushad ; Stack: edi, esi, OscWRK, esp, ebx, edx, ecx, , retaddr_su_op_oscillator, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
pushad ; Stack: edi, esi, OscWRK, esp, ebx, edx, ecx, , retaddr_su_op_oscillator, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
fldz ; 0 d
fxch ; d a=0, "accumulated signal"
su_op_oscillat_unison_loop:
@ -668,39 +649,31 @@ su_op_oscillat_unison_loop:
jmp short su_op_oscillat_unison_loop
su_op_oscillat_unison_out:
popad ; Popped: eax = , ecx, edx, ebx, esp, ebp = OscWRK, esi, edi. Stack: retaddr_su_op_oscillator, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, Sample, Row, GlobalTick, RandSeed, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
popad ; Popped: eax = , ecx, edx, ebx, esp, ebp = OscWRK, esi, edi. Stack: retaddr_su_op_oscillator, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
ret
su_op_oscillat_single:
fld dword [edx]
fsub dword [FCONST_0_500000]
fdiv dword [FCONST_0_00781250]
faddp st1
test al, byte 0x08
jnz su_op_oscillat_skipnote
fiadd dword [edx-su_voice.inputs+su_voice.note] ; // st0 is note, st1 is t+d offset
su_op_oscillat_skipnote:
fmul dword [ICONST_1034594986]
call su_power
test al, byte 0x08
jz short su_op_oscillat_normalize_note
fmul dword [FCONST_3_80000em05] ; // st0 is now frequency for lfo
jmp short su_op_oscillat_normalized
su_op_oscillat_normalize_note:
fmul dword [FCONST_9_269614em05] ; // st0 is now frequency
su_op_oscillat_normalized:
fadd dword [ebp]
test al, byte 0x80
jz short su_op_oscillat_not_sample
fst dword [ebp] ; for samples, we store the phase without mod(p,1)
call su_oscillat_sample
jmp su_op_oscillat_shaping ; skip the rest to avoid color phase normalization and colorloading
su_op_oscillat_not_sample:
fld1 ; we need to take mod(p,1) so the frequency does not drift as the float
fadd st1, st0 ; make no mistake: without this, there is audible drifts in oscillator pitch
fxch ; as the actual period changes once the phase becomes too big
fprem ; we actually computed mod(p+1,1) instead of mod(p,1) as the fprem takes mod
fstp st1 ; towards zero
fst dword [ebp] ; store back the updated phase
fadd dword [edx + 8]
fld1 ; this is a bit stupid, but we need to take mod(x,1) again after phase modulations
fadd st1, st0 ; as the actual oscillator functions expect x in [0,1]
fxch
fprem
fstp st1
fld dword [edx + 12] ; // c p
; every oscillator test included if needed
test al, byte 0x40
@ -711,6 +684,10 @@ su_op_oscillat_notsine:
jz short su_op_oscillat_not_trisaw
call su_oscillat_trisaw
su_op_oscillat_not_trisaw:
test al, byte 0x10
jz short su_op_oscillat_not_pulse
call su_oscillat_pulse
su_op_oscillat_not_pulse:
su_op_oscillat_shaping:
; finally, shape the oscillator and apply gain
fld dword [edx + 16]
@ -719,6 +696,17 @@ su_op_oscillat_gain:
fmul dword [edx + 20]
ret
section .su_oscillat_pulse code align=1
su_oscillat_pulse:
fucomi st1 ; // c p
fld1
jnc short su_oscillat_pulse_up ; // +1 c p
fchs ; // -1 c p
su_oscillat_pulse_up:
fstp st1 ; // +-1 p
fstp st1 ; // +-1
ret
section .su_oscillat_trisaw code align=1
su_oscillat_trisaw:
fucomi st1 ; // c p
@ -748,6 +736,30 @@ su_oscillat_sine_do:
fsin ; // sin(2*pi*p)
ret
section .su_oscillat_sample code align=1
su_oscillat_sample:
pushad ; Stack: SampleDi, esi, ebp, esp, SampleBx, SampleDx, SampleCx, SampleAx, retaddr_su_oscillat_sample, retaddr_su_op_oscillator, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr ; edx must be saved, eax & ecx if this is stereo osc
push eax
mov al, byte [esi-4] ; reuse "color" as the sample number
lea edi, [su_sample_offsets + eax*8]; edi points now to the sample table entry
fmul dword [FCONST_84_28075] ; p*r
fistp dword [esp]
pop edx ; edx is now the sample number
movzx ebx, word [edi + 4] ; ecx = loopstart
sub edx, ebx ; if sample number < loop start
jl su_oscillat_sample_not_looping ; then we're not looping yet
mov eax, edx ; eax = sample number
movzx ecx, word [edi + 6] ; edi is now the loop length
xor edx, edx ; div wants edx to be empty
div ecx ; edx is now the remainder
su_oscillat_sample_not_looping:
add edx, ebx ; sampleno += loopstart
add edx, dword [edi]
fild word [su_sample_table + edx*2]
fdiv dword [FCONST_32767_0]
popad ; Popped: eax = SampleAx, ecx = SampleCx, edx = SampleDx, ebx = SampleBx, esp, ebp, esi, edi = SampleDi. Stack: retaddr_su_oscillat_sample, retaddr_su_op_oscillator, edi, OperandStream, Voice, esp, OpcodeStream, Synth, DelayWorkSpace, eax, retaddr_su_run_vm, VoicesRemain, PolyphonyBitmask, Sample, Row, GlobalTick, RandSeed, VoiceTrackBitmask, edi, esi, ebp, esp, ebx, edx, ecx, eax, retaddr_su_render_song, OutputBufPtr
ret
;-------------------------------------------------------------------------------
; IN opcode: inputs and clears a global port
;-------------------------------------------------------------------------------
@ -766,6 +778,37 @@ su_op_in:
ret
section .su_load_gmdls code align=1
global _su_load_gmdls@0
_su_load_gmdls@0:
mov eax, su_sample_table
; these are the arguments for ReadFile
push 0 ; NULL
push eax ; &bytes_read, reusing sample table again; it does not matter that the first four bytes are trashed
push 3440660 ; number of bytes to read
push eax ; here we actually pass the sample table to readfile
; these are for OpenFile
push 0 ; OF_READ
push eax ; &ofstruct, blatantly reuse the sample table
push su_gmdls_path1 ; path
call dword [__imp__OpenFile@12]; eax = OpenFile(path,&ofstruct,OF_READ)
push eax ; handle to file
call dword [__imp__ReadFile@20] ; Readfile(handle,&su_sample_table,SAMPLE_TABLE_SIZE,&bytes_read,NULL)
ret
extern __imp__OpenFile@12 ; requires windows
extern __imp__ReadFile@20
; requires windows
section .su_gmdls_path1 data align=1
su_gmdls_path1:
db 'drivers/gm.dls',0
section .susamtable bss align=256
su_sample_table:
resb 3440660 ; size of gmdls.
;-------------------------------------------------------------------------------
; su_nonlinear_map function: returns 2^(-24*x) of parameter number _AX
@ -813,7 +856,7 @@ su_power:
; best way to do this
;-------------------------------------------------------------------------------
section .su_op_distort code align=1
su_op_distort:call su_effects_stereohelper
su_op_distort:
fld dword [edx]
su_waveshaper:
@ -869,17 +912,15 @@ section .su_vm_jumptable data align=1
su_vm_jumptable:
dd su_op_envelope
dd su_op_oscillator
dd su_op_distort
dd su_op_hold
dd su_op_mulp
dd su_op_noise
dd su_op_filter
dd su_op_addp
dd su_op_pan
dd su_op_delay
dd su_op_xch
dd su_op_outaux
dd su_op_send
dd su_op_distort
dd su_op_delay
dd su_op_compressor
dd su_op_in
dd su_op_out
@ -891,17 +932,15 @@ section .su_vm_transformcounts data align=1
su_vm_transformcounts:
db 5
db 6
db 1
db 1
db 0
db 2
db 2
db 0
db 1
db 2
db 1
db 1
db 4
db 0
db 2
db 1
db 5
db 0
db 1
@ -913,55 +952,53 @@ su_vm_transformcounts:
section .su_patterns data align=1
su_patterns:
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,57,1,1,1,57,1,1,1
db 1,1,1,1,57,1,1,1,1,1,1,1,57,1,1,1
db 1,1,1,1,57,1,1,1,1,1,1,57,57,1,1,1
db 1,1,1,1,57,57,57,57,1,1,1,1,57,1,1,1
db 1,1,1,1,57,1,1,1,57,57,1,1,57,1,1,1
db 48,1,1,1,48,1,1,1,48,1,1,1,48,1,1,1
db 48,1,1,1,48,1,1,1,48,1,1,1,48,1,48,1
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
db 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,46,1,1,1,46,1
db 46,1,1,1,1,1,1,1,1,1,46,1,1,1,1,1
db 46,1,1,1,1,1,1,1,46,1,46,1,1,1,1,1
db 46,1,1,1,1,1,1,1,46,46,46,46,1,1,1,1
db 46,1,1,1,1,1,1,1,1,1,46,46,1,1,1,1
db 48,1,48,1,1,1,48,1,48,1,48,1,1,1,48,1
db 50,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
db 48,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
db 46,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
db 1,1,1,1,1,1,1,1,1,1,48,1,50,1,53,1
db 43,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
db 1,1,1,1,1,1,1,1,43,1,45,1,46,1,48,1
db 1,1,1,1,1,1,1,1,1,1,1,1,48,1,50,1
db 52,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
db 45,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
db 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0
db 62,0,64,0,65,0,69,0,65,0,64,0,62,0,64,0
db 65,0,72,0,65,0,64,0,62,0,64,0,65,0,71,0
db 65,0,69,0,65,0,64,0,62,0,64,0,65,0,72,0
db 50,0,50,1,50,0,50,1,50,0,50,1,50,0,50,1
db 48,0,48,1,48,0,48,1,48,0,48,1,48,0,48,1
db 46,0,46,1,46,0,46,1,46,0,46,1,46,0,46,1
db 43,0,43,1,43,0,43,1,43,0,43,1,43,0,43,1
db 43,0,43,1,43,0,43,1,43,0,43,1,43,0,43,0
db 1,1,1,1,58,1,1,1,1,1,1,1,58,1,1,1
db 1,1,1,1,72,1,1,1,1,1,1,1,72,1,1,1
db 74,1,0,0,74,1,77,70,1,0,70,1,0,70,1,0
db 74,1,0,0,74,1,77,70,1,0,70,1,0,0,72,1
db 74,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 60,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
db 1,1,53,1,1,1,53,1,1,1,53,1,1,1,53,1
db 1,1,53,1,1,1,53,1,1,1,53,1,1,1,53,53
;-------------------------------------------------------------------------------
; Tracks
;-------------------------------------------------------------------------------
section .su_tracks data align=1
su_tracks:
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,2,3,2,2,2,4,2,2,2,2,2,2,2,5,2,2,2,3,2,2,2,4,2,2,2,2,2,2,2,5,6,6,7,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,9,9,9,10,9,9,9,11,9,9,9,10,9,9,9,12,9,9,9,10,9,9,9,11,9,9,9,10,9,9,9,12,6,6,7,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,6,6,7,0
db 14,6,15,6,16,17,18,19,16,20,21,22,14,6,6,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,24,25,24,26,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,27,28,28,29,29,30,30,27,27,28,28,29,29,30,30,27,27,28,28,29,29,30,30,27,27,28,28,29,29,30,31,0,0,0,0
db 0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,3
db 0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,3
db 0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,3
db 6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,8
db 0,0,0,0,9,3,3,3,9,3,3,3,3,3,3,3,3
db 0,0,0,0,10,11,10,10,10,10,10,10,10,10,10,10,3
;-------------------------------------------------------------------------------
; Sample offsets
;-------------------------------------------------------------------------------
section .su_sample_offsets data align=1
su_sample_offsets:
dd 560606
dw 4276
dw 1
dd 641780
dw 2423
dw 1
dd 433554
dw 2615
dw 5676
dd 367477
dw 1343
dw 1
;-------------------------------------------------------------------------------
; Delay times
;-------------------------------------------------------------------------------
section .su_delay_times data align=1
su_delay_times:
dw 1116,1188,1276,1356,1422,1492,1556,1618,1140,1212,1300,1380,1446,1516,1580,1642,21381,12027
dw 1395,350,1744,1744,1116,1188,1276,1356,1422,1492,1556,1618,1140,1212,1300,1380,1446,1516,1580,1642
;-------------------------------------------------------------------------------
@ -969,14 +1006,14 @@ su_delay_times:
;-------------------------------------------------------------------------------
section .su_patch_opcodes data align=1
su_patch_opcodes:
db 2,4,6,8,10,2,12,10,14,14,16,14,14,14,14,14,6,8,18,20,22,20,22,25,2,26,2,26,2,26,0,2,26,4,6,8,10,2,12,14,14,10,16,14,14,14,14,18,25,2,2,10,26,0,2,12,10,14,14,14,18,25,0,5,5,17,5,17,15,14,22,14,7,15,3,11,25,4,26,4,26,26,4,26,4,26,4,26,0,2,4,4,16,10,18,20,22,20,25,0,2,26,26,2,4,4,16,10,14,14,18,7,29,11,25,0,31,21,33,0
db 2,4,6,2,8,10,10,6,12,10,10,10,10,14,17,2,2,6,18,0,2,4,20,6,2,8,6,10,10,12,14,17,2,18,2,18,0,2,22,8,6,2,22,8,6,12,2,4,6,12,10,20,14,17,0,2,4,4,12,6,10,10,20,2,8,6,10,12,24,6,20,14,17,2,18,0,3,3,7,5,7,15,17,0,3,5,7,11,11,15,17,0,27,23,29,0
;-------------------------------------------------------------------------------
; The parameters / inputs to each opcode
;-------------------------------------------------------------------------------
section .su_patch_operands data align=1
su_patch_operands:
db 22,64,0,0,38,77,64,19,128,66,70,64,78,128,0,68,0,0,70,2,128,97,128,68,108,128,68,100,128,68,19,98,16,15,128,80,40,74,80,23,42,16,97,128,59,27,128,112,0,0,15,27,128,112,0,8,15,128,0,38,49,0,0,128,70,40,0,47,54,0,0,128,19,152,0,54,68,70,0,128,26,200,0,39,71,0,0,128,7,0,149,88,64,42,115,114,54,33,58,100,28,45,0,0,128,84,102,93,63,68,75,87,64,11,66,68,53,128,80,7,76,16,13,54,16,64,128,0,71,128,74,0,128,49,71,121,0,128,0,56,0,4,53,0,0,128,102,128,87,128,16,95,128,80,89,71,32,61,45,0,64,87,64,128,65,128,34,64,60,87,128,64,128,35,64,69,0,128,106,128,66,62,91,64,103,26,88,85,31,88,96,12,128,88,25,59,106,60,64,29,21,64,64,4,128,64,128,40,52,25,0,41,42,55,54,63,128,72,75,33,0,59,43,0,74,64,0,128,64,128,72,69,73,0,40,64,0,128,64,128,72,71,120,0,40,64,0,128,64,128,72,86,152,0,39,62,0,30,71,88,62,14,53,27,72,64,88,66,64,113,64,128,64,64,71,128,86,0,16,1,73,128,90,0,17,1,84,52,39,81,0,0,128,87,144,0,90,107,0,33,57,67,57,128,76,64,0,98,64,101,64,64,48,85,78,97,64,35,39,82,64,15,128,68,64,80,48,56,87,46,54,85,35,2,50,128,114,77,0,15,128
db 18,65,0,0,60,94,57,0,128,63,79,66,0,43,0,0,128,67,81,87,35,68,100,62,64,9,75,68,53,128,80,10,85,16,10,49,16,64,57,0,62,128,0,0,128,39,61,34,0,128,0,40,0,0,76,0,0,96,86,116,0,0,114,37,130,95,0,68,0,0,83,3,107,57,67,68,128,78,64,71,84,10,47,54,0,0,128,19,136,0,54,68,70,0,128,26,255,255,0,53,0,0,128,64,128,0,0,0,3,97,0,0,54,0,0,128,64,6,0,0,2,3,79,128,0,62,0,0,42,64,64,0,1,64,125,128,39,76,68,114,70,50,12,46,74,36,39,77,40,48,0,84,50,128,35,71,64,0,64,64,64,16,3,128,64,94,128,64,83,32,53,0,0,64,52,59,91,102,72,37,65,87,47,102,59,64,98,23,0,72,47,45,76,128,104,0,8,90,0,0,128,21,78,0,85,64,77,64,0,2,64,111,128,73,49,78,50,60,0,0,128,82,64,0,3,64,127,128,78,128,76,109,128,64,57,84,0,2,40,128,120,42,4,15,128
;-------------------------------------------------------------------------------
; Constants
@ -986,8 +1023,8 @@ FCONST_32767_0 dd 0x46fffe00
FCONST_0_00781250 dd 0x3c000000
FCONST_0_500000 dd 0x3f000000
FCONST_0_99609375 dd 0x3f7f0000
FCONST_3_80000em05 dd 0x381f6230
FCONST_9_269614em05 dd 0x38c265dc
FCONST_84_28075 dd 0x42a88fbe
ICONST_2147483648 dd 0x80000000
ICONST_1034594986 dd 0x3daaaaaa
ICONST_24 dd 0x18