1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 
34 /* non-concurrent version, only supporting little endians */
35 #define generic_dmix_supported_format \
36     ((1ULL << SND_PCM_FORMAT_S16_LE) | (1ULL << SND_PCM_FORMAT_S32_LE) |\
37      (1ULL << SND_PCM_FORMAT_S24_LE) | (1ULL << SND_PCM_FORMAT_S24_3LE) | \
38      (1ULL << SND_PCM_FORMAT_U8))
39 
generic_mix_areas_16_native(unsigned int size,volatile signed short * dst,signed short * src,volatile signed int * sum,size_t dst_step,size_t src_step,size_t sum_step)40 static void generic_mix_areas_16_native(unsigned int size,
41                     volatile signed short *dst,
42                     signed short *src,
43                     volatile signed int *sum,
44                     size_t dst_step,
45                     size_t src_step,
46                     size_t sum_step)
47 {
48     register signed int sample;
49 
50     for (;;) {
51         sample = *src;
52         if (! *dst) {
53             *sum = sample;
54             *dst = *src;
55         } else {
56             sample += *sum;
57             *sum = sample;
58             if (sample > 0x7fff)
59                 sample = 0x7fff;
60             else if (sample < -0x8000)
61                 sample = -0x8000;
62             *dst = sample;
63         }
64         if (!--size)
65             return;
66         src = (signed short *) ((char *)src + src_step);
67         dst = (signed short *) ((char *)dst + dst_step);
68         sum = (signed int *)   ((char *)sum + sum_step);
69     }
70 }
71 
generic_remix_areas_16_native(unsigned int size,volatile signed short * dst,signed short * src,volatile signed int * sum,size_t dst_step,size_t src_step,size_t sum_step)72 static void generic_remix_areas_16_native(unsigned int size,
73                       volatile signed short *dst,
74                       signed short *src,
75                       volatile signed int *sum,
76                       size_t dst_step,
77                       size_t src_step,
78                       size_t sum_step)
79 {
80     register signed int sample;
81 
82     for (;;) {
83         sample = *src;
84         if (! *dst) {
85             *sum = -sample;
86             *dst = -sample;
87         } else {
88             *sum = sample = *sum - sample;
89             if (sample > 0x7fff)
90                 sample = 0x7fff;
91             else if (sample < -0x8000)
92                 sample = -0x8000;
93             *dst = sample;
94         }
95         if (!--size)
96             return;
97         src = (signed short *) ((char *)src + src_step);
98         dst = (signed short *) ((char *)dst + dst_step);
99         sum = (signed int *)   ((char *)sum + sum_step);
100     }
101 }
102 
generic_mix_areas_32_native(unsigned int size,volatile signed int * dst,signed int * src,volatile signed int * sum,size_t dst_step,size_t src_step,size_t sum_step)103 static void generic_mix_areas_32_native(unsigned int size,
104                     volatile signed int *dst,
105                     signed int *src,
106                     volatile signed int *sum,
107                     size_t dst_step,
108                     size_t src_step,
109                     size_t sum_step)
110 {
111     register signed int sample;
112 
113     for (;;) {
114         sample = *src >> 8;
115         if (! *dst) {
116             *sum = sample;
117             *dst = *src;
118         } else {
119             sample += *sum;
120             *sum = sample;
121             if (sample > 0x7fffff)
122                 sample = 0x7fffffff;
123             else if (sample < -0x800000)
124                 sample = -0x80000000;
125             else
126                 sample *= 256;
127             *dst = sample;
128         }
129         if (!--size)
130             return;
131         src = (signed int *) ((char *)src + src_step);
132         dst = (signed int *) ((char *)dst + dst_step);
133         sum = (signed int *) ((char *)sum + sum_step);
134     }
135 }
136 
generic_remix_areas_32_native(unsigned int size,volatile signed int * dst,signed int * src,volatile signed int * sum,size_t dst_step,size_t src_step,size_t sum_step)137 static void generic_remix_areas_32_native(unsigned int size,
138                       volatile signed int *dst,
139                       signed int *src,
140                       volatile signed int *sum,
141                       size_t dst_step,
142                       size_t src_step,
143                       size_t sum_step)
144 {
145     register signed int sample;
146 
147     for (;;) {
148         sample = *src >> 8;
149         if (! *dst) {
150             *sum = -sample;
151             *dst = -*src;
152         } else {
153             *sum = sample = *sum - sample;
154             if (sample > 0x7fffff)
155                 sample = 0x7fffffff;
156             else if (sample < -0x800000)
157                 sample = -0x80000000;
158             else
159                 sample *= 256;
160             *dst = sample;
161         }
162         if (!--size)
163             return;
164         src = (signed int *) ((char *)src + src_step);
165         dst = (signed int *) ((char *)dst + dst_step);
166         sum = (signed int *) ((char *)sum + sum_step);
167     }
168 }
169 
170 /* always little endian */
generic_mix_areas_24(unsigned int size,volatile unsigned char * dst,unsigned char * src,volatile signed int * sum,size_t dst_step,size_t src_step,size_t sum_step)171 static void generic_mix_areas_24(unsigned int size,
172                  volatile unsigned char *dst,
173                  unsigned char *src,
174                  volatile signed int *sum,
175                  size_t dst_step,
176                  size_t src_step,
177                  size_t sum_step)
178 {
179     register signed int sample;
180 
181     for (;;) {
182         sample = src[0] | (src[1] << 8) | (((signed char *)src)[2] << 16);
183         if (!(dst[0] | dst[1] | dst[2])) {
184             *sum = sample;
185         } else {
186             sample += *sum;
187             *sum = sample;
188             if (sample > 0x7fffff)
189                 sample = 0x7fffff;
190             else if (sample < -0x800000)
191                 sample = -0x800000;
192         }
193         dst[0] = sample;
194         dst[1] = sample >> 8;
195         dst[2] = sample >> 16;
196         if (!--size)
197             return;
198         dst += dst_step;
199         src += src_step;
200         sum = (signed int *) ((char *)sum + sum_step);
201     }
202 }
203 
generic_remix_areas_24(unsigned int size,volatile unsigned char * dst,unsigned char * src,volatile signed int * sum,size_t dst_step,size_t src_step,size_t sum_step)204 static void generic_remix_areas_24(unsigned int size,
205                    volatile unsigned char *dst,
206                    unsigned char *src,
207                    volatile signed int *sum,
208                    size_t dst_step,
209                    size_t src_step,
210                    size_t sum_step)
211 {
212     register signed int sample;
213 
214     for (;;) {
215         sample = src[0] | (src[1] << 8) | (((signed char *)src)[2] << 16);
216         if (!(dst[0] | dst[1] | dst[2])) {
217             sample = -sample;
218             *sum = sample;
219         } else {
220             *sum = sample = *sum - sample;
221             if (sample > 0x7fffff)
222                 sample = 0x7fffff;
223             else if (sample < -0x800000)
224                 sample = -0x800000;
225         }
226         dst[0] = sample;
227         dst[1] = sample >> 8;
228         dst[2] = sample >> 16;
229         if (!--size)
230             return;
231         dst += dst_step;
232         src += src_step;
233         sum = (signed int *) ((char *)sum + sum_step);
234     }
235 }
236 
generic_mix_areas_u8(unsigned int size,volatile unsigned char * dst,unsigned char * src,volatile signed int * sum,size_t dst_step,size_t src_step,size_t sum_step)237 static void generic_mix_areas_u8(unsigned int size,
238                  volatile unsigned char *dst,
239                  unsigned char *src,
240                  volatile signed int *sum,
241                  size_t dst_step,
242                  size_t src_step,
243                  size_t sum_step)
244 {
245     for (;;) {
246         register int sample = *src - 0x80;
247         if (*dst == 0x80) {
248             *sum = sample;
249         } else {
250             sample += *sum;
251             *sum = sample;
252             if (sample > 0x7f)
253                 sample = 0x7f;
254             else if (sample < -0x80)
255                 sample = -0x80;
256         }
257         *dst = sample + 0x80;
258         if (!--size)
259             return;
260         dst += dst_step;
261         src += src_step;
262         sum = (signed int *) ((char *)sum + sum_step);
263     }
264 }
265 
generic_remix_areas_u8(unsigned int size,volatile unsigned char * dst,unsigned char * src,volatile signed int * sum,size_t dst_step,size_t src_step,size_t sum_step)266 static void generic_remix_areas_u8(unsigned int size,
267                    volatile unsigned char *dst,
268                    unsigned char *src,
269                    volatile signed int *sum,
270                    size_t dst_step,
271                    size_t src_step,
272                    size_t sum_step)
273 {
274     for (;;) {
275         register int sample = *src - 0x80;
276         if (*dst == 0x80) {
277             sample = -sample;
278             *sum = sample;
279         } else {
280             *sum = sample = *sum - sample;
281             if (sample > 0x7f)
282                 sample = 0x7f;
283             else if (sample < -0x80)
284                 sample = -0x80;
285         }
286         *dst = sample + 0x80;
287         if (!--size)
288             return;
289         dst += dst_step;
290         src += src_step;
291         sum = (signed int *) ((char *)sum + sum_step);
292     }
293 }
294 
295 
generic_mix_select_callbacks(snd_pcm_direct_t * dmix)296 static void generic_mix_select_callbacks(snd_pcm_direct_t *dmix)
297 {
298     /* only support native version, not support swap version */
299 
300     dmix->u.dmix.mix_areas_16 = generic_mix_areas_16_native;
301     dmix->u.dmix.mix_areas_32 = generic_mix_areas_32_native;
302     dmix->u.dmix.remix_areas_16 = generic_remix_areas_16_native;
303     dmix->u.dmix.remix_areas_32 = generic_remix_areas_32_native;
304 
305     dmix->u.dmix.mix_areas_24 = generic_mix_areas_24;
306     dmix->u.dmix.mix_areas_u8 = generic_mix_areas_u8;
307     dmix->u.dmix.remix_areas_24 = generic_remix_areas_24;
308     dmix->u.dmix.remix_areas_u8 = generic_remix_areas_u8;
309 }
310