Files
uopi/internal/datasource/synthetic/dsp_bridge.go
T
2026-06-20 14:28:28 +02:00

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)
}
}