]> git.sesse.net Git - vlc/blob - modules/audio_filter/converter/neon.c
aout_filter_t.(in|out)put -> aout_filter_t.fmt_(in|out).audio
[vlc] / modules / audio_filter / converter / neon.c
1 /*****************************************************************************
2  * arm_neon.c: NEON assembly optimized audio conversions
3  *****************************************************************************
4  * Copyright (C) 2009 RĂ©mi Denis-Courmont
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <vlc_common.h>
26 #include <vlc_plugin.h>
27 #include <vlc_aout.h>
28 #include <vlc_cpu.h>
29
30 static int Open (vlc_object_t *);
31
32 vlc_module_begin ()
33     set_description (N_("ARM NEON audio format conversions") )
34     set_capability ("audio filter", 20)
35     set_callbacks (Open, NULL)
36     add_requirement (NEON)
37 vlc_module_end ()
38
39 static void Do_F32_S32 (aout_instance_t *, aout_filter_t *,
40                         aout_buffer_t *, aout_buffer_t *);
41 static void Do_S32_S16 (aout_instance_t *, aout_filter_t *,
42                         aout_buffer_t *, aout_buffer_t *);
43
44 static int Open (vlc_object_t *obj)
45 {
46     aout_filter_t *filter = (aout_filter_t *)obj;
47
48     if (!AOUT_FMTS_SIMILAR (&filter->fmt_in.audio, &filter->fmt_out.audio))
49         return VLC_EGENERIC;
50
51     switch (filter->fmt_in.audio.i_format)
52     {
53         case VLC_CODEC_FL32:
54             switch (filter->fmt_out.audio.i_format)
55             {
56                 case VLC_CODEC_FI32:
57                     filter->pf_do_work = Do_F32_S32;
58                     break;
59                 default:
60                     return VLC_EGENERIC;
61             }
62             break;
63
64         case VLC_CODEC_FI32:
65             switch (filter->fmt_out.audio.i_format)
66             {
67                 case VLC_CODEC_S16N:
68                     filter->pf_do_work = Do_S32_S16;
69                     break;
70                 default:
71                     return VLC_EGENERIC;
72             }
73             break;
74         default:
75             return VLC_EGENERIC;
76     }
77
78     filter->b_in_place = true;
79     return 0;
80 }
81
82 /**
83  * Half-precision floating point to signed fixed point conversion.
84  */
85 static void Do_F32_S32 (aout_instance_t *aout, aout_filter_t *filter,
86                         aout_buffer_t *inbuf, aout_buffer_t *outbuf)
87 {
88     unsigned nb_samples = inbuf->i_nb_samples
89                      * aout_FormatNbChannels (&filter->fmt_in.audio);
90     const float *inp = (float *)inbuf->p_buffer;
91     const float *endp = inp + nb_samples;
92     int32_t *outp = (int32_t *)outbuf->p_buffer;
93
94     if (nb_samples & 1)
95     {
96         asm volatile (
97             "vldr.32 s0, [%[inp]]\n"
98             "vcvt.s32.f32 d0, d0, #28\n"
99             "vstr.32 s0, [%[outp]]\n"
100             :
101             : [outp] "r" (outp), [inp] "r" (inp)
102             : "d0", "memory");
103         outp++;
104         inp++;
105     }
106
107     if (nb_samples & 2)
108         asm volatile (
109             "vld1.f32 {d0}, [%[inp]]!\n"
110             "vcvt.s32.f32 d0, d0, #28\n"
111             "vst1.s32 {d0}, [%[outp]]!\n"
112             : [outp] "+r" (outp), [inp] "+r" (inp)
113             :
114             : "d0", "memory");
115
116     if (nb_samples & 4)
117         asm volatile (
118             "vld1.f32 {q0}, [%[inp]]!\n"
119             "vcvt.s32.f32 q0, q0, #28\n"
120             "vst1.s32 {q0}, [%[outp]]!\n"
121             : [outp] "+r" (outp), [inp] "+r" (inp)
122             :
123             : "q0", "memory");
124
125     while (inp != endp)
126         asm volatile (
127             "vld1.f32 {q0-q1}, [%[inp]]!\n"
128             "vcvt.s32.f32 q0, q0, #28\n"
129             "vcvt.s32.f32 q1, q1, #28\n"
130             "vst1.s32 {q0-q1}, [%[outp]]!\n"
131             : [outp] "+r" (outp), [inp] "+r" (inp)
132             :
133             : "q0", "q1", "memory");
134
135     outbuf->i_nb_samples = inbuf->i_nb_samples;
136     outbuf->i_buffer = inbuf->i_buffer;
137     (void) aout;
138 }
139
140 /**
141  * Signed 32-bits fixed point to signed 16-bits integer
142  */
143 static void Do_S32_S16 (aout_instance_t *aout, aout_filter_t *filter,
144                         aout_buffer_t *inbuf, aout_buffer_t *outbuf)
145 {
146     unsigned nb_samples = inbuf->i_nb_samples
147                      * aout_FormatNbChannels (&filter->fmt_in.audio);
148     int32_t *inp = (int32_t *)inbuf->p_buffer;
149     const int32_t *endp = inp + nb_samples;
150     int16_t *outp = (int16_t *)outbuf->p_buffer;
151
152     while (nb_samples & 3)
153     {
154         const int16_t roundup = 1 << 12;
155         asm volatile (
156             "qadd r0, %[inv], %[roundup]\n"
157             "ssat %[outv], #16, r0, asr #13\n"
158             : [outv] "=r" (*outp)
159             : [inv] "r" (*inp), [roundup] "r" (roundup)
160             : "r0");
161         inp++;
162         outp++;
163         nb_samples--;
164     }
165
166     if (nb_samples & 4)
167         asm volatile (
168             "vld1.s32 {q0}, [%[inp]]!\n"
169             "vrshrn.i32 d0, q0, #13\n"
170             "vst1.s16 {d0}, [%[outp]]!\n"
171             : [outp] "+r" (outp), [inp] "+r" (inp)
172             :
173             : "q0", "memory");
174
175     if (nb_samples & 8)
176         asm volatile (
177             "vld1.s32 {q0-q1}, [%[inp]]!\n"
178             "vrshrn.i32 d0, q0, #13\n"
179             "vrshrn.i32 d1, q1, #13\n"
180             "vst1.s16 {q0}, [%[outp]]!\n"
181             : [outp] "+r" (outp), [inp] "+r" (inp)
182             :
183             : "q0", "q1", "memory");
184
185     while (inp != endp)
186         asm volatile (
187             "vld1.s32 {q0-q1}, [%[inp]]!\n"
188             "vld1.s32 {q2-q3}, [%[inp]]!\n"
189             "vrshrn.s32 d0, q0, #13\n"
190             "vrshrn.s32 d1, q1, #13\n"
191             "vrshrn.s32 d2, q2, #13\n"
192             "vrshrn.s32 d3, q3, #13\n"
193             "vst1.s16 {q0-q1}, [%[outp]]!\n"
194             : [outp] "+r" (outp), [inp] "+r" (inp)
195             :
196             : "q0", "q1", "q2", "q3", "memory");
197
198     outbuf->i_nb_samples = inbuf->i_nb_samples;
199     outbuf->i_buffer = inbuf->i_buffer / 2;
200     (void) aout;
201 }