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) 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) && foreach (var (path, value) in dictionary)
!map.TryGetValue(path.TrimStart('/'), out zone))
{ {
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() public void Dispose()