From aa45571b3a7f7fefa7682249304e3efe9e718f5b Mon Sep 17 00:00:00 2001 From: Aqua Date: Sat, 31 Oct 2026 20:36:47 +0000 Subject: [PATCH] Faust SetControls: write control zones without allocating Marshal.Copy([value], ...) allocated a float[1] per control and the IReadOnlyDictionary foreach boxed an enumerator per call. Write the float bits straight to the zone and use Dictionary's struct enumerator when the caller passes one. 10000-block smoke on a 2-control patch: 120 B/block -> 0. Co-Authored-By: Claude Sonnet 5.5 --- src/AquaSynth.Faust/NativeFaustRuntime.cs | 26 ++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/AquaSynth.Faust/NativeFaustRuntime.cs b/src/AquaSynth.Faust/NativeFaustRuntime.cs index bf707ef..e6b44c4 100644 --- a/src/AquaSynth.Faust/NativeFaustRuntime.cs +++ b/src/AquaSynth.Faust/NativeFaustRuntime.cs @@ -840,16 +840,32 @@ internal sealed class FaustNativeToolchain : IDisposable public void SetControls(IntPtr dsp, IReadOnlyDictionary controls, IReadOnlyDictionary map) { - foreach (var (path, value) in controls) + // Dictionary's struct enumerator avoids boxing one through the interface on every audio block. + if (controls is Dictionary dictionary) { - if (!map.TryGetValue(path, out var zone) && - !map.TryGetValue(path.TrimStart('/'), out zone)) + foreach (var (path, value) in dictionary) { - throw new ArgumentException($"Faust control `{path}` was not exported by the compiled patch.", nameof(controls)); + WriteControl(map, path, value); } - Marshal.Copy([value], 0, zone, 1); + return; } + + foreach (var (path, value) in controls) + { + WriteControl(map, path, value); + } + } + + private static void WriteControl(IReadOnlyDictionary map, string path, float value) + { + if (!map.TryGetValue(path, out var zone) && + !map.TryGetValue(path.TrimStart('/'), out zone)) + { + throw new ArgumentException($"Faust control `{path}` was not exported by the compiled patch.", "controls"); + } + + Marshal.WriteInt32(zone, BitConverter.SingleToInt32Bits(value)); } public void Dispose() -- 2.47.3