From 1d94de5358a44e08d9c1a07ab76df0b85d029ab7 Mon Sep 17 00:00:00 2001
From: Nebuleon <2391500+Nebuleon@users.noreply.github.com>
Date: Sun, 24 Sep 2023 22:26:02 -0400
Subject: [PATCH] Optimize the additive DAC code, fixing performance-related
 hangs (#21662)

---
 platforms/chibios/drivers/audio_dac_additive.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/platforms/chibios/drivers/audio_dac_additive.c b/platforms/chibios/drivers/audio_dac_additive.c
index 22e4fa2608..7bb5cfffb5 100644
--- a/platforms/chibios/drivers/audio_dac_additive.c
+++ b/platforms/chibios/drivers/audio_dac_additive.c
@@ -121,24 +121,27 @@ __attribute__((weak)) uint16_t dac_value_generate(void) {
     /* doing additive wave synthesis over all currently playing tones = adding up
      * sine-wave-samples for each frequency, scaled by the number of active tones
      */
-    uint16_t value     = 0;
-    float    frequency = 0.0f;
+    uint_fast16_t value     = 0;
+    float         frequency = 0.0f;
 
-    for (uint8_t i = 0; i < active_tones_snapshot_length; i++) {
+    for (size_t i = 0; i < active_tones_snapshot_length; i++) {
         /* Note: a user implementation does not have to rely on the active_tones_snapshot, but
          * could directly query the active frequencies through audio_get_processed_frequency */
         frequency = active_tones_snapshot[i];
 
-        dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3;
+        float new_dac_if = dac_if[i];
+        new_dac_if += frequency * ((float)AUDIO_DAC_BUFFER_SIZE / AUDIO_DAC_SAMPLE_RATE * 2.0f / 3.0f);
         /*Note: the 2/3 are necessary to get the correct frequencies on the
          *      DAC output (as measured with an oscilloscope), since the gpt
          *      timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback
          *      is called twice per conversion.*/
 
-        dac_if[i] = fmodf(dac_if[i], AUDIO_DAC_BUFFER_SIZE);
+        while (new_dac_if >= AUDIO_DAC_BUFFER_SIZE)
+            new_dac_if -= AUDIO_DAC_BUFFER_SIZE;
+        dac_if[i] = new_dac_if;
 
         // Wavetable generation/lookup
-        uint16_t dac_i = (uint16_t)dac_if[i];
+        size_t dac_i = (size_t)new_dac_if;
 
 #if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE)
         value += dac_buffer_sine[dac_i] / active_tones_snapshot_length;