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