]> git.sesse.net Git - vlc/blob - modules/audio_filter/converter/neon.c
Qt: DO NOT use qobject_cast without checking it!
[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_filter.h>
29 #include <vlc_cpu.h>
30
31 #include <assert.h>
32
33 static int Open (vlc_object_t *);
34
35 vlc_module_begin ()
36     set_description (N_("ARM NEON audio format conversions") )
37     set_capability ("audio filter", 20)
38     set_callbacks (Open, NULL)
39     add_requirement (NEON)
40 vlc_module_end ()
41
42 static block_t *Do_F32_S32 (filter_t *, block_t *);
43 static block_t *Do_S32_S16 (filter_t *, block_t *);
44
45 static int Open (vlc_object_t *obj)
46 {
47     filter_t *filter = (filter_t *)obj;
48
49     if (!AOUT_FMTS_SIMILAR (&filter->fmt_in.audio, &filter->fmt_out.audio))
50         return VLC_EGENERIC;
51
52     switch (filter->fmt_in.audio.i_format)
53     {
54         case VLC_CODEC_FL32:
55             switch (filter->fmt_out.audio.i_format)
56             {
57                 case VLC_CODEC_FI32:
58                     filter->pf_audio_filter = Do_F32_S32;
59                     break;
60                 default:
61                     return VLC_EGENERIC;
62             }
63             break;
64
65         case VLC_CODEC_FI32:
66             switch (filter->fmt_out.audio.i_format)
67             {
68                 case VLC_CODEC_S16N:
69                     filter->pf_audio_filter = Do_S32_S16;
70                     break;
71                 default:
72                     return VLC_EGENERIC;
73             }
74             break;
75         default:
76             return VLC_EGENERIC;
77     }
78     return VLC_SUCCESS;
79 }
80
81 /**
82  * Single-precision floating point to signed fixed point conversion.
83  */
84 static block_t *Do_F32_S32 (filter_t *filter, block_t *inbuf)
85 {
86     unsigned nb_samples = inbuf->i_nb_samples
87                      * aout_FormatNbChannels (&filter->fmt_in.audio);
88     int32_t *outp = (int32_t *)inbuf->p_buffer;
89     int32_t *endp = outp + nb_samples;
90
91     if (nb_samples & 1)
92     {
93         asm volatile (
94             "vldr.32 s0, [%[outp]]\n"
95             "vcvt.s32.f32 d0, d0, #28\n"
96             "vstr.32 s0, [%[outp]]\n"
97             :
98             : [outp] "r" (outp)
99             : "d0", "memory");
100         outp++;
101     }
102
103     if (nb_samples & 2)
104         asm volatile (
105             "vld1.f32 {d0}, [%[outp]]\n"
106             "vcvt.s32.f32 d0, d0, #28\n"
107             "vst1.s32 {d0}, [%[outp]]!\n"
108             : [outp] "+r" (outp)
109             :
110             : "d0", "memory");
111
112     if (nb_samples & 4)
113         asm volatile (
114             "vld1.f32 {q0}, [%[outp]]\n"
115             "vcvt.s32.f32 q0, q0, #28\n"
116             "vst1.s32 {q0}, [%[outp]]!\n"
117             : [outp] "+r" (outp)
118             :
119             : "q0", "memory");
120
121     while (outp != endp)
122         asm volatile (
123             "vld1.f32 {q0-q1}, [%[outp]]\n"
124             "vcvt.s32.f32 q0, q0, #28\n"
125             "vcvt.s32.f32 q1, q1, #28\n"
126             "vst1.s32 {q0-q1}, [%[outp]]!\n"
127             : [outp] "+r" (outp)
128             :
129             : "q0", "q1", "memory");
130
131     return inbuf;
132 }
133
134 void s32_s16_neon_unaligned (int16_t *out, const int32_t *in, unsigned nb);
135 void s32_s16_neon (int16_t *out, const int32_t *in, unsigned nb);
136
137 /**
138  * Signed 32-bits fixed point to signed 16-bits integer
139  */
140 static block_t *Do_S32_S16 (filter_t *filter, block_t *inbuf)
141 {
142     const int32_t *in = (int32_t *)inbuf->p_buffer;
143     int16_t *out = (int16_t *)in;
144     unsigned nb;
145
146     nb = ((-(uintptr_t)in) & 12) >> 2;
147     out += nb; /* fix up misalignment */
148     inbuf->p_buffer += 2 * nb;
149
150     s32_s16_neon_unaligned (out, in, nb);
151     in += nb;
152     out += nb;
153
154     nb = inbuf->i_nb_samples
155          * aout_FormatNbChannels (&filter->fmt_in.audio) - nb;
156     assert (!(((uintptr_t)in) & 15));
157     assert (!(((uintptr_t)out) & 15));
158
159     s32_s16_neon (out, in, nb);
160     inbuf->i_buffer /= 2;
161     return inbuf;
162 }