{{- if .HasOp "outaux"}} ;;------------------------------------------------------------------------------- ;; OUTAUX opcode: outputs to main and aux1 outputs and pops the signal ;;------------------------------------------------------------------------------- ;; Mono: add outgain*ST0 to main left port and auxgain*ST0 to aux1 left ;; Stereo: also add outgain*ST1 to main right port and auxgain*ST1 to aux1 right ;;------------------------------------------------------------------------------- (func $su_op_outaux (param $stereo i32) (local $addr i32) (local.set $addr (i32.const {{index .Labels "su_globalports"}})) {{- if .Stereo "outaux"}} loop $stereoLoop {{- end}} (f32.store ;; send (local.get $addr) (f32.add (f32.mul (call $peek) (call $input (i32.const {{.InputNumber "outaux" "outgain"}})) ) (f32.load (local.get $addr)) ) ) (f32.store offset=8 (local.get $addr) (f32.add (f32.mul (call $pop) (call $input (i32.const {{.InputNumber "outaux" "auxgain"}})) ) (f32.load offset=8 (local.get $addr)) ) ) {{- if .Stereo "outaux"}} (local.set $addr (i32.add (local.get $addr) (i32.const 4))) (br_if $stereoLoop (i32.eqz (local.tee $stereo (i32.eqz (local.get $stereo))))) end {{- end}} ) {{end}} {{- if .HasOp "aux"}} ;;------------------------------------------------------------------------------- ;; AUX opcode: outputs the signal to aux (or main) port and pops the signal ;;------------------------------------------------------------------------------- ;; Mono: add gain*ST0 to left port ;; 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 $scanOperand) (i32.const 4)) (i32.const {{index .Labels "su_globalports"}}))) {{- if .Stereo "aux"}} loop $stereoLoop {{- end}} (f32.store (local.get $addr) (f32.add (f32.mul (call $pop) (call $input (i32.const {{.InputNumber "aux" "gain"}})) ) (f32.load (local.get $addr)) ) ) {{- if .Stereo "aux"}} (local.set $addr (i32.add (local.get $addr) (i32.const 4))) (br_if $stereoLoop (i32.eqz (local.tee $stereo (i32.eqz (local.get $stereo))))) end {{- end}} ) {{end}} {{- if .HasOp "send"}} ;;------------------------------------------------------------------------------- ;; SEND opcode: adds the signal to a port ;;------------------------------------------------------------------------------- ;; Mono: adds signal to a memory address, defined by a word in VAL stream ;; 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 $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 (call $push (call $peek2)) (call $push (call $peek2)) )(else {{- end}} (call $push (call $peek)) {{- if .Stereo "send"}} )) {{- end}} )) {{- if .Stereo "send"}} loop $stereoLoop {{- end}} (local.set $scaledAddress (i32.add (i32.mul (i32.and (local.get $address) (i32.const 0x7FF7)) (i32.const 4)) {{- if .SupportsGlobalSend}} (select (i32.const {{index .Labels "su_synth"}}) {{- end}} (global.get $voice) {{- if .SupportsGlobalSend}} (i32.and (local.get $address)(i32.const 0x8000)) ) {{- end}} )) (f32.store offset=32 (local.get $scaledAddress) (f32.add (f32.load offset=32 (local.get $scaledAddress)) (f32.mul (call $inputSigned (i32.const {{.InputNumber "send" "amount"}})) (call $pop) ) ) ) {{- if .Stereo "send"}} (local.set $address (i32.add (local.get $address) (i32.const 1))) (br_if $stereoLoop (i32.eqz (local.tee $stereo (i32.eqz (local.get $stereo))))) end {{- end}} ) {{end}} {{- if .HasOp "out"}} ;;------------------------------------------------------------------------------- ;; OUT opcode: outputs and pops the signal ;;------------------------------------------------------------------------------- {{- if .Mono "out"}} ;; Mono: add ST0 to main left port, then pop {{- end}} {{- if .Stereo "out"}} ;; Stereo: add ST0 to left out and ST1 to right out, then pop {{- end}} ;;------------------------------------------------------------------------------- (func $su_op_out (param $stereo i32) (local $ptr i32) (local.set $ptr (i32.const {{index .Labels "su_globalports"}})) ;; synth.left (f32.store (local.get $ptr) (f32.add (f32.mul (call $pop) (call $input (i32.const {{.InputNumber "out" "gain"}})) ) (f32.load (local.get $ptr)) ) ) {{- if .StereoAndMono "out"}} (if (local.get $stereo)(then {{- end}} {{- if .Stereo "out"}} (local.set $ptr (i32.const {{add (index .Labels "su_globalports") 4}})) ;; synth.right (f32.store (local.get $ptr) (f32.add (f32.mul (call $pop) (call $input (i32.const {{.InputNumber "out" "gain"}})) ) (f32.load (local.get $ptr)) ) ) {{- end}} {{- if .StereoAndMono "out"}} )) {{- end}} ) {{end}} {{- if .HasOp "speed"}} ;;------------------------------------------------------------------------------- ;; SPEED opcode: modulate the speed (bpm) of the song based on ST0 ;;------------------------------------------------------------------------------- ;; Mono: adds or subtracts the ticks, a value of 0.5 is neutral & will7 ;; result in no speed change. ;; There is no STEREO version. ;;------------------------------------------------------------------------------- (func $su_op_speed (param $stereo i32) (local $r f32) (local $w i32) (f32.store (global.get $WRK) (local.tee $r (f32.sub (local.tee $r (f32.add (f32.load (global.get $WRK)) (f32.sub (call $pow2 (f32.mul (call $pop) (f32.const 2.206896551724138) ) ) (f32.const 1) ) ) ) (f32.convert_i32_s (local.tee $w (i32.trunc_f32_s (local.get $r))) ;; note: small difference from x86, as this is trunc; x86 rounds to nearest) ) ) ) ) (global.set $sample (i32.add (global.get $sample) (local.get $w))) ) {{end}}