refactor(vm): rename Commands/Values to Opcodes/Operands

The commands and values were not very good names to what the
byte sequences actually are: opcodes and their operands. In
many other places, we were already calling the byte in the Command
stream as Opcode, so a logical name for a sequence of these is
Opcodes. Values is such a generic name that it's not immediately
clear that this sequence is related to the opcodes. Operands is not
perfect but clearly suggests that this sequence is related to
the Opcodes.
This commit is contained in:
5684185+vsariola@users.noreply.github.com
2023-10-18 19:51:56 +03:00
parent 87604dd92e
commit 01bf409929
14 changed files with 158 additions and 156 deletions

View File

@ -32,17 +32,17 @@ func Synth(patch sointu.Patch, bpm int) (*NativeSynth, error) {
if err != nil {
return nil, fmt.Errorf("error compiling patch: %v", err)
}
if len(comPatch.Commands) > 2048 { // TODO: 2048 could probably be pulled automatically from cgo
return nil, errors.New("bridge supports at most 2048 commands; the compiled patch has more")
if len(comPatch.Opcodes) > 2048 { // TODO: 2048 could probably be pulled automatically from cgo
return nil, errors.New("bridge supports at most 2048 opcodes; the compiled patch has more")
}
if len(comPatch.Values) > 16384 { // TODO: 16384 could probably be pulled automatically from cgo
return nil, errors.New("bridge supports at most 16384 values; the compiled patch has more")
if len(comPatch.Operands) > 16384 { // TODO: 16384 could probably be pulled automatically from cgo
return nil, errors.New("bridge supports at most 16384 operands; the compiled patch has more")
}
for i, v := range comPatch.Commands {
s.Commands[i] = (C.uchar)(v)
for i, v := range comPatch.Opcodes {
s.Opcodes[i] = (C.uchar)(v)
}
for i, v := range comPatch.Values {
s.Values[i] = (C.uchar)(v)
for i, v := range comPatch.Operands {
s.Operands[i] = (C.uchar)(v)
}
for i, v := range comPatch.DelayTimes {
s.DelayTimes[i] = (C.ushort)(v)
@ -124,21 +124,21 @@ func (bridgesynth *NativeSynth) Update(patch sointu.Patch, bpm int) error {
if err != nil {
return fmt.Errorf("error compiling patch: %v", err)
}
if len(comPatch.Commands) > 2048 { // TODO: 2048 could probably be pulled automatically from cgo
return errors.New("bridge supports at most 2048 commands; the compiled patch has more")
if len(comPatch.Opcodes) > 2048 { // TODO: 2048 could probably be pulled automatically from cgo
return errors.New("bridge supports at most 2048 opcodes; the compiled patch has more")
}
if len(comPatch.Values) > 16384 { // TODO: 16384 could probably be pulled automatically from cgo
return errors.New("bridge supports at most 16384 values; the compiled patch has more")
if len(comPatch.Operands) > 16384 { // TODO: 16384 could probably be pulled automatically from cgo
return errors.New("bridge supports at most 16384 operands; the compiled patch has more")
}
needsRefresh := false
for i, v := range comPatch.Commands {
if cmdChar := (C.uchar)(v); s.Commands[i] != cmdChar {
s.Commands[i] = cmdChar
needsRefresh = true // if any of the commands change, we retrigger all units
for i, v := range comPatch.Opcodes {
if cmdChar := (C.uchar)(v); s.Opcodes[i] != cmdChar {
s.Opcodes[i] = cmdChar
needsRefresh = true // if any of the opcodes change, we retrigger all units
}
}
for i, v := range comPatch.Values {
s.Values[i] = (C.uchar)(v)
for i, v := range comPatch.Operands {
s.Operands[i] = (C.uchar)(v)
}
for i, v := range comPatch.DelayTimes {
s.DelayTimes[i] = (C.ushort)(v)
@ -152,7 +152,7 @@ func (bridgesynth *NativeSynth) Update(patch sointu.Patch, bpm int) error {
s.Polyphony = C.uint(comPatch.PolyphonyBitmask)
if needsRefresh {
for i := range s.SynthWrk.Voices {
// if any of the commands change, we retrigger all units
// if any of the opcodes change, we retrigger all units
// note that we don't change the notes or release states, just the units
for j := range s.SynthWrk.Voices[i].Units {
s.SynthWrk.Voices[i].Units[j] = C.Unit{}

View File

@ -7,8 +7,8 @@ struc su_synth
.sampleoffs resb su_sample_offset.size * 256
.randseed resd 1
.globaltime resd 1
.commands resb 32 * 64
.values resb 32 * 64 * 8
.opcodes resb 32 * 64
.operands resb 32 * 64 * 8
.polyphony resd 1
.numvoices resd 1
endstruc
@ -73,8 +73,8 @@ su_render_samples_loop:
mov eax, [{{.CX}} + su_synth.numvoices]
{{.Push .AX "VoicesRemain"}}
lea {{.DX}}, [{{.CX}}+ su_synth.synth_wrk]
lea {{.COM}}, [{{.CX}}+ su_synth.commands]
lea {{.VAL}}, [{{.CX}}+ su_synth.values]
lea {{.COM}}, [{{.CX}}+ su_synth.opcodes]
lea {{.VAL}}, [{{.CX}}+ su_synth.operands]
lea {{.WRK}}, [{{.DX}} + su_synthworkspace.voices]
lea {{.CX}}, [{{.CX}}+ su_synth.delay_wrks - su_delayline_wrk.filtstate]
{{.Call "su_run_vm"}}

View File

@ -43,8 +43,8 @@ typedef struct Synth {
struct SampleOffset SampleOffsets[256];
unsigned int RandSeed;
unsigned int GlobalTick;
unsigned char Commands[32 * 64];
unsigned char Values[32 * 64 * 8];
unsigned char Opcodes[32 * 64];
unsigned char Operands[32 * 64 * 8];
unsigned int Polyphony;
unsigned int NumVoices;
} Synth;

View File

@ -5,15 +5,15 @@
; 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
; COM : Pointer to opcode stream
; VAL : Pointer to operand stream
; WRK : Pointer to the last workspace processed
; Output: su_synth_obj.left : left sample
; su_synth_obj.right : right sample
; Dirty: everything
;-------------------------------------------------------------------------------
{{.Func "su_run_vm"}}
{{- .PushRegs .CX "DelayWorkSpace" .DX "Synth" .COM "CommandStream" .WRK "Voice" .VAL "ValueStream" | indent 4}}
{{- .PushRegs .CX "DelayWorkSpace" .DX "Synth" .COM "OpcodeStream" .WRK "Voice" .VAL "OperandStream" | indent 4}}
{{- if .RowSync}}
fild dword [{{.Stack "Sample"}}]
{{.Int .Song.SamplesPerRow | .Prepare | indent 8}}
@ -33,13 +33,13 @@ su_run_vm_loop: ; loop until all voices done
add {{.INP}}, su_voice.inputs
xor ecx, ecx ; counter = 0
xor eax, eax ; clear out high bits of eax, as lodsb only sets al
su_transform_values_loop:
su_transform_operands_loop:
{{- .Prepare "su_vm_transformcounts-1" | indent 4}}
cmp cl, byte [{{.Use "su_vm_transformcounts-1"}}+{{.DI}}] ; compare the counter to the value in the param count table
je su_transform_values_out
lodsb ; load the byte value from VAL stream
je su_transform_operands_out
lodsb ; load the operand from VAL stream
push {{.AX}} ; push it to memory so FPU can read it
fild dword [{{.SP}}] ; load the value to FPU stack
fild dword [{{.SP}}] ; load the operand value to FPU stack
{{- .Prepare (.Float 0.0078125) | indent 4}}
fmul dword [{{.Use (.Float 0.0078125)}}] ; divide it by 128 (0 => 0, 128 => 1.0)
fadd dword [{{.WRK}}+su_unit.ports+{{.CX}}*4] ; add the modulations in the current workspace
@ -48,8 +48,8 @@ su_transform_values_loop:
mov dword [{{.WRK}}+su_unit.ports+{{.CX}}*4], eax ; clear out the modulation ports
pop {{.AX}}
inc ecx
jmp su_transform_values_loop
su_transform_values_out:
jmp su_transform_operands_loop
su_transform_operands_out:
popf ; pop flags for the carry bit = stereo bit
{{- .SaveStack "Opcode"}}
{{- $x := printf "su_vm_jumptable-%v" .PTRSIZE}}
@ -65,11 +65,11 @@ su_run_vm_advance:
dec ecx ; decrement number of voices to process
bt dword [{{.Stack "PolyphonyBitmask"}}], ecx ; if voice bit of su_polyphonism not set
jnc su_op_advance_next_instrument ; goto next_instrument
mov {{.VAL}}, [{{.Stack "ValueStream"}}] ; if it was set, then repeat the opcodes for the current voice
mov {{.COM}}, [{{.Stack "CommandStream"}}]
mov {{.VAL}}, [{{.Stack "OperandStream"}}] ; if it was set, then repeat the opcodes for the current voice
mov {{.COM}}, [{{.Stack "OpcodeStream"}}]
su_op_advance_next_instrument:
mov [{{.Stack "ValueStream"}}], {{.VAL}} ; save current VAL as a checkpoint
mov [{{.Stack "CommandStream"}}], {{.COM}} ; save current COM as a checkpoint
mov [{{.Stack "OperandStream"}}], {{.VAL}} ; save current VAL as a checkpoint
mov [{{.Stack "OpcodeStream"}}], {{.COM}} ; save current COM as a checkpoint
su_op_advance_finish:
mov [{{.Stack "VoicesRemain"}}], ecx
jne su_run_vm_loop ; ZF was set by dec ecx
@ -95,7 +95,7 @@ su_op_advance_finish:
; su_nonlinear_map function: returns 2^(-24*x) of parameter number _AX
;-------------------------------------------------------------------------------
; Input: _AX : parameter number (e.g. for envelope: 0 = attac, 1 = decay...)
; INP : pointer to transformed values
; INP : pointer to transformed operands
; Output: st0 : 2^(-24*x), where x is the parameter in the range 0-1
;-------------------------------------------------------------------------------
{{.Func "su_nonlinear_map"}}

View File

@ -60,8 +60,8 @@ su_render_sampleloop: ; loop through every sample in the row
{{- end}}
{{.Push (.Song.Patch.NumVoices | printf "%v") "VoicesRemain"}}
mov {{.DX}}, {{.PTRWORD}} su_synth_obj ; {{.DX}} points to the synth object
mov {{.COM}}, {{.PTRWORD}} su_patch_code ; COM points to vm code
mov {{.VAL}}, {{.PTRWORD}} su_patch_parameters ; VAL points to unit params
mov {{.COM}}, {{.PTRWORD}} su_patch_opcodes ; COM points to vm code
mov {{.VAL}}, {{.PTRWORD}} su_patch_operands ; VAL points to unit params
{{- if .HasOp "delay"}}
mov {{.CX}}, {{.PTRWORD}} su_synth_obj + su_synthworkspace.size - su_delayline_wrk.filtstate
{{- end}}
@ -240,14 +240,14 @@ su_update_voices_skipadd:
;-------------------------------------------------------------------------------
; The code for this patch, basically indices to vm jump table
;-------------------------------------------------------------------------------
{{.Data "su_patch_code"}}
db {{.Commands | toStrings | join ","}}
{{.Data "su_patch_opcodes"}}
db {{.Opcodes | toStrings | join ","}}
;-------------------------------------------------------------------------------
; The parameters / inputs to each opcode
;-------------------------------------------------------------------------------
{{.Data "su_patch_parameters"}}
db {{.Values | toStrings | join ","}}
{{.Data "su_patch_operands"}}
db {{.Operands | toStrings | join ","}}
;-------------------------------------------------------------------------------
; Constants

View File

@ -115,7 +115,7 @@
(global.set $VAL (i32.sub (global.get $VAL) (i32.const 1)))
))
{{- end}}
(local.set $flags (call $scanValueByte))
(local.set $flags (call $scanOperand))
(local.set $freq (f32.mul
(call $input (i32.const {{.InputNumber "filter" "frequency"}}))
(call $input (i32.const {{.InputNumber "filter" "frequency"}}))
@ -252,16 +252,16 @@
(func $su_op_delay (param $stereo i32) (local $delayIndex i32) (local $delayCount i32) (local $output f32) (local $s f32) (local $filtstate f32)
{{- if .Stereo "delay"}} (local $delayCountStash i32) {{- end}}
{{- if or (.SupportsModulation "delay" "delaytime") (.SupportsParamValue "delay" "notetracking" 1)}} (local $delayTime f32) {{- end}}
(local.set $delayIndex (i32.mul (call $scanValueByte) (i32.const 2)))
(local.set $delayIndex (i32.mul (call $scanOperand) (i32.const 2)))
{{- if .Stereo "delay"}}
(local.set $delayCountStash (call $scanValueByte))
(local.set $delayCountStash (call $scanOperand))
(if (local.get $stereo)(then
(call $su_op_xch (i32.const 0))
))
loop $stereoLoop
(local.set $delayCount (local.get $delayCountStash))
{{- else}}
(local.set $delayCount (call $scanValueByte))
(local.set $delayCount (call $scanOperand))
{{- end}}
(local.set $output (f32.mul
(call $input (i32.const {{.InputNumber "delay" "dry"}}))

View File

@ -9,15 +9,15 @@
(if (local.tee $opcode (i32.shr_u (local.get $opcodeWithStereo) (i32.const 1)))(then ;; if $opcode = $opcodeStereo >> 1; $opcode != 0 {
(local.set $paramNum (i32.const 0))
(local.set $paramX4 (i32.const 0))
loop $transform_values_loop
loop $transform_operands_loop
{{- $addr := sub (index .Labels "su_vm_transformcounts") 1}}
(if (i32.lt_u (local.get $paramNum) (i32.load8_u offset={{$addr}} (local.get $opcode)))(then ;;(i32.ge (local.get $paramNum) (i32.load8_u (local.get $opcode))) /*TODO: offset to transformvalues
(local.set $WRKplusparam (i32.add (global.get $WRK) (local.get $paramX4)))
(f32.store offset={{index .Labels "su_transformedvalues"}}
(f32.store offset={{index .Labels "su_transformedoperands"}}
(local.get $paramX4)
(f32.add
(f32.mul
(f32.convert_i32_u (call $scanValueByte))
(f32.convert_i32_u (call $scanOperand))
(f32.const 0.0078125) ;; scale from 0-128 to 0.0 - 1.0
)
(f32.load offset=32 (local.get $WRKplusparam)) ;; add modulation
@ -26,7 +26,7 @@
(f32.store offset=32 (local.get $WRKplusparam) (f32.const 0.0)) ;; clear modulations
(local.set $paramNum (i32.add (local.get $paramNum) (i32.const 1))) ;; $paramNum++
(local.set $paramX4 (i32.add (local.get $paramX4) (i32.const 4)))
br $transform_values_loop ;; continue looping
br $transform_operands_loop ;; continue looping
))
;; paramNum was >= the number of parameters to transform, exiting loop
end
@ -59,7 +59,7 @@
;; The transformed values start at 512 (TODO: change magic constants somehow)
;;-------------------------------------------------------------------------------
(func $input (param $inputNumber i32) (result f32)
(f32.load offset={{index .Labels "su_transformedvalues"}} (i32.mul (local.get $inputNumber) (i32.const 4)))
(f32.load offset={{index .Labels "su_transformedoperands"}} (i32.mul (local.get $inputNumber) (i32.const 4)))
)
;;-------------------------------------------------------------------------------

View File

@ -31,8 +31,8 @@
; The code for this patch, basically indices to vm jump table
;-------------------------------------------------------------------------------
*/}}
{{- .SetDataLabel "su_patch_code"}}
{{- range .Commands}}
{{- .SetDataLabel "su_patch_opcodes"}}
{{- range .Opcodes}}
{{- $.DataB .}}
{{- end}}
@ -41,8 +41,8 @@
; The parameters / inputs to each opcode
;-------------------------------------------------------------------------------
*/}}
{{- .SetDataLabel "su_patch_parameters"}}
{{- range .Values}}
{{- .SetDataLabel "su_patch_operands"}}
{{- range .Operands}}
{{- $.DataB .}}
{{- end}}
@ -79,11 +79,11 @@
{{- /*
;-------------------------------------------------------------------------------
; Allocate memory for transformed values.
; Allocate memory for transformed operands.
;-------------------------------------------------------------------------------
*/}}
{{- .Align}}
{{- .SetBlockLabel "su_transformedvalues"}}
{{- .SetBlockLabel "su_transformedoperands"}}
{{- .Block 32}}
{{- /*
@ -193,7 +193,7 @@
local.get 0
)
(func $scanValueByte (result i32) ;; scans positions $VAL for a byte, incrementing $VAL afterwards
(func $scanOperand (result i32) ;; scans positions $VAL for a byte, incrementing $VAL afterwards
(i32.load8_u (global.get $VAL)) ;; in other words: returns byte [$VAL++]
(global.set $VAL (i32.add (global.get $VAL) (i32.const 1))) ;; $VAL++
)
@ -211,8 +211,8 @@
(call $su_update_voices)
(global.set $sample (i32.const 0))
loop $sample_loop
(global.set $COM (i32.const {{index .Labels "su_patch_code"}}))
(global.set $VAL (i32.const {{index .Labels "su_patch_parameters"}}))
(global.set $COM (i32.const {{index .Labels "su_patch_opcodes"}}))
(global.set $VAL (i32.const {{index .Labels "su_patch_operands"}}))
{{- if .SupportsPolyphony}}
(global.set $COM_instr_start (global.get $COM))
(global.set $VAL_instr_start (global.get $VAL))

View File

@ -47,7 +47,7 @@
;; Stereo: also add gain*ST1 to right port
;;-------------------------------------------------------------------------------
(func $su_op_aux (param $stereo i32) (local $addr i32)
(local.set $addr (i32.add (i32.mul (call $scanValueByte) (i32.const 4)) (i32.const {{index .Labels "su_globalports"}})))
(local.set $addr (i32.add (i32.mul (call $scanOperand) (i32.const 4)) (i32.const {{index .Labels "su_globalports"}})))
{{- if .Stereo "aux"}}
loop $stereoLoop
{{- end}}
@ -78,7 +78,7 @@
;; Stereo: also add right signal to the following address
;;-------------------------------------------------------------------------------
(func $su_op_send (param $stereo i32) (local $address i32) (local $scaledAddress i32)
(local.set $address (i32.add (call $scanValueByte) (i32.shl (call $scanValueByte) (i32.const 8))))
(local.set $address (i32.add (call $scanOperand) (i32.shl (call $scanOperand) (i32.const 8))))
(if (i32.eqz (i32.and (local.get $address) (i32.const 8)))(then
{{- if .Stereo "send"}}
(if (local.get $stereo)(then

View File

@ -118,7 +118,7 @@
(local.set $freqMod (f32.load offset={{.InputNumber "oscillator" "frequency" | mul 4 | add 32}} (global.get $WRK)))
(f32.store offset={{.InputNumber "oscillator" "frequency" | mul 4 | add 32}} (global.get $WRK) (f32.const 0))
{{- end}}
(local.set $flags (call $scanValueByte))
(local.set $flags (call $scanOperand))
(local.set $detune (call $inputSigned (i32.const {{.InputNumber "oscillator" "detune"}})))
{{- if .Stereo "oscillator"}}
loop $stereoLoop
@ -197,7 +197,7 @@
{{- if .SupportsParamValueOtherThan "oscillator" "unison" 0}}
(call $push (f32.add (call $pop) (call $pop)))
(if (local.tee $unison (i32.sub (local.get $unison) (i32.const 1)))(then
(f32.store offset={{.InputNumber "oscillator" "phase" | mul 4 | add (index .Labels "su_transformedvalues")}} (i32.const 0)
(f32.store offset={{.InputNumber "oscillator" "phase" | mul 4 | add (index .Labels "su_transformedoperands")}} (i32.const 0)
(f32.add
(call $input (i32.const {{.InputNumber "oscillator" "phase"}}))
(f32.const 0.08333333) ;; 1/12, add small phase shift so all oscillators don't start in phase
@ -341,7 +341,7 @@
;; Stereo: also push the right channel (stack in l r order)
;;-------------------------------------------------------------------------------
(func $su_op_in (param $stereo i32) (local $addr i32)
call $scanValueByte
call $scanOperand
{{- if .Stereo "in"}}
(i32.add (local.get $stereo)) ;; start from right channel if stereo
{{- end}}