mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-17 20:44:29 -04:00
fix(vm): change crush resolution to bits (closes #79)
BREAKING CHANGE: The problem with crush was that it had very few usable values. This changes the crush to map the value nonlinearly, so the crush resolution is bits. Still the upper portion of the values is not very usable (bits 12-24 i.e. hardly any crushing), but at least the lower portion is usable. But now crush resolution has slightly different meaning.
This commit is contained in:
parent
1ac2ad3c75
commit
7df8103bf9
@ -22,6 +22,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- In the WebAssembly core, $WRK was messed after stereo oscillators,
|
- In the WebAssembly core, $WRK was messed after stereo oscillators,
|
||||||
making modulations not work
|
making modulations not work
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- The crush resolution is now in bits instead of linear range; this is a
|
||||||
|
breaking change and changes the meaning of the resolution values. But
|
||||||
|
now there are more usable values in the resolution.
|
||||||
|
|
||||||
## v0.1.0
|
## v0.1.0
|
||||||
### Added
|
### Added
|
||||||
- An instrument (set of opcodes & accompanying values) can have any number of voices.
|
- An instrument (set of opcodes & accompanying values) can have any number of voices.
|
||||||
|
5
patch.go
5
patch.go
@ -233,6 +233,11 @@ func (p Patch) ParamHintString(instrIndex, unitIndex int, param string) string {
|
|||||||
return "aux3 right"
|
return "aux3 right"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "crush":
|
||||||
|
switch param {
|
||||||
|
case "resolution":
|
||||||
|
return fmt.Sprintf("%v bits", 24*float32(value)/128)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -25,6 +25,6 @@ patch:
|
|||||||
- type: mulp
|
- type: mulp
|
||||||
parameters: {stereo: 0}
|
parameters: {stereo: 0}
|
||||||
- type: crush
|
- type: crush
|
||||||
parameters: {resolution: 64, stereo: 0}
|
parameters: {resolution: 32, stereo: 0}
|
||||||
- type: out
|
- type: out
|
||||||
parameters: {gain: 128, stereo: 1}
|
parameters: {gain: 128, stereo: 1}
|
||||||
|
@ -23,6 +23,6 @@ patch:
|
|||||||
- type: mulp
|
- type: mulp
|
||||||
parameters: {stereo: 0}
|
parameters: {stereo: 0}
|
||||||
- type: crush
|
- type: crush
|
||||||
parameters: {resolution: 32, stereo: 1}
|
parameters: {resolution: 8, stereo: 1}
|
||||||
- type: out
|
- type: out
|
||||||
parameters: {gain: 128, stereo: 1}
|
parameters: {gain: 128, stereo: 1}
|
||||||
|
@ -63,7 +63,7 @@ if (process.argv.length <= 3) {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
let margin = 1e-2 * (instance.exports.t.value ? 32767 : 1);
|
let margin = 2e-2 * (instance.exports.t.value ? 32767 : 1);
|
||||||
|
|
||||||
var firstError = true, firstErrorPos, errorCount = 0
|
var firstError = true, firstErrorPos, errorCount = 0
|
||||||
// we still have occasional sample wrong here or there. We only consider this a true error
|
// we still have occasional sample wrong here or there. We only consider this a true error
|
||||||
|
@ -34,16 +34,19 @@ su_op_hold_holding:
|
|||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; CRUSH opcode: quantize the signal to finite number of levels
|
; CRUSH opcode: quantize the signal to finite number of levels
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; Mono: x -> e*int(x/e)
|
; Mono: x -> e*int(x/e) where e=2**(-24*resolution)
|
||||||
; Stereo: l r -> e*int(l/e) e*int(r/e)
|
; Stereo: l r -> e*int(l/e) e*int(r/e)
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
{{.Func "su_op_crush" "Opcode"}}
|
{{.Func "su_op_crush" "Opcode"}}
|
||||||
{{- if .Stereo "crush"}}
|
{{- if .Stereo "crush"}}
|
||||||
{{.Call "su_effects_stereohelper"}}
|
{{.Call "su_effects_stereohelper"}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
fdiv dword [{{.Input "crush" "resolution"}}]
|
xor eax, eax
|
||||||
|
{{.Call "su_nonlinear_map"}}
|
||||||
|
fxch st0, st1
|
||||||
|
fdiv st0, st1
|
||||||
frndint
|
frndint
|
||||||
fmul dword [{{.Input "crush" "resolution"}}]
|
fmulp st1, st0
|
||||||
ret
|
ret
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
@ -54,14 +54,14 @@
|
|||||||
;; Mono: x -> e*int(x/e)
|
;; Mono: x -> e*int(x/e)
|
||||||
;; Stereo: l r -> e*int(l/e) e*int(r/e)
|
;; Stereo: l r -> e*int(l/e) e*int(r/e)
|
||||||
;;-------------------------------------------------------------------------------
|
;;-------------------------------------------------------------------------------
|
||||||
(func $su_op_crush (param $stereo i32)
|
(func $su_op_crush (param $stereo i32) (local $e f32)
|
||||||
{{- if .Stereo "crush"}}
|
{{- if .Stereo "crush"}}
|
||||||
(call $stereoHelper (local.get $stereo) (i32.const {{div (.GetOp "crush") 2}}))
|
(call $stereoHelper (local.get $stereo) (i32.const {{div (.GetOp "crush") 2}}))
|
||||||
{{- end}}
|
{{- end}}
|
||||||
call $pop
|
call $pop
|
||||||
(f32.div (call $input (i32.const {{.InputNumber "crush" "resolution"}})))
|
(f32.div (local.tee $e (call $nonLinearMap (i32.const {{.InputNumber "crush" "resolution"}}))))
|
||||||
f32.nearest
|
f32.nearest
|
||||||
(f32.mul (call $input (i32.const {{.InputNumber "crush" "resolution"}})))
|
(f32.mul (local.get $e))
|
||||||
call $push
|
call $push
|
||||||
)
|
)
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -611,7 +611,8 @@ func clip(value float32) float32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func crush(value, amount float32) float32 {
|
func crush(value, amount float32) float32 {
|
||||||
return float32(math.Round(float64(value/amount)) * float64(amount))
|
n := nonLinearMap(amount)
|
||||||
|
return float32(math.Round(float64(value/n)) * float64(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func waveshape(value, amount float32) float32 {
|
func waveshape(value, amount float32) float32 {
|
||||||
|
Reference in New Issue
Block a user