NEON vectorized fi32->s16l audio filter
authorRémi Denis-Courmont <remi@remlab.net>
Sat, 5 Sep 2009 19:12:36 +0000 (22:12 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Sun, 6 Sep 2009 10:55:45 +0000 (13:55 +0300)
This conversion is always needed between mixer and output.

modules/audio_filter/converter/neon.c

index 45a2a62..3b41e2c 100644 (file)
@@ -37,6 +37,8 @@ vlc_module_end ()
 
 static void Do_F32_S32 (aout_instance_t *, aout_filter_t *,
                         aout_buffer_t *, aout_buffer_t *);
 
 static void Do_F32_S32 (aout_instance_t *, aout_filter_t *,
                         aout_buffer_t *, aout_buffer_t *);
+static void Do_S32_S16 (aout_instance_t *, aout_filter_t *,
+                        aout_buffer_t *, aout_buffer_t *);
 
 static int Open (vlc_object_t *obj)
 {
 
 static int Open (vlc_object_t *obj)
 {
@@ -47,15 +49,32 @@ static int Open (vlc_object_t *obj)
     if (!AOUT_FMTS_SIMILAR (&filter->input, &filter->output))
         return VLC_EGENERIC;
 
     if (!AOUT_FMTS_SIMILAR (&filter->input, &filter->output))
         return VLC_EGENERIC;
 
-    if (filter->input.i_format == VLC_CODEC_FL32)
+    switch (filter->input.i_format)
     {
     {
-        if (filter->output.i_format == VLC_CODEC_FI32)
-            filter->pf_do_work = Do_F32_S32;
-        else
+        case VLC_CODEC_FL32:
+            switch (filter->output.i_format)
+            {
+                case VLC_CODEC_FI32:
+                    filter->pf_do_work = Do_F32_S32;
+                    break;
+                default:
+                    return VLC_EGENERIC;
+            }
+            break;
+
+        case VLC_CODEC_FI32:
+            switch (filter->output.i_format)
+            {
+                case VLC_CODEC_S16N:
+                    filter->pf_do_work = Do_S32_S16;
+                    break;
+                default:
+                    return VLC_EGENERIC;
+            }
+            break;
+        default:
             return VLC_EGENERIC;
     }
             return VLC_EGENERIC;
     }
-    else
-        return VLC_EGENERIC;
 
     filter->b_in_place = true;
     return 0;
 
     filter->b_in_place = true;
     return 0;
@@ -118,3 +137,53 @@ static void Do_F32_S32 (aout_instance_t *aout, aout_filter_t *filter,
     outbuf->i_nb_bytes = inbuf->i_nb_bytes;
     (void) aout;
 }
     outbuf->i_nb_bytes = inbuf->i_nb_bytes;
     (void) aout;
 }
+
+/**
+ * Signed 32-bits fixed point to signed 16-bits integer
+ */
+static void Do_S32_S16 (aout_instance_t *aout, aout_filter_t *filter,
+                        aout_buffer_t *inbuf, aout_buffer_t *outbuf)
+{
+    unsigned nb_samples = inbuf->i_nb_samples
+                     * aout_FormatNbChannels (&filter->input);
+    int32_t *inp = (int32_t *)inbuf->p_buffer;
+    const int32_t *endp = inp + nb_samples;
+    int16_t *outp = (int16_t *)outbuf->p_buffer;
+
+    while (nb_samples & 3)
+    {
+        const int16_t roundup = 1 << 12;
+        asm volatile (
+            "qadd r0, %[inv], %[roundup]\n"
+            "ssat %[outv], #16, r0, asr #13\n"
+            : [outv] "=r" (*outp)
+            : [inv] "r" (*inp), [roundup] "r" (roundup)
+            : "r0");
+        inp++;
+        outp++;
+        nb_samples--;
+    }
+
+    if (nb_samples & 4)
+        asm volatile (
+            "vld1.s32 {q0}, [%[inp]]!\n"
+            "vrshrn.i32 d0, q0, #13\n"
+            "vst1.s16 {d0}, [%[outp]]!\n"
+            : [outp] "+r" (outp), [inp] "+r" (inp)
+            :
+            : "q0", "memory");
+
+    while (inp != endp)
+        asm volatile (
+            "vld1.s32 {q0-q1}, [%[inp]]!\n"
+            "vrshrn.s32 d0, q0, #13\n"
+            "vrshrn.s32 d1, q1, #13\n"
+            "vst1.s16 {q0}, [%[outp]]!\n"
+            : [outp] "+r" (outp), [inp] "+r" (inp)
+            :
+            : "q0", "q1", "memory");
+
+    outbuf->i_nb_samples = inbuf->i_nb_samples;
+    outbuf->i_nb_bytes = inbuf->i_nb_bytes / 2;
+    (void) aout;
+}