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 <stdlib.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <time.h>
31
32 #include <spa/support/log-impl.h>
33 #include <spa/debug/mem.h>
34
35 SPA_LOG_IMPL(logger);
36
37 #define MATRIX(...) (float[]) { __VA_ARGS__ }
38
39 #include "channelmix-ops.c"
dump_matrix(struct channelmix * mix,float * coeff)40 static void dump_matrix(struct channelmix *mix, float *coeff)
41 {
42 uint32_t i, j;
43
44 for (i = 0; i < mix->dst_chan; i++) {
45 for (j = 0; j < mix->src_chan; j++) {
46 float v = mix->matrix_orig[i][j];
47 spa_log_debug(mix->log, "%d %d: %f <-> %f", i, j, v, *coeff);
48 spa_assert_se(fabs(v - *coeff) < 0.000001);
49 coeff++;
50 }
51 }
52 }
53
test_mix(uint32_t src_chan,uint32_t src_mask,uint32_t dst_chan,uint32_t dst_mask,float * coeff)54 static void test_mix(uint32_t src_chan, uint32_t src_mask, uint32_t dst_chan, uint32_t dst_mask, float *coeff)
55 {
56 struct channelmix mix;
57
58 spa_log_debug(&logger.log, "start %d->%d (%08x -> %08x)", src_chan, dst_chan, src_mask, dst_mask);
59
60 spa_zero(mix);
61 mix.src_chan = src_chan;
62 mix.dst_chan = dst_chan;
63 mix.src_mask = src_mask;
64 mix.dst_mask = dst_mask;
65 mix.log = &logger.log;
66
67 channelmix_init(&mix);
68 dump_matrix(&mix, coeff);
69 }
70
test_1_N_MONO(void)71 static void test_1_N_MONO(void)
72 {
73 test_mix(1, _M(MONO), 2, _M(FL)|_M(FR),
74 MATRIX(1.0, 1.0));
75 test_mix(1, _M(MONO), 3, _M(FL)|_M(FR)|_M(LFE),
76 MATRIX(1.0, 1.0, 1.0));
77 test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
78 MATRIX(1.0, 1.0, 1.0, 1.0));
79 test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
80 MATRIX(1.0, 1.0, 1.0, 1.0));
81 test_mix(1, _M(MONO), 12, 0,
82 MATRIX(1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
83 1.0, 1.0, 1.0, 1.0, 1.0, 1.0));
84 }
85
test_1_N_FC(void)86 static void test_1_N_FC(void)
87 {
88 test_mix(1, _M(FC), 2, _M(FL)|_M(FR),
89 MATRIX(0.707107, 0.707107));
90 test_mix(1, _M(FC), 3, _M(FL)|_M(FR)|_M(LFE),
91 MATRIX(0.707107, 0.707107, 0.0));
92 test_mix(1, _M(FC), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
93 MATRIX(0.0, 0.0, 1.0, 0.0));
94 test_mix(1, _M(FC), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
95 MATRIX(0.707107, 0.707107, 0.0, 0.0));
96 test_mix(1, _M(FC), 12, 0,
97 MATRIX(1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
98 1.0, 1.0, 1.0, 1.0, 1.0, 1.0));
99 }
100
test_N_1(void)101 static void test_N_1(void)
102 {
103 test_mix(1, _M(MONO), 1, _M(MONO),
104 MATRIX(1.0));
105 test_mix(1, _M(MONO), 1, _M(FC),
106 MATRIX(1.0));
107 test_mix(1, _M(FC), 1, _M(MONO),
108 MATRIX(1.0));
109 test_mix(1, _M(FC), 1, _M(FC),
110 MATRIX(1.0));
111 test_mix(2, _M(FL)|_M(FR), 1, _M(MONO),
112 MATRIX(0.707107, 0.707107));
113 test_mix(12, 0, 1, _M(MONO),
114 MATRIX(0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333,
115 0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.0833333));
116 }
117
test_3p1_N(void)118 static void test_3p1_N(void)
119 {
120 test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 1, _M(MONO),
121 MATRIX(0.707107, 0.707107, 1.0, 0.0));
122 test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 2, _M(FL)|_M(FR),
123 MATRIX(1.0, 0.0, 0.707107, 0.0,
124 0.0, 1.0, 0.707107, 0.0 ));
125 test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 3, _M(FL)|_M(FR)|_M(LFE),
126 MATRIX(1.0, 0.0, 0.707107, 0.0,
127 0.0, 1.0, 0.707107, 0.0,
128 0.0, 0.0, 0.0, 1.0 ));
129 test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
130 MATRIX(1.0, 0.0, 0.0, 0.0,
131 0.0, 1.0, 0.0, 0.0,
132 0.0, 0.0, 1.0, 0.0,
133 0.0, 0.0, 0.0, 1.0,));
134 test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
135 MATRIX(1.0, 0.0, 0.707107, 0.0,
136 0.0, 1.0, 0.707107, 0.0,
137 0.0, 0.0, 0.0, 0.0,
138 0.0, 0.0, 0.0, 0.0,));
139 }
140
test_4_N(void)141 static void test_4_N(void)
142 {
143 test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 1, _M(MONO),
144 MATRIX(0.707107, 0.707107, 0.5, 0.5));
145 test_mix(4, _M(FL)|_M(FR)|_M(SL)|_M(SR), 1, _M(MONO),
146 MATRIX(0.707107, 0.707107, 0.5, 0.5));
147 test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR),
148 MATRIX(1.0, 0.0, 0.707107, 0.0,
149 0.0, 1.0, 0.0, 0.707107));
150 test_mix(4, _M(FL)|_M(FR)|_M(SL)|_M(SR), 2, _M(FL)|_M(FR),
151 MATRIX(1.0, 0.0, 0.707107, 0.0,
152 0.0, 1.0, 0.0, 0.707107));
153 test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 3, _M(FL)|_M(FR)|_M(LFE),
154 MATRIX(1.0, 0.0, 0.707107, 0.0,
155 0.0, 1.0, 0.0, 0.707107,
156 0.0, 0.0, 0.0, 0.0));
157 test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
158 MATRIX(1.0, 0.0, 0.0, 0.0,
159 0.0, 1.0, 0.0, 0.0,
160 0.0, 0.0, 1.0, 0.0,
161 0.0, 0.0, 0.0, 1.0));
162 test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
163 MATRIX(1.0, 0.0, 0.707107, 0.0,
164 0.0, 1.0, 0.0, 0.707107,
165 0.0, 0.0, 0.0, 0.0,
166 0.0, 0.0, 0.0, 0.0));
167 }
168
test_5p1_N(void)169 static void test_5p1_N(void)
170 {
171 test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 1, _M(MONO),
172 MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5));
173 test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 2, _M(FL)|_M(FR),
174 MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0,
175 0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107));
176 test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR),
177 MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0,
178 0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107));
179 test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 3, _M(FL)|_M(FR)|_M(LFE),
180 MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0,
181 0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107,
182 0.0, 0.0, 0.0, 1.0, 0.0, 0.0));
183 test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
184 MATRIX(1.0, 0.0, 0.0, 0.0, 0.707107, 0.0,
185 0.0, 1.0, 0.0, 0.0, 0.0, 0.707107,
186 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
187 0.0, 0.0, 0.0, 1.0, 0.0, 0.0));
188 test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
189 MATRIX(1.0, 0.0, 0.707107, 0.0, 0.0, 0.0,
190 0.0, 1.0, 0.707107, 0.0, 0.0, 0.0,
191 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
192 0.0, 0.0, 0.0, 0.0, 0.0, 1.0));
193 test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 5, _M(FL)|_M(FR)|_M(FC)|_M(SL)|_M(SR),
194 MATRIX(1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
195 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
196 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
197 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
198 0.0, 0.0, 0.0, 0.0, 0.0, 1.0));
199 test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR),
200 MATRIX(1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
201 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
202 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
203 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
204 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
205 0.0, 0.0, 0.0, 0.0, 0.0, 1.0));
206 }
207
test_7p1_N(void)208 static void test_7p1_N(void)
209 {
210 test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 1, _M(MONO),
211 MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5, 0.5, 0.5));
212 test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR),
213 MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0, 0.707107, 0.0,
214 0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107, 0.0, 0.707107));
215 }
216
main(int argc,char * argv[])217 int main(int argc, char *argv[])
218 {
219 logger.log.level = SPA_LOG_LEVEL_TRACE;
220
221 test_1_N_MONO();
222 test_1_N_FC();
223 test_N_1();
224 test_3p1_N();
225 test_4_N();
226 test_5p1_N();
227 test_7p1_N();
228
229 return 0;
230 }
231