4 Commits

13 changed files with 405 additions and 370 deletions

View File

@ -204,7 +204,7 @@ jobs:
path: sointu-${{ matrix.config.os }} path: sointu-${{ matrix.config.os }}
- name: Zip binaries - name: Zip binaries
run: | run: |
zip ./sointu-${{ matrix.config.os }}.zip sointu-${{ matrix.config.os }}/* zip -r ./sointu-${{ matrix.config.os }}.zip sointu-${{ matrix.config.os }}/*
- name: Upload release assets - name: Upload release assets
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:

7
go.mod
View File

@ -3,14 +3,14 @@ module github.com/vsariola/sointu
go 1.24.0 go 1.24.0
require ( require (
gioui.org v0.9.0 gioui.org v0.9.1-0.20260317161059-dfe4ff020039
gioui.org/x v0.8.1 gioui.org/x v0.8.1
github.com/Masterminds/sprig v2.22.0+incompatible github.com/Masterminds/sprig v2.22.0+incompatible
github.com/ebitengine/oto/v3 v3.5.0-alpha.0.20260119133252-bae718d5ff43 github.com/ebitengine/oto/v3 v3.5.0-alpha.0.20260119133252-bae718d5ff43
github.com/viterin/vek v0.4.2 github.com/viterin/vek v0.4.2
gitlab.com/gomidi/midi/v2 v2.2.10 gitlab.com/gomidi/midi/v2 v2.2.10
golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0 golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0
golang.org/x/text v0.24.0 golang.org/x/text v0.32.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
pipelined.dev/audio/vst2 v0.10.1-0.20240223162706-41e9b65fb5c2 pipelined.dev/audio/vst2 v0.10.1-0.20240223162706-41e9b65fb5c2
) )
@ -32,9 +32,10 @@ require (
github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/viterin/partial v1.1.0 // indirect github.com/viterin/partial v1.1.0 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/crypto v0.46.0 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
golang.org/x/image v0.26.0 // indirect golang.org/x/image v0.26.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sys v0.40.0 // indirect golang.org/x/sys v0.40.0 // indirect
pipelined.dev/pipe v0.11.0 // indirect pipelined.dev/pipe v0.11.0 // indirect
pipelined.dev/signal v0.10.0 // indirect pipelined.dev/signal v0.10.0 // indirect

26
go.sum
View File

@ -1,16 +1,10 @@
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY= eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY=
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA= eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA=
gioui.org v0.8.1-0.20250526181049-1a17e9ea3725 h1:8dzkqzvWLIwW6HEQv5CinK53vMeANmUEETzpcbtPRp0= gioui.org v0.9.1-0.20260317161059-dfe4ff020039 h1:HhmvnsUsNudSUXqgisYXymyjrKHgazBKhiH0TLALVjo=
gioui.org v0.8.1-0.20250526181049-1a17e9ea3725/go.mod h1:CjNig0wAhLt9WZxOPAusgFD8x8IRvqt26LdDBa3Jvao= gioui.org v0.9.1-0.20260317161059-dfe4ff020039/go.mod h1:BdI7mF5DCa3kxlo3G93XHL7khtZnk1gu4335pExk8gs=
gioui.org v0.8.1-0.20250624114559-c3ce484b5e80 h1:cnimNlq1PEHY4z1Cy32n6In86VUF5/VLi7cWHAM1XcY=
gioui.org v0.8.1-0.20250624114559-c3ce484b5e80/go.mod h1:CjNig0wAhLt9WZxOPAusgFD8x8IRvqt26LdDBa3Jvao=
gioui.org v0.9.0 h1:4u7XZwnb5kzQW91Nz/vR0wKD6LdW9CaVF96r3rfy4kc=
gioui.org v0.9.0/go.mod h1:CjNig0wAhLt9WZxOPAusgFD8x8IRvqt26LdDBa3Jvao=
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA= gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
gioui.org/x v0.7.1 h1:7bnQHsV7qB36tIUit2WDcUx4Cnmo+6T9I38B9brLQ7o=
gioui.org/x v0.7.1/go.mod h1:5CzZ64oFpOaqb2kaMvj+QEr5T3nVuLKD0LizLH32ii0=
gioui.org/x v0.8.1 h1:Q2wumEOfjz3XfRa3TEi6w7dq8+cxV8zsYK8xXQkrCRk= gioui.org/x v0.8.1 h1:Q2wumEOfjz3XfRa3TEi6w7dq8+cxV8zsYK8xXQkrCRk=
gioui.org/x v0.8.1/go.mod h1:v2g60aiZtIVR7lNFXZ123+U0kijJeOChODSuqr7MFSI= gioui.org/x v0.8.1/go.mod h1:v2g60aiZtIVR7lNFXZ123+U0kijJeOChODSuqr7MFSI=
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI= git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI=
@ -28,12 +22,8 @@ github.com/chewxy/math32 v1.11.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUw
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ebitengine/oto/v3 v3.3.0 h1:34lJpJLqda0Iee9g9p8RWtVVwBcOOO2YSIS2x4yD1OQ=
github.com/ebitengine/oto/v3 v3.3.0/go.mod h1:MZeb/lwoC4DCOdiTIxYezrURTw7EvK/yF863+tmBI+U=
github.com/ebitengine/oto/v3 v3.5.0-alpha.0.20260119133252-bae718d5ff43 h1:2sTZTp/Nc8srRyDdari4gS+clwfnuNmpLiLvmwxqPVE= github.com/ebitengine/oto/v3 v3.5.0-alpha.0.20260119133252-bae718d5ff43 h1:2sTZTp/Nc8srRyDdari4gS+clwfnuNmpLiLvmwxqPVE=
github.com/ebitengine/oto/v3 v3.5.0-alpha.0.20260119133252-bae718d5ff43/go.mod h1:IOleLVD0m+CMak3mRVwsYY8vTctQgOM0iiL6S7Ar7eI= github.com/ebitengine/oto/v3 v3.5.0-alpha.0.20260119133252-bae718d5ff43/go.mod h1:IOleLVD0m+CMak3mRVwsYY8vTctQgOM0iiL6S7Ar7eI=
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4= github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4=
@ -66,20 +56,20 @@ github.com/viterin/vek v0.4.2 h1:Vyv04UjQT6gcjEFX82AS9ocgNbAJqsHviheIBdPlv5U=
github.com/viterin/vek v0.4.2/go.mod h1:A4JRAe8OvbhdzBL5ofzjBS0J29FyUrf95tQogvtHHUc= github.com/viterin/vek v0.4.2/go.mod h1:A4JRAe8OvbhdzBL5ofzjBS0J29FyUrf95tQogvtHHUc=
gitlab.com/gomidi/midi/v2 v2.2.10 h1:u9D+5TM0vkFWF5DcO6xGKG99ERYqksh6wPj2X2Rx5A8= gitlab.com/gomidi/midi/v2 v2.2.10 h1:u9D+5TM0vkFWF5DcO6xGKG99ERYqksh6wPj2X2Rx5A8=
gitlab.com/gomidi/midi/v2 v2.2.10/go.mod h1:ENtYaJPOwb2N+y7ihv/L7R4GtWjbknouhIIkMrJ5C0g= gitlab.com/gomidi/midi/v2 v2.2.10/go.mod h1:ENtYaJPOwb2N+y7ihv/L7R4GtWjbknouhIIkMrJ5C0g=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0 h1:tMSqXTK+AQdW3LpCbfatHSRPHeW6+2WuxaVQuHftn80= golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0 h1:tMSqXTK+AQdW3LpCbfatHSRPHeW6+2WuxaVQuHftn80=
golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8= golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY= golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c= golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

647
patch.go
View File

@ -81,15 +81,11 @@ type (
ParamMap map[string]int ParamMap map[string]int
// UnitParameter documents one parameter that an unit takes // UnitType documents the parameters and stack use of a unit type
UnitParameter struct { UnitType struct {
Name string // thould be found with this name in the Unit.Parameters map Params []UnitParameter
MinValue int // minimum value of the parameter, inclusive DefaultVarArgs []int
MaxValue int // maximum value of the parameter, inclusive StackUse func(*Unit) StackUse
Neutral int // neutral value of the parameter
CanSet bool // if true, then this parameter can be set through the gui
CanModulate bool // if true, then this parameter can be modulated i.e. has a port number in "send" unit
DisplayFunc UnitParameterDisplayFunc
} }
// StackUse documents how a unit will affect the signal stack. // StackUse documents how a unit will affect the signal stack.
@ -99,133 +95,358 @@ type (
NumOutputs int // NumOutputs is the number of outputs produced by the unit. This is used to determine how many outputs are needed for the unit. NumOutputs int // NumOutputs is the number of outputs produced by the unit. This is used to determine how many outputs are needed for the unit.
} }
// UnitParameter documents one parameter that an unit takes
UnitParameter struct {
Name string // thould be found with this name in the Unit.Parameters map
MinValue int // minimum value of the parameter, inclusive
MaxValue int // maximum value of the parameter, inclusive
Neutral int // neutral value of the parameter
Default int // the default value of the parameter
CanSet bool // if true, then this parameter can be set through the gui
CanModulate bool // if true, then this parameter can be modulated i.e. has a port number in "send" unit
DisplayFunc UnitParameterDisplayFunc
}
UnitParameterDisplayFunc func(int) (value string, unit string) UnitParameterDisplayFunc func(int) (value string, unit string)
) )
// UnitTypes documents all the available unit types and if they support stereo variant // UnitTypes documents all the available unit types and if they support stereo
// and what parameters they take. // variant and what parameters they take. If you add a new unit type, add it
var UnitTypes = map[string]([]UnitParameter){ // here and also add its opcode to vm/opcodes.go by running "go generate ./vm"
"add": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, // in the terminal.
"addp": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, var UnitTypes = map[string]UnitType{
"pop": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, "add": {
"loadnote": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
"mul": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, StackUse: func(unit *Unit) StackUse {
"mulp": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, if stereo, ok := unit.Parameters["stereo"]; ok && stereo == 1 {
"push": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, return StackUse{Inputs: [][]int{{0, 2}, {1, 3}, {2}, {3}}, Modifies: []bool{false, false, true, true}, NumOutputs: 4}
"xch": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, }
"distort": []UnitParameter{ return StackUse{Inputs: [][]int{{0, 1}, {1}}, Modifies: []bool{false, true}, NumOutputs: 2}
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, },
{Name: "drive", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true}}, },
"hold": []UnitParameter{ "addp": {
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
{Name: "holdfreq", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}}, StackUse: func(u *Unit) StackUse {
"crush": []UnitParameter{ if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, return StackUse{Inputs: [][]int{{0}, {1}, {0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2}
{Name: "resolution", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(24 * float64(v) / 128), "bits" }}}, }
"gain": []UnitParameter{ return StackUse{Inputs: [][]int{{0}, {0}}, Modifies: []bool{true}, NumOutputs: 1}
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, },
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}}, },
"invgain": []UnitParameter{ "mul": {
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
{Name: "invgain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(128/float64(v)), 'g', 3, 64), "dB" }}}, StackUse: func(unit *Unit) StackUse {
"dbgain": []UnitParameter{ if stereo, ok := unit.Parameters["stereo"]; ok && stereo == 1 {
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, return StackUse{Inputs: [][]int{{0, 2}, {1, 3}, {2}, {3}}, Modifies: []bool{false, false, true, true}, NumOutputs: 4}
{Name: "decibels", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(40 * (float64(v)/64 - 1)), "dB" }}}, }
"filter": []UnitParameter{ return StackUse{Inputs: [][]int{{0, 1}, {1}}, Modifies: []bool{false, true}, NumOutputs: 2}
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, },
{Name: "frequency", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: filterFrequencyDispFunc}, },
{Name: "resonance", MinValue: 0, Neutral: 128, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { "mulp": {
return strconv.FormatFloat(toDecibel(128/float64(v)), 'g', 3, 64), "Q dB" Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
}}, StackUse: func(u *Unit) StackUse {
{Name: "lowpass", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
{Name: "bandpass", MinValue: -1, MaxValue: 1, CanSet: true, CanModulate: false}, return StackUse{Inputs: [][]int{{0}, {1}, {0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2}
{Name: "highpass", MinValue: -1, MaxValue: 1, CanSet: true, CanModulate: false}}, }
"clip": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, return StackUse{Inputs: [][]int{{0}, {0}}, Modifies: []bool{true}, NumOutputs: 1}
"pan": []UnitParameter{ },
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, },
{Name: "panning", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true}}, "xch": {
"delay": []UnitParameter{ Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, StackUse: func(u *Unit) StackUse {
{Name: "pregain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}, if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
{Name: "dry", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}, return StackUse{Inputs: [][]int{{2}, {3}, {0}, {1}}, Modifies: []bool{false, false, false, false}, NumOutputs: 4}
{Name: "feedback", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}, }
{Name: "damp", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}, return StackUse{Inputs: [][]int{{1}, {0}}, Modifies: []bool{false, false}, NumOutputs: 2}
{Name: "notetracking", MinValue: 0, MaxValue: 2, CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc(noteTrackingNames[:])}, },
{Name: "delaytime", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true}}, },
"compressor": []UnitParameter{ "push": {
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
{Name: "attack", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: compressorTimeDispFunc}, StackUse: func(u *Unit) StackUse {
{Name: "release", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: compressorTimeDispFunc}, if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
{Name: "invgain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return StackUse{Inputs: [][]int{{0, 2}, {1, 3}}, Modifies: []bool{false, false, false, false}, NumOutputs: 4}
return strconv.FormatFloat(toDecibel(128/float64(v)), 'g', 3, 64), "dB" }
}}, return StackUse{Inputs: [][]int{{0, 1}}, Modifies: []bool{false, false}, NumOutputs: 2}
{Name: "threshold", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { },
return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" },
}}, "pop": {
{Name: "ratio", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(1 - float64(v)/128), "" }}}, Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
"speed": []UnitParameter{}, StackUse: stackUseSink,
"out": []UnitParameter{ },
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, "loadnote": {
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}}, Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
"outaux": []UnitParameter{ StackUse: stackUseSource,
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, },
{Name: "outgain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}, "distort": {
{Name: "auxgain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}}, Params: []UnitParameter{
"aux": []UnitParameter{ {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, {Name: "drive", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}, },
{Name: "channel", MinValue: 0, MaxValue: 6, CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc(channelNames[:])}}, StackUse: stackUseEffect,
"send": []UnitParameter{ },
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, "hold": {
{Name: "amount", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(float64(v)/64 - 1), "" }}, Params: []UnitParameter{
{Name: "voice", MinValue: 0, MaxValue: 32, CanSet: true, CanModulate: false, DisplayFunc: sendVoiceDispFunc}, {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "target", MinValue: 0, MaxValue: math.MaxInt32, CanSet: true, CanModulate: false}, {Name: "holdfreq", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "port", MinValue: 0, MaxValue: 7, CanSet: true, CanModulate: false}, },
{Name: "sendpop", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}}, StackUse: stackUseEffect,
"envelope": []UnitParameter{ },
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, "crush": {
{Name: "attack", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return engineeringTime(math.Pow(2, 24*float64(v)/128) / 44100) }}, Params: []UnitParameter{
{Name: "decay", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return engineeringTime(math.Pow(2, 24*float64(v)/128) / 44100) }}, {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "sustain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}, {Name: "resolution", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(24 * float64(v) / 128), "bits" }},
{Name: "release", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return engineeringTime(math.Pow(2, 24*float64(v)/128) / 44100) }}, },
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}}, StackUse: stackUseEffect,
"noise": []UnitParameter{ },
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, "gain": {
{Name: "shape", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true}, Params: []UnitParameter{
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}}, {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
"oscillator": []UnitParameter{ {Name: "gain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, },
{Name: "transpose", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: oscillatorTransposeDispFunc}, StackUse: stackUseEffect,
{Name: "detune", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(float64(v-64) / 64), "st" }}, },
{Name: "phase", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { "invgain": {
return strconv.FormatFloat(float64(v)/128*360, 'f', 1, 64), "°" Params: []UnitParameter{
}}, {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "color", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}, {Name: "invgain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(128/float64(v)), 'g', 3, 64), "dB" }},
{Name: "shape", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true}, },
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }}, StackUse: stackUseEffect,
{Name: "frequency", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true}, },
{Name: "type", MinValue: int(Sine), MaxValue: int(Sample), CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc(oscTypes[:])}, "dbgain": {
{Name: "lfo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, Params: []UnitParameter{
{Name: "unison", MinValue: 0, MaxValue: 3, CanSet: true, CanModulate: false}, {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "samplestart", MinValue: 0, MaxValue: 1720329, CanSet: true, CanModulate: false}, {Name: "decibels", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(40 * (float64(v)/64 - 1)), "dB" }},
{Name: "loopstart", MinValue: 0, MaxValue: 65535, CanSet: true, CanModulate: false}, },
{Name: "looplength", MinValue: 0, MaxValue: 65535, CanSet: true, CanModulate: false}}, StackUse: stackUseEffect,
"loadval": []UnitParameter{ },
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, "filter": {
{Name: "value", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(float64(v)/64 - 1), "" }}}, Params: []UnitParameter{
"receive": []UnitParameter{ {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, {Name: "frequency", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) {
{Name: "left", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true}, // https://www.musicdsp.org/en/latest/Filters/23-state-variable.html
{Name: "right", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true}}, // calls it cutoff" but it's actually the location of the
"in": []UnitParameter{ // resonance peak
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, freq := float64(v) / 128
{Name: "channel", MinValue: 0, MaxValue: 6, CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc(channelNames[:])}}, return strconv.FormatFloat(math.Asin(freq*freq/2)/math.Pi*44100, 'f', 0, 64), "Hz"
"sync": []UnitParameter{}, },
"belleq": []UnitParameter{ },
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, {Name: "resonance", MinValue: 0, Default: 64, Neutral: 128, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) {
{Name: "frequency", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return belleqFrequencyDisplay(v) }}, return strconv.FormatFloat(toDecibel(128/float64(v)), 'g', 3, 64), "Q dB"
{Name: "bandwidth", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return belleqBandwidthDisplay(v) }}, }},
{Name: "gain", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return belleqGainDisplay(v) }}}, {Name: "lowpass", MinValue: 0, Default: 1, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "bandpass", MinValue: -1, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "highpass", MinValue: -1, MaxValue: 1, CanSet: true, CanModulate: false},
},
StackUse: stackUseEffect,
},
"clip": {
Params: []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
StackUse: stackUseEffect,
},
"pan": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "panning", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true},
},
StackUse: func(u *Unit) StackUse {
if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
return StackUse{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2}
}
return StackUse{Inputs: [][]int{{0, 1}}, Modifies: []bool{true, true}, NumOutputs: 2}
},
},
"delay": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "pregain", MinValue: 0, Default: 40, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "dry", MinValue: 0, Default: 128, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "feedback", MinValue: 0, Default: 96, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "damp", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "notetracking", MinValue: 0, Default: 2, MaxValue: 2, CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc([]string{"fixed", "pitch", "BPM"})},
{Name: "delaytime", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true},
},
DefaultVarArgs: []int{48},
StackUse: stackUseEffect,
},
"compressor": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "attack", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: compressorTimeDispFunc},
{Name: "release", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: compressorTimeDispFunc},
{Name: "invgain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) {
return strconv.FormatFloat(toDecibel(128/float64(v)), 'g', 3, 64), "dB"
}},
{Name: "threshold", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) {
return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB"
}},
{Name: "ratio", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(1 - float64(v)/128), "" }},
},
StackUse: func(u *Unit) StackUse {
if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
return StackUse{Inputs: [][]int{{0, 2, 3}, {1, 2, 3}}, Modifies: []bool{false, false, true, true}, NumOutputs: 4}
}
return StackUse{Inputs: [][]int{{0, 1}}, Modifies: []bool{false, true}, NumOutputs: 2}
},
},
"speed": {
Params: []UnitParameter{},
StackUse: func(u *Unit) StackUse { return StackUse{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 0} },
},
"out": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, Default: 1, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "gain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
},
StackUse: stackUseSink,
},
"outaux": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, Default: 1, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "outgain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
{Name: "auxgain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
},
StackUse: stackUseSink,
},
"aux": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, Default: 1, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "gain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
{Name: "channel", MinValue: 0, Default: 2, MaxValue: 6, CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc(channelNames[:])},
},
StackUse: stackUseSink,
},
"send": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "amount", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(float64(v)/64 - 1), "" }},
{Name: "voice", MinValue: 0, MaxValue: 32, CanSet: true, CanModulate: false, DisplayFunc: func(v int) (string, string) {
if v == 0 {
return "default", ""
}
return strconv.Itoa(v), ""
}},
{Name: "target", MinValue: 0, MaxValue: math.MaxInt32, CanSet: true, CanModulate: false},
{Name: "port", MinValue: 0, MaxValue: 7, CanSet: true, CanModulate: false},
{Name: "sendpop", MinValue: 0, Default: 1, MaxValue: 1, CanSet: true, CanModulate: false},
},
StackUse: func(u *Unit) StackUse {
ret := StackUse{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 1}
if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
ret = StackUse{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2}
}
if sendpop, ok := u.Parameters["sendpop"]; ok && sendpop == 1 {
ret.NumOutputs = 0
}
return ret
},
},
"envelope": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "attack", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return engineeringTime(math.Pow(2, 24*float64(v)/128) / 44100) }},
{Name: "decay", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return engineeringTime(math.Pow(2, 24*float64(v)/128) / 44100) }},
{Name: "sustain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
{Name: "release", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return engineeringTime(math.Pow(2, 24*float64(v)/128) / 44100) }},
{Name: "gain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
},
StackUse: stackUseSource,
},
"noise": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "shape", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "gain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
},
StackUse: stackUseSource,
},
"oscillator": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "transpose", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) {
relvalue := v - 64
if relvalue%12 == 0 {
return strconv.Itoa(relvalue / 12), "oct"
}
return strconv.Itoa(relvalue), "st"
}},
{Name: "detune", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(float64(v-64) / 64), "st" }},
{Name: "phase", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) {
return strconv.FormatFloat(float64(v)/128*360, 'f', 1, 64), "°"
}},
{Name: "color", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "shape", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true},
{Name: "gain", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(toDecibel(float64(v)/128), 'g', 3, 64), "dB" }},
{Name: "frequency", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true},
{Name: "type", MinValue: int(Sine), Default: int(Sine), MaxValue: int(Sample), CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc([]string{"sine", "trisaw", "pulse", "gate", "sample"})},
{Name: "lfo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "unison", MinValue: 0, MaxValue: 3, CanSet: true, CanModulate: false},
{Name: "samplestart", MinValue: 0, MaxValue: 1720329, CanSet: true, CanModulate: false},
{Name: "loopstart", MinValue: 0, MaxValue: 65535, CanSet: true, CanModulate: false},
{Name: "looplength", MinValue: 0, MaxValue: 65535, CanSet: true, CanModulate: false},
},
StackUse: stackUseSource,
},
"loadval": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "value", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return formatFloat(float64(v)/64 - 1), "" }},
},
StackUse: stackUseSource,
},
"receive": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "left", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true},
{Name: "right", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true},
},
StackUse: stackUseSource,
},
"in": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, Default: 1, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "channel", MinValue: 0, Default: 2, MaxValue: 6, CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc(channelNames[:])},
},
StackUse: stackUseSource,
},
"sync": {
Params: []UnitParameter{},
StackUse: func(u *Unit) StackUse { return StackUse{Inputs: [][]int{{0}}, Modifies: []bool{false}, NumOutputs: 1} },
},
"belleq": {
Params: []UnitParameter{
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
{Name: "frequency", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) {
freq := float64(v) / 128
return strconv.FormatFloat(44100*2*freq*freq/math.Pi/2, 'f', 0, 64), "Hz"
}},
{Name: "bandwidth", MinValue: 0, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return strconv.FormatFloat(1/(4*float64(v)/128), 'f', 2, 64), "Q" }},
{Name: "gain", MinValue: 0, Neutral: 64, Default: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) {
return strconv.FormatFloat(40*(float64(v)/64-1), 'f', 2, 64), "dB"
}},
},
StackUse: stackUseEffect,
},
}
func stackUseSource(u *Unit) StackUse {
if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
return StackUse{Inputs: [][]int{}, Modifies: []bool{true, true}, NumOutputs: 2}
}
return StackUse{Inputs: [][]int{}, Modifies: []bool{true}, NumOutputs: 1}
}
func stackUseSink(u *Unit) StackUse {
if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
return StackUse{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 0}
}
return StackUse{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 0}
}
func stackUseEffect(u *Unit) StackUse {
if stereo, ok := u.Parameters["stereo"]; ok && stereo == 1 {
return StackUse{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2}
}
return StackUse{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 1}
} }
// compile errors if interface is not implemented. // compile errors if interface is not implemented.
@ -253,8 +474,6 @@ func (a *ParamMap) UnmarshalYAML(value *yaml.Node) error {
} }
var channelNames = [...]string{"left", "right", "aux1 left", "aux1 right", "aux2 left", "aux2 right", "aux3 left", "aux3 right"} var channelNames = [...]string{"left", "right", "aux1 left", "aux1 right", "aux2 left", "aux2 right", "aux3 left", "aux3 right"}
var noteTrackingNames = [...]string{"fixed", "pitch", "BPM"}
var oscTypes = [...]string{"sine", "trisaw", "pulse", "gate", "sample"}
func arrDispFunc(arr []string) UnitParameterDisplayFunc { func arrDispFunc(arr []string) UnitParameterDisplayFunc {
return func(v int) (string, string) { return func(v int) (string, string) {
@ -265,54 +484,12 @@ func arrDispFunc(arr []string) UnitParameterDisplayFunc {
} }
} }
func filterFrequencyDispFunc(v int) (string, string) {
// In https://www.musicdsp.org/en/latest/Filters/23-state-variable.html,
// they call it "cutoff" but it's actually the location of the resonance
// peak
freq := float64(v) / 128
p := freq * freq
f := math.Asin(p/2) / math.Pi * 44100
return strconv.FormatFloat(f, 'f', 0, 64), "Hz"
}
func belleqFrequencyDisplay(v int) (string, string) {
freq := float64(v) / 128
p := 2 * freq * freq
f := 44100 * p / math.Pi / 2
return strconv.FormatFloat(f, 'f', 0, 64), "Hz"
}
func belleqBandwidthDisplay(v int) (string, string) {
p := float64(v) / 128
Q := 1 / (4 * p)
return strconv.FormatFloat(Q, 'f', 2, 64), "Q"
}
func belleqGainDisplay(v int) (string, string) {
return strconv.FormatFloat(40*(float64(v)/64-1), 'f', 2, 64), "dB"
}
func compressorTimeDispFunc(v int) (string, string) { func compressorTimeDispFunc(v int) (string, string) {
alpha := math.Pow(2, -24*float64(v)/128) // alpha is the "smoothing factor" of first order low pass iir alpha := math.Pow(2, -24*float64(v)/128) // alpha is the "smoothing factor" of first order low pass iir
sec := -1 / (44100 * math.Log(1-alpha)) // from smoothing factor to time constant, https://en.wikipedia.org/wiki/Exponential_smoothing sec := -1 / (44100 * math.Log(1-alpha)) // from smoothing factor to time constant, https://en.wikipedia.org/wiki/Exponential_smoothing
return engineeringTime(sec) return engineeringTime(sec)
} }
func oscillatorTransposeDispFunc(v int) (string, string) {
relvalue := v - 64
if relvalue%12 == 0 {
return strconv.Itoa(relvalue / 12), "oct"
}
return strconv.Itoa(relvalue), "st"
}
func sendVoiceDispFunc(v int) (string, string) {
if v == 0 {
return "default", ""
}
return strconv.Itoa(v), ""
}
func engineeringTime(sec float64) (string, string) { func engineeringTime(sec float64) (string, string) {
if sec < 1e-3 { if sec < 1e-3 {
return fmt.Sprintf("%.2f", sec*1e6), "us" return fmt.Sprintf("%.2f", sec*1e6), "us"
@ -367,7 +544,7 @@ var Ports = make(map[string]([]string))
func init() { func init() {
for name, unitType := range UnitTypes { for name, unitType := range UnitTypes {
unitPorts := make([]string, 0) unitPorts := make([]string, 0)
for _, param := range unitType { for _, param := range unitType.Params {
if param.CanModulate { if param.CanModulate {
unitPorts = append(unitPorts, param.Name) unitPorts = append(unitPorts, param.Name)
} }
@ -376,6 +553,24 @@ func init() {
} }
} }
func MakeUnit(unitType string) Unit {
if ut, ok := UnitTypes[unitType]; ok {
ret := Unit{
Type: unitType,
Parameters: make(map[string]int),
VarArgs: make([]int, len(ut.DefaultVarArgs)),
}
copy(ret.VarArgs, ut.DefaultVarArgs)
for _, p := range ut.Params {
if p.Default > 0 {
ret.Parameters[p.Name] = p.Default
}
}
return ret
}
return Unit{Parameters: make(map[string]int)}
}
// Copy makes a deep copy of a unit. // Copy makes a deep copy of a unit.
func (u *Unit) Copy() Unit { func (u *Unit) Copy() Unit {
ret := *u ret := *u
@ -388,102 +583,14 @@ func (u *Unit) Copy() Unit {
return ret return ret
} }
var stackUseSource = [2]StackUse{
{Inputs: [][]int{}, Modifies: []bool{true}, NumOutputs: 1}, // mono
{Inputs: [][]int{}, Modifies: []bool{true, true}, NumOutputs: 2}, // stereo
}
var stackUseSink = [2]StackUse{
{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 0}, // mono
{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 0}, // stereo
}
var stackUseEffect = [2]StackUse{
{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 1}, // mono
{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2}, // stereo
}
var stackUseMonoStereo = map[string][2]StackUse{
"add": {
{Inputs: [][]int{{0, 1}, {1}}, Modifies: []bool{false, true}, NumOutputs: 2},
{Inputs: [][]int{{0, 2}, {1, 3}, {2}, {3}}, Modifies: []bool{false, false, true, true}, NumOutputs: 4},
},
"mul": {
{Inputs: [][]int{{0, 1}, {1}}, Modifies: []bool{false, true}, NumOutputs: 2},
{Inputs: [][]int{{0, 2}, {1, 3}, {2}, {3}}, Modifies: []bool{false, false, true, true}, NumOutputs: 4},
},
"addp": {
{Inputs: [][]int{{0}, {0}}, Modifies: []bool{true}, NumOutputs: 1},
{Inputs: [][]int{{0}, {1}, {0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2},
},
"mulp": {
{Inputs: [][]int{{0}, {0}}, Modifies: []bool{true}, NumOutputs: 1},
{Inputs: [][]int{{0}, {1}, {0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2},
},
"xch": {
{Inputs: [][]int{{1}, {0}}, Modifies: []bool{false, false}, NumOutputs: 2},
{Inputs: [][]int{{2}, {3}, {0}, {1}}, Modifies: []bool{false, false, false, false}, NumOutputs: 4},
},
"push": {
{Inputs: [][]int{{0, 1}}, Modifies: []bool{false, false}, NumOutputs: 2},
{Inputs: [][]int{{0, 2}, {1, 3}}, Modifies: []bool{false, false, false, false}, NumOutputs: 4},
},
"pop": stackUseSink,
"envelope": stackUseSource,
"oscillator": stackUseSource,
"noise": stackUseSource,
"loadnote": stackUseSource,
"loadval": stackUseSource,
"receive": stackUseSource,
"in": stackUseSource,
"out": stackUseSink,
"outaux": stackUseSink,
"aux": stackUseSink,
"distort": stackUseEffect,
"hold": stackUseEffect,
"crush": stackUseEffect,
"gain": stackUseEffect,
"invgain": stackUseEffect,
"dbgain": stackUseEffect,
"filter": stackUseEffect,
"clip": stackUseEffect,
"delay": stackUseEffect,
"compressor": {
{Inputs: [][]int{{0, 1}}, Modifies: []bool{false, true}, NumOutputs: 2}, // mono
{Inputs: [][]int{{0, 2, 3}, {1, 2, 3}}, Modifies: []bool{false, false, true, true}, NumOutputs: 4}, // stereo
},
"pan": {
{Inputs: [][]int{{0, 1}}, Modifies: []bool{true, true}, NumOutputs: 2}, // mono
{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2}, // mono
},
"speed": {
{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 0},
{},
},
"sync": {
{Inputs: [][]int{{0}}, Modifies: []bool{false}, NumOutputs: 1},
{},
},
"belleq": stackUseEffect,
}
var stackUseSendNoPop = [2]StackUse{
{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 1},
{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 2},
}
var stackUseSendPop = [2]StackUse{
{Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 0}, // mono
{Inputs: [][]int{{0}, {1}}, Modifies: []bool{true, true}, NumOutputs: 0}, // stereo
}
func (u *Unit) StackUse() StackUse { func (u *Unit) StackUse() StackUse {
if u.Disabled { if u.Disabled {
return StackUse{} return StackUse{}
} }
if u.Type == "send" { if ut, ok := UnitTypes[u.Type]; ok {
// "send" unit is special, it has a different stack use depending on sendpop return ut.StackUse(u)
if u.Parameters["sendpop"] == 0 {
return stackUseSendNoPop[u.Parameters["stereo"]]
}
return stackUseSendPop[u.Parameters["stereo"]]
} }
return stackUseMonoStereo[u.Type][u.Parameters["stereo"]] return StackUse{}
} }
// StackChange returns how this unit will affect the signal stack. "pop" and // StackChange returns how this unit will affect the signal stack. "pop" and
@ -638,7 +745,7 @@ func FindParamForModulationPort(unitName string, index int) (up UnitParameter, u
if !ok { if !ok {
return UnitParameter{}, 0, false return UnitParameter{}, 0, false
} }
for i, param := range unitType { for i, param := range unitType.Params {
if !param.CanModulate { if !param.CanModulate {
continue continue
} }

View File

@ -116,7 +116,7 @@ func (m *Model) deriveParams(unit *sointu.Unit, ret []Parameter) []Parameter {
return ret return ret
} }
portIndex := 0 portIndex := 0
for i, up := range unitType { for i, up := range unitType.Params {
if !up.CanSet && !up.CanModulate { if !up.CanSet && !up.CanModulate {
continue // skip parameters that cannot be set or modulated continue // skip parameters that cannot be set or modulated
} }
@ -131,7 +131,7 @@ func (m *Model) deriveParams(unit *sointu.Unit, ret []Parameter) []Parameter {
portIndex++ portIndex++
q = portIndex q = portIndex
} }
ret = append(ret, Parameter{m: m, unit: unit, up: &unitType[i], vtable: &namedParameter{}, port: q}) ret = append(ret, Parameter{m: m, unit: unit, up: &unitType.Params[i], vtable: &namedParameter{}, port: q})
} }
if unit.Type == "oscillator" && unit.Parameters["type"] == sointu.Sample { if unit.Type == "oscillator" && unit.Parameters["type"] == sointu.Sample {
ret = append(ret, Parameter{m: m, unit: unit, vtable: &gmDlsEntryParameter{}}) ret = append(ret, Parameter{m: m, unit: unit, vtable: &gmDlsEntryParameter{}})

View File

@ -512,7 +512,7 @@ var validParameters = map[string](map[string]bool){}
func init() { func init() {
for name, unitType := range sointu.UnitTypes { for name, unitType := range sointu.UnitTypes {
validParameters[name] = map[string]bool{} validParameters[name] = map[string]bool{}
for _, param := range unitType { for _, param := range unitType.Params {
validParameters[name][param.Name] = true validParameters[name][param.Name] = true
} }
} }

View File

@ -409,12 +409,8 @@ func (n *namedParameter) RoundToGrid(p *Parameter, val int, up bool) int {
return roundToGrid(val, 8, up) return roundToGrid(val, 8, up)
} }
func (n *namedParameter) Reset(p *Parameter) { func (n *namedParameter) Reset(p *Parameter) {
v, ok := defaultUnits[p.unit.Type].Parameters[p.up.Name]
if !ok || p.unit.Parameters[p.up.Name] == v {
return
}
defer p.m.change("Reset"+p.Name(), PatchChange, MinorChange)() defer p.m.change("Reset"+p.Name(), PatchChange, MinorChange)()
p.unit.Parameters[p.up.Name] = v p.unit.Parameters[p.up.Name] = p.up.Default
} }
// GmDlsEntry is a single sample entry from the gm.dls file // GmDlsEntry is a single sample entry from the gm.dls file

View File

@ -21,9 +21,6 @@ units:
- type: envelope - type: envelope
id: 1284 id: 1284
parameters: {attack: 53, decay: 68, gain: 98, release: 0, stereo: 0, sustain: 0} parameters: {attack: 53, decay: 68, gain: 98, release: 0, stereo: 0, sustain: 0}
- type: send
id: 1348
parameters: {amount: 26, port: 0, sendpop: 0, stereo: 0, target: 184, voice: 0}
- type: oscillator - type: oscillator
id: 1285 id: 1285
parameters: {color: 128, detune: 64, gain: 64, lfo: 0, phase: 0, shape: 64, stereo: 0, transpose: 80, type: 0, unison: 3} parameters: {color: 128, detune: 64, gain: 64, lfo: 0, phase: 0, shape: 64, stereo: 0, transpose: 80, type: 0, unison: 3}

View File

@ -63,17 +63,3 @@ units:
- type: outaux - type: outaux
id: 1681 id: 1681
parameters: {auxgain: 1, outgain: 128, stereo: 1} parameters: {auxgain: 1, outgain: 128, stereo: 1}
- id: 1773
parameters: {}
comment: SideChains
- type: envelope
id: 1769
parameters: {attack: 57, decay: 75, gain: 128, release: 0, stereo: 0, sustain: 0}
- type: send
id: 1727
parameters: {amount: 21, port: 0, sendpop: 0, stereo: 0, target: 1726, voice: 0}
- type: send
id: 1728
parameters: {amount: 20, port: 0, sendpop: 1, stereo: 0, target: 1713, voice: 0}
- id: 1682
parameters: {}

View File

@ -154,53 +154,16 @@ func (m *SongModel) reset() {
m.d.ChangedSinceSave = false m.d.ChangedSinceSave = false
} }
var defaultUnits = map[string]sointu.Unit{
"envelope": {Type: "envelope", Parameters: map[string]int{"stereo": 0, "attack": 64, "decay": 64, "sustain": 64, "release": 64, "gain": 64}},
"oscillator": {Type: "oscillator", Parameters: map[string]int{"stereo": 0, "transpose": 64, "detune": 64, "phase": 0, "color": 64, "shape": 64, "gain": 64, "type": sointu.Sine}},
"noise": {Type: "noise", Parameters: map[string]int{"stereo": 0, "shape": 64, "gain": 64}},
"mulp": {Type: "mulp", Parameters: map[string]int{"stereo": 0}},
"mul": {Type: "mul", Parameters: map[string]int{"stereo": 0}},
"add": {Type: "add", Parameters: map[string]int{"stereo": 0}},
"addp": {Type: "addp", Parameters: map[string]int{"stereo": 0}},
"push": {Type: "push", Parameters: map[string]int{"stereo": 0}},
"pop": {Type: "pop", Parameters: map[string]int{"stereo": 0}},
"xch": {Type: "xch", Parameters: map[string]int{"stereo": 0}},
"receive": {Type: "receive", Parameters: map[string]int{"stereo": 0}},
"loadnote": {Type: "loadnote", Parameters: map[string]int{"stereo": 0}},
"loadval": {Type: "loadval", Parameters: map[string]int{"stereo": 0, "value": 64}},
"pan": {Type: "pan", Parameters: map[string]int{"stereo": 0, "panning": 64}},
"gain": {Type: "gain", Parameters: map[string]int{"stereo": 0, "gain": 64}},
"invgain": {Type: "invgain", Parameters: map[string]int{"stereo": 0, "invgain": 64}},
"dbgain": {Type: "dbgain", Parameters: map[string]int{"stereo": 0, "decibels": 64}},
"crush": {Type: "crush", Parameters: map[string]int{"stereo": 0, "resolution": 64}},
"clip": {Type: "clip", Parameters: map[string]int{"stereo": 0}},
"hold": {Type: "hold", Parameters: map[string]int{"stereo": 0, "holdfreq": 64}},
"distort": {Type: "distort", Parameters: map[string]int{"stereo": 0, "drive": 64}},
"filter": {Type: "filter", Parameters: map[string]int{"stereo": 0, "frequency": 64, "resonance": 64, "lowpass": 1, "bandpass": 0, "highpass": 0}},
"out": {Type: "out", Parameters: map[string]int{"stereo": 1, "gain": 64}},
"outaux": {Type: "outaux", Parameters: map[string]int{"stereo": 1, "outgain": 64, "auxgain": 64}},
"aux": {Type: "aux", Parameters: map[string]int{"stereo": 1, "gain": 64, "channel": 2}},
"delay": {Type: "delay",
Parameters: map[string]int{"damp": 0, "dry": 128, "feedback": 96, "notetracking": 2, "pregain": 40, "stereo": 0},
VarArgs: []int{48}},
"in": {Type: "in", Parameters: map[string]int{"stereo": 1, "channel": 2}},
"speed": {Type: "speed", Parameters: map[string]int{}},
"compressor": {Type: "compressor", Parameters: map[string]int{"stereo": 0, "attack": 64, "release": 64, "invgain": 64, "threshold": 64, "ratio": 64}},
"send": {Type: "send", Parameters: map[string]int{"stereo": 0, "amount": 64, "voice": 0, "unit": 0, "port": 0, "sendpop": 1}},
"sync": {Type: "sync", Parameters: map[string]int{}},
"belleq": {Type: "belleq", Parameters: map[string]int{"stereo": 0, "frequency": 64, "bandwidth": 64, "gain": 64}},
}
var defaultInstrument = sointu.Instrument{ var defaultInstrument = sointu.Instrument{
Name: "Instr", Name: "Instr",
NumVoices: 1, NumVoices: 1,
Units: []sointu.Unit{ Units: []sointu.Unit{
defaultUnits["envelope"], sointu.MakeUnit("envelope"),
defaultUnits["oscillator"], sointu.MakeUnit("oscillator"),
defaultUnits["mulp"], sointu.MakeUnit("mulp"),
defaultUnits["delay"], sointu.MakeUnit("delay"),
defaultUnits["pan"], sointu.MakeUnit("pan"),
defaultUnits["outaux"], sointu.MakeUnit("outaux"),
}, },
} }
@ -216,7 +179,7 @@ var defaultSong = sointu.Song{
}, },
Patch: sointu.Patch{defaultInstrument, Patch: sointu.Patch{defaultInstrument,
{Name: "Global", NumVoices: 1, Units: []sointu.Unit{ {Name: "Global", NumVoices: 1, Units: []sointu.Unit{
defaultUnits["in"], sointu.MakeUnit("in"),
{Type: "delay", {Type: "delay",
Parameters: map[string]int{"damp": 64, "dry": 128, "feedback": 125, "notetracking": 0, "pregain": 40, "stereo": 1}, Parameters: map[string]int{"damp": 64, "dry": 128, "feedback": 125, "notetracking": 0, "pregain": 40, "stereo": 1},
VarArgs: []int{1116, 1188, 1276, 1356, 1422, 1492, 1556, 1618, VarArgs: []int{1116, 1188, 1276, 1356, 1422, 1492, 1556, 1618,

View File

@ -270,12 +270,7 @@ func (m *UnitModel) SetType(t string) {
for len(m.d.Song.Patch[m.d.InstrIndex].Units) <= m.d.UnitIndex { for len(m.d.Song.Patch[m.d.InstrIndex].Units) <= m.d.UnitIndex {
m.d.Song.Patch[m.d.InstrIndex].Units = append(m.d.Song.Patch[m.d.InstrIndex].Units, sointu.Unit{}) m.d.Song.Patch[m.d.InstrIndex].Units = append(m.d.Song.Patch[m.d.InstrIndex].Units, sointu.Unit{})
} }
unit, ok := defaultUnits[t] unit := sointu.MakeUnit(t)
if !ok { // if the type is invalid, we just set it to empty unit
unit = sointu.Unit{Parameters: make(map[string]int)}
} else {
unit = unit.Copy()
}
oldUnit := m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex] oldUnit := m.d.Song.Patch[m.d.InstrIndex].Units[m.d.UnitIndex]
if oldUnit.Type == unit.Type { if oldUnit.Type == unit.Type {
return return

View File

@ -262,7 +262,7 @@ func (b *bytecodeBuilder) operand(operands ...int) {
// defOperands appends the operands to the stream for all parameters that can be // defOperands appends the operands to the stream for all parameters that can be
// modulated and set // modulated and set
func (b *bytecodeBuilder) defOperands(unit sointu.Unit) { func (b *bytecodeBuilder) defOperands(unit sointu.Unit) {
for _, v := range sointu.UnitTypes[unit.Type] { for _, v := range sointu.UnitTypes[unit.Type].Params {
if v.CanModulate && v.CanSet { if v.CanModulate && v.CanSet {
b.Operands = append(b.Operands, byte(unit.Parameters[v.Name])) b.Operands = append(b.Operands, byte(unit.Parameters[v.Name]))
} }

View File

@ -58,7 +58,7 @@ func init() {
for k, v := range sointu.UnitTypes { for k, v := range sointu.UnitTypes {
inputCount := 0 inputCount := 0
transformCount := 0 transformCount := 0
for _, t := range v { for _, t := range v.Params {
if t.CanModulate { if t.CanModulate {
allInputs[paramKey{k, t.Name}] = inputCount allInputs[paramKey{k, t.Name}] = inputCount
inputCount++ inputCount++
@ -125,7 +125,7 @@ func NecessaryFeaturesFor(patch sointu.Patch) NecessaryFeatures {
features.instructions = append(features.instructions, unit.Type) features.instructions = append(features.instructions, unit.Type)
features.opcodes[unit.Type] = len(features.instructions) * 2 // note that the first opcode gets value 1, as 0 is always reserved for advance features.opcodes[unit.Type] = len(features.instructions) * 2 // note that the first opcode gets value 1, as 0 is always reserved for advance
} }
for _, paramType := range sointu.UnitTypes[unit.Type] { for _, paramType := range sointu.UnitTypes[unit.Type].Params {
v := unit.Parameters[paramType.Name] v := unit.Parameters[paramType.Name]
key := paramKey{unit.Type, paramType.Name} key := paramKey{unit.Type, paramType.Name}
if features.supportsParamValue[key] == nil { if features.supportsParamValue[key] == nil {