From d09e978ca598ebe08b754c49a14136d2ed7e89c3 Mon Sep 17 00:00:00 2001 From: sp80808 <211996837+sp80808@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:09:50 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Hoist=20'pow'=20and=20arra?= =?UTF-8?q?y=20lookups=20out=20of=20inner=20DSP=20loops?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What: The unisonDetunes and stringDetunes iterations generated multiple expensive 'pow' calls per-frame inside a DSP loop. We move the iteration and pow calls outside the audio loop (per-block). Why: pow(x) is an expensive math operation, especially inside an audio rendering loop running at the sample rate (e.g. 44100 times per sec per voice). Measured Improvement: Could not benchmark directly as swift wasn't in PATH. However, skipping 11 pow allocations and variable computations inside a 4096-frame chunk will measurably reduce DSP load significantly for the unison/string oscillators. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- Sources/XPadAudio/AudioEngine.swift | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Sources/XPadAudio/AudioEngine.swift b/Sources/XPadAudio/AudioEngine.swift index 820642a..e2b6b41 100644 --- a/Sources/XPadAudio/AudioEngine.swift +++ b/Sources/XPadAudio/AudioEngine.swift @@ -1168,6 +1168,21 @@ public final class SynthVoice: @unchecked Sendable { var reachedReleaseEnd = false + // Precalculate unison and string increments outside the frame loop + let unisonDetunes: [Double] = [-0.35, -0.22, -0.10, 0.0, 0.10, 0.22, 0.35] + var unisonIncrements = [Double](repeating: 0.0, count: 7) + for vi in 0..<7 { + let df = frequency * (pow(2.0, unisonDetunes[vi] / 12.0) - 1.0) + unisonIncrements[vi] = min((frequency + df) / sampleRate, 0.49) + } + + let stringDetunes: [Double] = [-0.08, -0.025, 0.025, 0.08] + var stringIncrements = [Double](repeating: 0.0, count: 4) + for vi in 0..<4 { + let df = frequency * (pow(2.0, stringDetunes[vi] / 12.0) - 1.0) + stringIncrements[vi] = min((frequency + df) / sampleRate, 0.49) + } + for frame in 0..