133 lines
2.8 KiB
Go
133 lines
2.8 KiB
Go
package synthetic
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/uopi/uopi/internal/dsp"
|
|
)
|
|
|
|
// floatParam extracts a float64 from params; returns 0 if missing or wrong type.
|
|
func floatParam(params map[string]any, key string) float64 {
|
|
if params == nil {
|
|
return 0
|
|
}
|
|
v, ok := params[key]
|
|
if !ok {
|
|
return 0
|
|
}
|
|
f, ok := v.(float64)
|
|
if !ok {
|
|
return 0
|
|
}
|
|
return f
|
|
}
|
|
|
|
// stringParam extracts a string from params; returns "" if missing or wrong type.
|
|
func stringParam(params map[string]any, key string) string {
|
|
if params == nil {
|
|
return ""
|
|
}
|
|
v, ok := params[key]
|
|
if !ok {
|
|
return ""
|
|
}
|
|
s, ok := v.(string)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
return s
|
|
}
|
|
|
|
// stringSliceParam extracts a []string from params; JSON arrays decode to []any,
|
|
// so each element is coerced via its string value. Returns nil if missing.
|
|
func stringSliceParam(params map[string]any, key string) []string {
|
|
if params == nil {
|
|
return nil
|
|
}
|
|
v, ok := params[key]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
arr, ok := v.([]any)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
out := make([]string, 0, len(arr))
|
|
for _, e := range arr {
|
|
if s, ok := e.(string); ok && s != "" {
|
|
out = append(out, s)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// buildNode converts a single NodeDef (from JSON) into a dsp.Node ready for
|
|
// execution. JSON numbers are float64, so all numeric params are handled as
|
|
// float64 regardless of the final type needed.
|
|
func buildNode(d NodeDef) (dsp.Node, error) {
|
|
p := d.Params
|
|
switch d.Type {
|
|
case "gain":
|
|
return &dsp.GainNode{Gain: floatParam(p, "gain")}, nil
|
|
|
|
case "offset":
|
|
return &dsp.OffsetNode{Offset: floatParam(p, "offset")}, nil
|
|
|
|
case "add":
|
|
return &dsp.AddNode{}, nil
|
|
|
|
case "subtract":
|
|
return &dsp.SubtractNode{}, nil
|
|
|
|
case "multiply":
|
|
return &dsp.MultiplyNode{}, nil
|
|
|
|
case "divide":
|
|
return &dsp.DivideNode{}, nil
|
|
|
|
case "moving_average":
|
|
return &dsp.MovingAverageNode{Window: max(1, int(floatParam(p, "window")))}, nil
|
|
|
|
case "rms":
|
|
return &dsp.RMSNode{Window: max(1, int(floatParam(p, "window")))}, nil
|
|
|
|
case "derivative":
|
|
return &dsp.DerivativeNode{}, nil
|
|
|
|
case "integrate":
|
|
return &dsp.IntegrateNode{}, nil
|
|
|
|
case "clamp":
|
|
return &dsp.ClampNode{
|
|
Min: floatParam(p, "min"),
|
|
Max: floatParam(p, "max"),
|
|
}, nil
|
|
|
|
case "threshold":
|
|
return &dsp.ThresholdNode{
|
|
Threshold: floatParam(p, "threshold"),
|
|
High: floatParam(p, "high"),
|
|
Low: floatParam(p, "low"),
|
|
}, nil
|
|
|
|
case "expr":
|
|
return &dsp.ExprNode{Expr: stringParam(p, "expr"), Vars: stringSliceParam(p, "vars")}, nil
|
|
|
|
case "lowpass":
|
|
order := int(floatParam(p, "order"))
|
|
if order < 1 {
|
|
order = 1
|
|
}
|
|
return &dsp.LowPassNode{
|
|
Freq: floatParam(p, "freq"),
|
|
Order: order,
|
|
}, nil
|
|
|
|
case "lua":
|
|
return &dsp.LuaNode{Script: stringParam(p, "script"), Vars: stringSliceParam(p, "vars")}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unknown node type %q", d.Type)
|
|
}
|
|
}
|