feat: envelopexp ported to go synth

This commit is contained in:
qm210
2024-10-22 01:04:39 +02:00
parent cf05e68471
commit 9678108fd1
2 changed files with 15 additions and 8 deletions

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"github.com/vsariola/sointu/cmd"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -14,7 +15,6 @@ import (
"github.com/vsariola/sointu" "github.com/vsariola/sointu"
"github.com/vsariola/sointu/oto" "github.com/vsariola/sointu/oto"
"github.com/vsariola/sointu/version" "github.com/vsariola/sointu/version"
"github.com/vsariola/sointu/vm/compiler/bridge"
) )
func main() { func main() {
@ -93,7 +93,7 @@ func main() {
return fmt.Errorf("the song could not be parsed as .json (%v) or .yml (%v)", errJSON, errYaml) return fmt.Errorf("the song could not be parsed as .json (%v) or .yml (%v)", errJSON, errYaml)
} }
} }
buffer, err := sointu.Play(bridge.NativeSynther{}, song, nil) // render the song to calculate its length buffer, err := sointu.Play(cmd.MainSynther, song, nil) // render the song to calculate its length
if err != nil { if err != nil {
return fmt.Errorf("sointu.Play failed: %v", err) return fmt.Errorf("sointu.Play failed: %v", err)
} }

View File

@ -330,25 +330,27 @@ func (s *GoSynth) Render(buffer sointu.AudioBuffer, maxtime int) (samples int, t
stack = append(stack, output) stack = append(stack, output)
} }
case opEnvelopexp: case opEnvelopexp:
// TODO @qm210 - for now, this just clones the envelope so everything is wired up, but IT IS NOT IMPLEMENTED YET
// is ignoring for now
// - params[1] - attack shape parameter (center value should mean "linear")
// - params[3] - decay shape parameter (center value should mean "linear")
if !voices[0].sustain { if !voices[0].sustain {
unit.state[0] = envStateRelease // set state to release unit.state[0] = envStateRelease // set state to release
} }
state := unit.state[0] state := unit.state[0]
level := unit.state[1] level := unit.state[1]
exponent := float64(1)
baseline := float32(0)
switch state { switch state {
case envStateAttack: case envStateAttack:
exponent = scaledEnvelopExponent(params[1])
level += nonLinearMap(params[0]) level += nonLinearMap(params[0])
if level >= 1 { if level >= 1 {
level = 1 level = 1
state = envStateDecay state = envStateDecay
} }
case envStateDecay: case envStateDecay:
exponent = scaledEnvelopExponent(params[3])
sustain := params[4]
baseline = sustain
level -= nonLinearMap(params[2]) level -= nonLinearMap(params[2])
if sustain := params[4]; level <= sustain { if level <= sustain {
level = sustain level = sustain
} }
case envStateRelease: case envStateRelease:
@ -359,7 +361,8 @@ func (s *GoSynth) Render(buffer sointu.AudioBuffer, maxtime int) (samples int, t
} }
unit.state[0] = state unit.state[0] = state
unit.state[1] = level unit.state[1] = level
output := level * params[6] expLevel := float32(math.Pow(float64(level), exponent))
output := (baseline + (1-baseline)*expLevel) * params[6]
stack = append(stack, output) stack = append(stack, output)
if stereo { if stereo {
stack = append(stack, output) stack = append(stack, output)
@ -646,6 +649,10 @@ func nonLinearMap(value float32) float32 {
return float32(math.Exp2(float64(-24 * value))) return float32(math.Exp2(float64(-24 * value)))
} }
func scaledEnvelopExponent(value float32) float64 {
return math.Pow(2, 6*(0.5-float64(value)))
}
func clip(value float32) float32 { func clip(value float32) float32 {
if value < -1 { if value < -1 {
return -1 return -1