109 lines
2.3 KiB
Go
109 lines
2.3 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
|
|
}
|
|
|
|
// BuildPipeline converts a []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 BuildPipeline(defs []NodeDef) ([]dsp.Node, error) {
|
|
nodes := make([]dsp.Node, 0, len(defs))
|
|
for i, d := range defs {
|
|
n, err := buildNode(d)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("pipeline node %d (%q): %w", i, d.Type, err)
|
|
}
|
|
nodes = append(nodes, n)
|
|
}
|
|
return nodes, nil
|
|
}
|
|
|
|
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 "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")}, nil
|
|
|
|
case "lua":
|
|
return &dsp.LuaNode{Script: stringParam(p, "script")}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unknown node type %q", d.Type)
|
|
}
|
|
}
|