audio_utils primitives: Add float clamping memcopy

For security reason, float buffers provided by application must be
clamped to FLOAT_NOMINAL_RANGE_HEADROOM.
With the new all float pipeline, float are no longer clamped by their
conversion to fixed point.

This patch adds a function to efficiently clamp a buffer during a
memcopy.

Test: adb shell /system/bin/primitives_benchmark
Test: adb shell /data/nativetest/primitives_tests/primitives_tests --gtest_filter=*Clamping*
Bug: 68099072
Change-Id: I030b247ea29cb94c62d1206c31960f45da2446e6
Signed-off-by: Kevin Rocard <krocard@google.com>
diff --git a/audio_utils/primitives.c b/audio_utils/primitives.c
index 9a4cc3b..77d4f34 100644
--- a/audio_utils/primitives.c
+++ b/audio_utils/primitives.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <math.h>
 #include <cutils/bitops.h>  /* for popcount() */
 #include <audio_utils/primitives.h>
 #include "private/private.h"
@@ -256,6 +257,18 @@
     }
 }
 
+void memcpy_to_float_from_float_with_clamping(float *dst, const float *src, size_t count,
+                                              float absMax) {
+    // Note: using NEON intrinsics (vminq_f32, vld1q_f32...) did NOT accelerate
+    // the function when benchmarked. The compiler already vectorize using FMINNM f32x4 & similar.
+    // Note: clamping induce a ~20% overhead compared to memcpy for count in [64, 512]
+    //       See primitives_benchmark
+    while (count--) {
+        const float sample = *src++;
+        *dst++ = fmax(-absMax, fmin(absMax, sample));
+    }
+}
+
 void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count)
 {
     while (count--) {