1 /* Spa
2 *
3 * Copyright © 2019 Wim Taymans
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <math.h>
28
29 #include <spa/support/cpu.h>
30 #include <spa/utils/defs.h>
31 #include <spa/param/audio/format-utils.h>
32
33 #include "mix-ops.h"
34
35 typedef void (*mix_func_t) (struct mix_ops *ops, void * SPA_RESTRICT dst,
36 const void * SPA_RESTRICT src[], uint32_t n_src, uint32_t n_samples);
37
38 struct mix_info {
39 uint32_t fmt;
40 uint32_t n_channels;
41 uint32_t cpu_flags;
42 uint32_t stride;
43 mix_func_t process;
44 };
45
46 static struct mix_info mix_table[] =
47 {
48 /* f32 */
49 #if defined(HAVE_AVX)
50 { SPA_AUDIO_FORMAT_F32, 0, SPA_CPU_FLAG_AVX, 4, mix_f32_avx },
51 { SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_AVX, 4, mix_f32_avx },
52 #endif
53 #if defined (HAVE_SSE)
54 { SPA_AUDIO_FORMAT_F32, 0, SPA_CPU_FLAG_SSE, 4, mix_f32_sse },
55 { SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSE, 4, mix_f32_sse },
56 #endif
57 { SPA_AUDIO_FORMAT_F32, 0, 0, 4, mix_f32_c },
58 { SPA_AUDIO_FORMAT_F32P, 0, 0, 4, mix_f32_c },
59
60 /* f64 */
61 #if defined (HAVE_SSE2)
62 { SPA_AUDIO_FORMAT_F64, 0, SPA_CPU_FLAG_SSE2, 8, mix_f64_sse2 },
63 { SPA_AUDIO_FORMAT_F64P, 0, SPA_CPU_FLAG_SSE2, 8, mix_f64_sse2 },
64 #endif
65 { SPA_AUDIO_FORMAT_F64, 0, 0, 8, mix_f64_c },
66 { SPA_AUDIO_FORMAT_F64P, 0, 0, 8, mix_f64_c },
67
68 /* s8 */
69 { SPA_AUDIO_FORMAT_S8, 0, 0, 1, mix_s8_c },
70 { SPA_AUDIO_FORMAT_S8P, 0, 0, 1, mix_s8_c },
71 { SPA_AUDIO_FORMAT_U8, 0, 0, 1, mix_u8_c },
72 { SPA_AUDIO_FORMAT_U8P, 0, 0, 1, mix_u8_c },
73
74 /* s16 */
75 { SPA_AUDIO_FORMAT_S16, 0, 0, 2, mix_s16_c },
76 { SPA_AUDIO_FORMAT_S16P, 0, 0, 2, mix_s16_c },
77 { SPA_AUDIO_FORMAT_U16, 0, 0, 2, mix_u16_c },
78
79 /* s24 */
80 { SPA_AUDIO_FORMAT_S24, 0, 0, 3, mix_s24_c },
81 { SPA_AUDIO_FORMAT_S24P, 0, 0, 3, mix_s24_c },
82 { SPA_AUDIO_FORMAT_U24, 0, 0, 3, mix_u24_c },
83
84 /* s32 */
85 { SPA_AUDIO_FORMAT_S32, 0, 0, 4, mix_s32_c },
86 { SPA_AUDIO_FORMAT_S32P, 0, 0, 4, mix_s32_c },
87 { SPA_AUDIO_FORMAT_U32, 0, 0, 4, mix_u32_c },
88
89 /* s24_32 */
90 { SPA_AUDIO_FORMAT_S24_32, 0, 0, 4, mix_s24_32_c },
91 { SPA_AUDIO_FORMAT_S24_32P, 0, 0, 4, mix_s24_32_c },
92 { SPA_AUDIO_FORMAT_U24_32, 0, 0, 4, mix_u24_32_c },
93 };
94
95 #define MATCH_CHAN(a,b) ((a) == 0 || (a) == (b))
96 #define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a)
97
find_mix_info(uint32_t fmt,uint32_t n_channels,uint32_t cpu_flags)98 static const struct mix_info *find_mix_info(uint32_t fmt,
99 uint32_t n_channels, uint32_t cpu_flags)
100 {
101 size_t i;
102
103 for (i = 0; i < SPA_N_ELEMENTS(mix_table); i++) {
104 if (mix_table[i].fmt == fmt &&
105 MATCH_CHAN(mix_table[i].n_channels, n_channels) &&
106 MATCH_CPU_FLAGS(mix_table[i].cpu_flags, cpu_flags))
107 return &mix_table[i];
108 }
109 return NULL;
110 }
111
impl_mix_ops_clear(struct mix_ops * ops,void * SPA_RESTRICT dst,uint32_t n_samples)112 static void impl_mix_ops_clear(struct mix_ops *ops, void * SPA_RESTRICT dst, uint32_t n_samples)
113 {
114 const struct mix_info *info = ops->priv;
115 memset(dst, 0, n_samples * info->stride);
116 }
117
impl_mix_ops_free(struct mix_ops * ops)118 static void impl_mix_ops_free(struct mix_ops *ops)
119 {
120 spa_zero(*ops);
121 }
122
mix_ops_init(struct mix_ops * ops)123 int mix_ops_init(struct mix_ops *ops)
124 {
125 const struct mix_info *info;
126
127 info = find_mix_info(ops->fmt, ops->n_channels, ops->cpu_flags);
128 if (info == NULL)
129 return -ENOTSUP;
130
131 ops->priv = info;
132 ops->cpu_flags = info->cpu_flags;
133 ops->clear = impl_mix_ops_clear;
134 ops->process = info->process;
135 ops->free = impl_mix_ops_free;
136
137 return 0;
138 }
139