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 <noreply@anthropic.com>
This commit is contained in:
Aqua 2026-10-31 20:36:47 +00:00
commit aa45571b3a

View file

@ -840,16 +840,32 @@ internal sealed class FaustNativeToolchain : IDisposable
public void SetControls(IntPtr dsp, IReadOnlyDictionary<string, float> controls, IReadOnlyDictionary<string, IntPtr> 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<string, float> 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<string, IntPtr> 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()