mirror of
https://github.com/vsariola/sointu.git
synced 2025-05-28 03:10:24 -04:00
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.
145 lines
7.0 KiB
Plaintext
145 lines
7.0 KiB
Plaintext
;;-------------------------------------------------------------------------------
|
|
;; su_run_vm function: runs the entire virtual machine once, creating 1 sample
|
|
;;-------------------------------------------------------------------------------
|
|
(func $su_run_vm (local $opcodeWithStereo i32) (local $opcode i32) (local $paramNum i32) (local $paramX4 i32) (local $WRKplusparam i32)
|
|
loop $vm_loop
|
|
(local.set $opcodeWithStereo (i32.load8_u (global.get $COM)))
|
|
(global.set $COM (i32.add (global.get $COM) (i32.const 1))) ;; move to next instruction
|
|
(global.set $WRK (i32.add (global.get $WRK) (i32.const 64))) ;; move WRK to next unit
|
|
(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_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_transformedoperands"}}
|
|
(local.get $paramX4)
|
|
(f32.add
|
|
(f32.mul
|
|
(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
|
|
)
|
|
)
|
|
(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_operands_loop ;; continue looping
|
|
))
|
|
;; paramNum was >= the number of parameters to transform, exiting loop
|
|
end
|
|
(call_indirect (type $opcode_func_signature) (i32.and (local.get $opcodeWithStereo) (i32.const 1)) (local.get $opcode))
|
|
)(else ;; advance to next voice
|
|
(global.set $voice (i32.add (global.get $voice) (i32.const 4096))) ;; advance to next voice
|
|
(global.set $WRK (global.get $voice)) ;; set WRK point to beginning of voice
|
|
(global.set $voicesRemain (i32.sub (global.get $voicesRemain) (i32.const 1)))
|
|
{{- if .SupportsPolyphony}}
|
|
(if (i32.and (i32.shr_u (i32.const {{.PolyphonyBitmask | printf "%v"}}) (global.get $voicesRemain)) (i32.const 1))(then
|
|
(global.set $VAL (global.get $VAL_instr_start))
|
|
(global.set $COM (global.get $COM_instr_start))
|
|
))
|
|
(global.set $VAL_instr_start (global.get $VAL))
|
|
(global.set $COM_instr_start (global.get $COM))
|
|
{{- end}}
|
|
(br_if 2 (i32.eqz (global.get $voicesRemain))) ;; if no more voices remain, return from function
|
|
))
|
|
br $vm_loop
|
|
end
|
|
)
|
|
|
|
{{- template "arithmetic.wat" .}}
|
|
{{- template "effects.wat" .}}
|
|
{{- template "sources.wat" .}}
|
|
{{- template "sinks.wat" .}}
|
|
|
|
;;-------------------------------------------------------------------------------
|
|
;; $input returns the float value of a transformed to 0.0 - 1.0f range.
|
|
;; The transformed values start at 512 (TODO: change magic constants somehow)
|
|
;;-------------------------------------------------------------------------------
|
|
(func $input (param $inputNumber i32) (result f32)
|
|
(f32.load offset={{index .Labels "su_transformedoperands"}} (i32.mul (local.get $inputNumber) (i32.const 4)))
|
|
)
|
|
|
|
;;-------------------------------------------------------------------------------
|
|
;; $inputSigned returns the float value of a transformed to -1.0 - 1.0f range.
|
|
;;-------------------------------------------------------------------------------
|
|
(func $inputSigned (param $inputNumber i32) (result f32)
|
|
(f32.sub (f32.mul (call $input (local.get $inputNumber)) (f32.const 2)) (f32.const 1))
|
|
)
|
|
|
|
;;-------------------------------------------------------------------------------
|
|
;; $nonLinearMap: x -> 2^(-24*input[x])
|
|
;;-------------------------------------------------------------------------------
|
|
(func $nonLinearMap (param $value i32) (result f32)
|
|
(call $pow2
|
|
(f32.mul
|
|
(f32.const -24)
|
|
(call $input (local.get $value))
|
|
)
|
|
)
|
|
)
|
|
|
|
;;-------------------------------------------------------------------------------
|
|
;; $pow2: x -> 2^x
|
|
;;-------------------------------------------------------------------------------
|
|
(func $pow2 (param $value f32) (result f32)
|
|
(call $pow (f32.const 2) (local.get $value))
|
|
)
|
|
|
|
;;-------------------------------------------------------------------------------
|
|
;; Waveshaper(x,a): "distorts" signal x by amount a
|
|
;; Returns x*a/(1-a+(2*a-1)*abs(x))
|
|
;;-------------------------------------------------------------------------------
|
|
(func $waveshaper (param $signal f32) (param $amount f32) (result f32)
|
|
(local.set $signal (call $clip (local.get $signal)))
|
|
(f32.mul
|
|
(local.get $signal)
|
|
(f32.div
|
|
(local.get $amount)
|
|
(f32.add
|
|
(f32.const 1)
|
|
(f32.sub
|
|
(f32.mul
|
|
(f32.sub
|
|
(f32.add (local.get $amount) (local.get $amount))
|
|
(f32.const 1)
|
|
)
|
|
(f32.abs (local.get $signal))
|
|
)
|
|
(local.get $amount)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;;-------------------------------------------------------------------------------
|
|
;; Clip(a : f32) returns min(max(a,-1),1)
|
|
;;-------------------------------------------------------------------------------
|
|
(func $clip (param $value f32) (result f32)
|
|
(f32.min (f32.max (local.get $value) (f32.const -1.0)) (f32.const 1.0))
|
|
)
|
|
|
|
(func $stereoHelper (param $stereo i32) (param $tableIndex i32)
|
|
(if (local.get $stereo)(then
|
|
(call $pop)
|
|
(global.set $WRK (i32.add (global.get $WRK) (i32.const 16)))
|
|
(call_indirect (type $opcode_func_signature) (i32.const 0) (local.get $tableIndex))
|
|
(global.set $WRK (i32.sub (global.get $WRK) (i32.const 16)))
|
|
(call $push)
|
|
))
|
|
)
|
|
|
|
;;-------------------------------------------------------------------------------
|
|
;; 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.
|
|
;;-------------------------------------------------------------------------------
|
|
(table {{.Instructions | len | add 1}} funcref)
|
|
(elem (i32.const 1) ;; start the indices at 1, as 0 is reserved for advance
|
|
{{- range .Instructions}}
|
|
$su_op_{{.}}
|
|
{{- end}}
|
|
)
|