Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Attenuated route Plug-In | |
3 | * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> | |
4 | * | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU Library General Public License as | |
8 | * published by the Free Software Foundation; either version 2 of | |
9 | * the License, or (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 Library General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Library General Public | |
17 | * License along with this library; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | * | |
20 | */ | |
21 | ||
22 | #include <sound/driver.h> | |
21a3479a JK |
23 | |
24 | #ifdef CONFIG_SND_PCM_OSS_PLUGINS | |
25 | ||
1da177e4 LT |
26 | #include <linux/slab.h> |
27 | #include <linux/time.h> | |
28 | #include <sound/core.h> | |
29 | #include <sound/pcm.h> | |
30 | #include "pcm_plugin.h" | |
31 | ||
32 | /* The best possible hack to support missing optimization in gcc 2.7.2.3 */ | |
33 | #if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0 | |
34 | #define div(a) a /= ROUTE_PLUGIN_RESOLUTION | |
35 | #elif ROUTE_PLUGIN_RESOLUTION == 16 | |
36 | #define div(a) a >>= 4 | |
37 | #else | |
38 | #error "Add some code here" | |
39 | #endif | |
40 | ||
6ac77bc1 | 41 | struct ttable_dst; |
1da177e4 | 42 | |
6ac77bc1 TI |
43 | typedef void (*route_channel_f)(struct snd_pcm_plugin *plugin, |
44 | const struct snd_pcm_plugin_channel *src_channels, | |
45 | struct snd_pcm_plugin_channel *dst_channel, | |
46 | struct ttable_dst *ttable, snd_pcm_uframes_t frames); | |
1da177e4 | 47 | |
6ac77bc1 | 48 | struct ttable_src { |
1da177e4 LT |
49 | int channel; |
50 | int as_int; | |
6ac77bc1 | 51 | }; |
1da177e4 LT |
52 | |
53 | struct ttable_dst { | |
54 | int att; /* Attenuated */ | |
55 | unsigned int nsrcs; | |
6ac77bc1 | 56 | struct ttable_src *srcs; |
1da177e4 LT |
57 | route_channel_f func; |
58 | }; | |
59 | ||
6ac77bc1 | 60 | struct route_priv { |
1da177e4 LT |
61 | enum {R_UINT32=0, R_UINT64=1} sum_type; |
62 | int get, put; | |
63 | int conv; | |
64 | int src_sample_size; | |
6ac77bc1 | 65 | struct ttable_dst ttable[0]; |
1da177e4 LT |
66 | }; |
67 | ||
6ac77bc1 | 68 | union sum { |
1da177e4 LT |
69 | u_int32_t as_uint32; |
70 | u_int64_t as_uint64; | |
6ac77bc1 | 71 | }; |
1da177e4 LT |
72 | |
73 | ||
6ac77bc1 TI |
74 | static void route_to_channel_from_zero(struct snd_pcm_plugin *plugin, |
75 | const struct snd_pcm_plugin_channel *src_channels, | |
76 | struct snd_pcm_plugin_channel *dst_channel, | |
77 | struct ttable_dst *ttable, | |
78 | snd_pcm_uframes_t frames) | |
1da177e4 LT |
79 | { |
80 | if (dst_channel->wanted) | |
81 | snd_pcm_area_silence(&dst_channel->area, 0, frames, plugin->dst_format.format); | |
82 | dst_channel->enabled = 0; | |
83 | } | |
84 | ||
6ac77bc1 TI |
85 | static void route_to_channel_from_one(struct snd_pcm_plugin *plugin, |
86 | const struct snd_pcm_plugin_channel *src_channels, | |
87 | struct snd_pcm_plugin_channel *dst_channel, | |
88 | struct ttable_dst *ttable, | |
89 | snd_pcm_uframes_t frames) | |
1da177e4 LT |
90 | { |
91 | #define CONV_LABELS | |
92 | #include "plugin_ops.h" | |
93 | #undef CONV_LABELS | |
6ac77bc1 | 94 | struct route_priv *data = (struct route_priv *)plugin->extra_data; |
1da177e4 | 95 | void *conv; |
6ac77bc1 | 96 | const struct snd_pcm_plugin_channel *src_channel = NULL; |
1da177e4 LT |
97 | unsigned int srcidx; |
98 | char *src, *dst; | |
99 | int src_step, dst_step; | |
100 | for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) { | |
101 | src_channel = &src_channels[ttable->srcs[srcidx].channel]; | |
102 | if (src_channel->area.addr != NULL) | |
103 | break; | |
104 | } | |
105 | if (srcidx == ttable->nsrcs) { | |
106 | route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames); | |
107 | return; | |
108 | } | |
109 | ||
110 | dst_channel->enabled = 1; | |
111 | conv = conv_labels[data->conv]; | |
112 | src = src_channel->area.addr + src_channel->area.first / 8; | |
113 | src_step = src_channel->area.step / 8; | |
114 | dst = dst_channel->area.addr + dst_channel->area.first / 8; | |
115 | dst_step = dst_channel->area.step / 8; | |
116 | while (frames-- > 0) { | |
117 | goto *conv; | |
118 | #define CONV_END after | |
119 | #include "plugin_ops.h" | |
120 | #undef CONV_END | |
121 | after: | |
122 | src += src_step; | |
123 | dst += dst_step; | |
124 | } | |
125 | } | |
126 | ||
6ac77bc1 TI |
127 | static void route_to_channel(struct snd_pcm_plugin *plugin, |
128 | const struct snd_pcm_plugin_channel *src_channels, | |
129 | struct snd_pcm_plugin_channel *dst_channel, | |
130 | struct ttable_dst *ttable, snd_pcm_uframes_t frames) | |
1da177e4 LT |
131 | { |
132 | #define GET_U_LABELS | |
133 | #define PUT_U32_LABELS | |
134 | #include "plugin_ops.h" | |
135 | #undef GET_U_LABELS | |
136 | #undef PUT_U32_LABELS | |
137 | static void *zero_labels[2] = { &&zero_int32, &&zero_int64 }; | |
138 | /* sum_type att */ | |
139 | static void *add_labels[2 * 2] = { &&add_int32_noatt, &&add_int32_att, | |
140 | &&add_int64_noatt, &&add_int64_att, | |
141 | }; | |
142 | /* sum_type att shift */ | |
143 | static void *norm_labels[2 * 2 * 4] = { NULL, | |
144 | &&norm_int32_8_noatt, | |
145 | &&norm_int32_16_noatt, | |
146 | &&norm_int32_24_noatt, | |
147 | NULL, | |
148 | &&norm_int32_8_att, | |
149 | &&norm_int32_16_att, | |
150 | &&norm_int32_24_att, | |
151 | &&norm_int64_0_noatt, | |
152 | &&norm_int64_8_noatt, | |
153 | &&norm_int64_16_noatt, | |
154 | &&norm_int64_24_noatt, | |
155 | &&norm_int64_0_att, | |
156 | &&norm_int64_8_att, | |
157 | &&norm_int64_16_att, | |
158 | &&norm_int64_24_att, | |
159 | }; | |
6ac77bc1 | 160 | struct route_priv *data = (struct route_priv *)plugin->extra_data; |
1da177e4 LT |
161 | void *zero, *get, *add, *norm, *put_u32; |
162 | int nsrcs = ttable->nsrcs; | |
163 | char *dst; | |
164 | int dst_step; | |
165 | char *srcs[nsrcs]; | |
166 | int src_steps[nsrcs]; | |
6ac77bc1 | 167 | struct ttable_src src_tt[nsrcs]; |
1da177e4 LT |
168 | u_int32_t sample = 0; |
169 | int srcidx, srcidx1 = 0; | |
170 | for (srcidx = 0; srcidx < nsrcs; ++srcidx) { | |
6ac77bc1 | 171 | const struct snd_pcm_plugin_channel *src_channel = &src_channels[ttable->srcs[srcidx].channel]; |
1da177e4 LT |
172 | if (!src_channel->enabled) |
173 | continue; | |
174 | srcs[srcidx1] = src_channel->area.addr + src_channel->area.first / 8; | |
175 | src_steps[srcidx1] = src_channel->area.step / 8; | |
176 | src_tt[srcidx1] = ttable->srcs[srcidx]; | |
177 | srcidx1++; | |
178 | } | |
179 | nsrcs = srcidx1; | |
180 | if (nsrcs == 0) { | |
181 | route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames); | |
182 | return; | |
183 | } else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) { | |
184 | route_to_channel_from_one(plugin, src_channels, dst_channel, ttable, frames); | |
185 | return; | |
186 | } | |
187 | ||
188 | dst_channel->enabled = 1; | |
189 | zero = zero_labels[data->sum_type]; | |
190 | get = get_u_labels[data->get]; | |
191 | add = add_labels[data->sum_type * 2 + ttable->att]; | |
192 | norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size]; | |
193 | put_u32 = put_u32_labels[data->put]; | |
194 | dst = dst_channel->area.addr + dst_channel->area.first / 8; | |
195 | dst_step = dst_channel->area.step / 8; | |
196 | ||
197 | while (frames-- > 0) { | |
6ac77bc1 TI |
198 | struct ttable_src *ttp = src_tt; |
199 | union sum sum; | |
1da177e4 LT |
200 | |
201 | /* Zero sum */ | |
202 | goto *zero; | |
203 | zero_int32: | |
204 | sum.as_uint32 = 0; | |
205 | goto zero_end; | |
206 | zero_int64: | |
207 | sum.as_uint64 = 0; | |
208 | goto zero_end; | |
209 | zero_end: | |
210 | for (srcidx = 0; srcidx < nsrcs; ++srcidx) { | |
211 | char *src = srcs[srcidx]; | |
212 | ||
213 | /* Get sample */ | |
214 | goto *get; | |
215 | #define GET_U_END after_get | |
216 | #include "plugin_ops.h" | |
217 | #undef GET_U_END | |
218 | after_get: | |
219 | ||
220 | /* Sum */ | |
221 | goto *add; | |
222 | add_int32_att: | |
223 | sum.as_uint32 += sample * ttp->as_int; | |
224 | goto after_sum; | |
225 | add_int32_noatt: | |
226 | if (ttp->as_int) | |
227 | sum.as_uint32 += sample; | |
228 | goto after_sum; | |
229 | add_int64_att: | |
230 | sum.as_uint64 += (u_int64_t) sample * ttp->as_int; | |
231 | goto after_sum; | |
232 | add_int64_noatt: | |
233 | if (ttp->as_int) | |
234 | sum.as_uint64 += sample; | |
235 | goto after_sum; | |
236 | after_sum: | |
237 | srcs[srcidx] += src_steps[srcidx]; | |
238 | ttp++; | |
239 | } | |
240 | ||
241 | /* Normalization */ | |
242 | goto *norm; | |
243 | norm_int32_8_att: | |
244 | sum.as_uint64 = sum.as_uint32; | |
245 | norm_int64_8_att: | |
246 | sum.as_uint64 <<= 8; | |
247 | norm_int64_0_att: | |
248 | div(sum.as_uint64); | |
249 | goto norm_int; | |
250 | ||
251 | norm_int32_16_att: | |
252 | sum.as_uint64 = sum.as_uint32; | |
253 | norm_int64_16_att: | |
254 | sum.as_uint64 <<= 16; | |
255 | div(sum.as_uint64); | |
256 | goto norm_int; | |
257 | ||
258 | norm_int32_24_att: | |
259 | sum.as_uint64 = sum.as_uint32; | |
260 | norm_int64_24_att: | |
261 | sum.as_uint64 <<= 24; | |
262 | div(sum.as_uint64); | |
263 | goto norm_int; | |
264 | ||
265 | norm_int32_8_noatt: | |
266 | sum.as_uint64 = sum.as_uint32; | |
267 | norm_int64_8_noatt: | |
268 | sum.as_uint64 <<= 8; | |
269 | goto norm_int; | |
270 | ||
271 | norm_int32_16_noatt: | |
272 | sum.as_uint64 = sum.as_uint32; | |
273 | norm_int64_16_noatt: | |
274 | sum.as_uint64 <<= 16; | |
275 | goto norm_int; | |
276 | ||
277 | norm_int32_24_noatt: | |
278 | sum.as_uint64 = sum.as_uint32; | |
279 | norm_int64_24_noatt: | |
280 | sum.as_uint64 <<= 24; | |
281 | goto norm_int; | |
282 | ||
283 | norm_int64_0_noatt: | |
284 | norm_int: | |
285 | if (sum.as_uint64 > (u_int32_t)0xffffffff) | |
286 | sample = (u_int32_t)0xffffffff; | |
287 | else | |
288 | sample = sum.as_uint64; | |
289 | goto after_norm; | |
290 | ||
291 | after_norm: | |
292 | ||
293 | /* Put sample */ | |
294 | goto *put_u32; | |
295 | #define PUT_U32_END after_put_u32 | |
296 | #include "plugin_ops.h" | |
297 | #undef PUT_U32_END | |
298 | after_put_u32: | |
299 | ||
300 | dst += dst_step; | |
301 | } | |
302 | } | |
303 | ||
6ac77bc1 | 304 | static int route_src_channels_mask(struct snd_pcm_plugin *plugin, |
47eaebfd TI |
305 | unsigned long *dst_vmask, |
306 | unsigned long **src_vmask) | |
1da177e4 | 307 | { |
6ac77bc1 | 308 | struct route_priv *data = (struct route_priv *)plugin->extra_data; |
1da177e4 LT |
309 | int schannels = plugin->src_format.channels; |
310 | int dchannels = plugin->dst_format.channels; | |
47eaebfd | 311 | unsigned long *vmask = plugin->src_vmask; |
1da177e4 | 312 | int channel; |
6ac77bc1 | 313 | struct ttable_dst *dp = data->ttable; |
47eaebfd | 314 | bitmap_zero(vmask, schannels); |
1da177e4 LT |
315 | for (channel = 0; channel < dchannels; channel++, dp++) { |
316 | unsigned int src; | |
6ac77bc1 | 317 | struct ttable_src *sp; |
47eaebfd | 318 | if (!test_bit(channel, dst_vmask)) |
1da177e4 LT |
319 | continue; |
320 | sp = dp->srcs; | |
321 | for (src = 0; src < dp->nsrcs; src++, sp++) | |
47eaebfd | 322 | set_bit(sp->channel, vmask); |
1da177e4 LT |
323 | } |
324 | *src_vmask = vmask; | |
325 | return 0; | |
326 | } | |
327 | ||
6ac77bc1 | 328 | static int route_dst_channels_mask(struct snd_pcm_plugin *plugin, |
47eaebfd TI |
329 | unsigned long *src_vmask, |
330 | unsigned long **dst_vmask) | |
1da177e4 | 331 | { |
6ac77bc1 | 332 | struct route_priv *data = (struct route_priv *)plugin->extra_data; |
1da177e4 | 333 | int dchannels = plugin->dst_format.channels; |
47eaebfd | 334 | unsigned long *vmask = plugin->dst_vmask; |
1da177e4 | 335 | int channel; |
6ac77bc1 | 336 | struct ttable_dst *dp = data->ttable; |
47eaebfd | 337 | bitmap_zero(vmask, dchannels); |
1da177e4 LT |
338 | for (channel = 0; channel < dchannels; channel++, dp++) { |
339 | unsigned int src; | |
6ac77bc1 | 340 | struct ttable_src *sp; |
1da177e4 LT |
341 | sp = dp->srcs; |
342 | for (src = 0; src < dp->nsrcs; src++, sp++) { | |
47eaebfd TI |
343 | if (test_bit(sp->channel, src_vmask)) { |
344 | set_bit(channel, vmask); | |
1da177e4 LT |
345 | break; |
346 | } | |
347 | } | |
348 | } | |
349 | *dst_vmask = vmask; | |
350 | return 0; | |
351 | } | |
352 | ||
6ac77bc1 | 353 | static void route_free(struct snd_pcm_plugin *plugin) |
1da177e4 | 354 | { |
6ac77bc1 | 355 | struct route_priv *data = (struct route_priv *)plugin->extra_data; |
1da177e4 LT |
356 | unsigned int dst_channel; |
357 | for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) { | |
358 | kfree(data->ttable[dst_channel].srcs); | |
359 | } | |
360 | } | |
361 | ||
6ac77bc1 TI |
362 | static int route_load_ttable(struct snd_pcm_plugin *plugin, |
363 | const int *src_ttable) | |
1da177e4 | 364 | { |
6ac77bc1 | 365 | struct route_priv *data; |
1da177e4 | 366 | unsigned int src_channel, dst_channel; |
6ac77bc1 TI |
367 | const int *sptr; |
368 | struct ttable_dst *dptr; | |
1da177e4 LT |
369 | if (src_ttable == NULL) |
370 | return 0; | |
6ac77bc1 | 371 | data = (struct route_priv *)plugin->extra_data; |
1da177e4 LT |
372 | dptr = data->ttable; |
373 | sptr = src_ttable; | |
374 | plugin->private_free = route_free; | |
375 | for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) { | |
6ac77bc1 | 376 | int t = 0; |
1da177e4 LT |
377 | int att = 0; |
378 | int nsrcs = 0; | |
6ac77bc1 | 379 | struct ttable_src srcs[plugin->src_format.channels]; |
1da177e4 LT |
380 | for (src_channel = 0; src_channel < plugin->src_format.channels; ++src_channel) { |
381 | snd_assert(*sptr >= 0 || *sptr <= FULL, return -ENXIO); | |
382 | if (*sptr != 0) { | |
383 | srcs[nsrcs].channel = src_channel; | |
384 | srcs[nsrcs].as_int = *sptr; | |
385 | if (*sptr != FULL) | |
386 | att = 1; | |
387 | t += *sptr; | |
388 | nsrcs++; | |
389 | } | |
390 | sptr++; | |
391 | } | |
392 | dptr->att = att; | |
393 | dptr->nsrcs = nsrcs; | |
394 | if (nsrcs == 0) | |
395 | dptr->func = route_to_channel_from_zero; | |
396 | else if (nsrcs == 1 && !att) | |
397 | dptr->func = route_to_channel_from_one; | |
398 | else | |
399 | dptr->func = route_to_channel; | |
400 | if (nsrcs > 0) { | |
401 | int srcidx; | |
402 | dptr->srcs = kcalloc(nsrcs, sizeof(*srcs), GFP_KERNEL); | |
403 | for(srcidx = 0; srcidx < nsrcs; srcidx++) | |
404 | dptr->srcs[srcidx] = srcs[srcidx]; | |
405 | } else | |
406 | dptr->srcs = NULL; | |
407 | dptr++; | |
408 | } | |
409 | return 0; | |
410 | } | |
411 | ||
6ac77bc1 TI |
412 | static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin, |
413 | const struct snd_pcm_plugin_channel *src_channels, | |
414 | struct snd_pcm_plugin_channel *dst_channels, | |
1da177e4 LT |
415 | snd_pcm_uframes_t frames) |
416 | { | |
6ac77bc1 | 417 | struct route_priv *data; |
1da177e4 LT |
418 | int src_nchannels, dst_nchannels; |
419 | int dst_channel; | |
6ac77bc1 TI |
420 | struct ttable_dst *ttp; |
421 | struct snd_pcm_plugin_channel *dvp; | |
1da177e4 LT |
422 | |
423 | snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO); | |
424 | if (frames == 0) | |
425 | return 0; | |
6ac77bc1 | 426 | data = (struct route_priv *)plugin->extra_data; |
1da177e4 LT |
427 | |
428 | src_nchannels = plugin->src_format.channels; | |
429 | dst_nchannels = plugin->dst_format.channels; | |
430 | ||
431 | #ifdef CONFIG_SND_DEBUG | |
432 | { | |
433 | int src_channel; | |
434 | for (src_channel = 0; src_channel < src_nchannels; ++src_channel) { | |
435 | snd_assert(src_channels[src_channel].area.first % 8 == 0 || | |
436 | src_channels[src_channel].area.step % 8 == 0, | |
437 | return -ENXIO); | |
438 | } | |
439 | for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) { | |
440 | snd_assert(dst_channels[dst_channel].area.first % 8 == 0 || | |
441 | dst_channels[dst_channel].area.step % 8 == 0, | |
442 | return -ENXIO); | |
443 | } | |
444 | } | |
445 | #endif | |
446 | ||
447 | ttp = data->ttable; | |
448 | dvp = dst_channels; | |
449 | for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) { | |
450 | ttp->func(plugin, src_channels, dvp, ttp, frames); | |
451 | dvp++; | |
452 | ttp++; | |
453 | } | |
454 | return frames; | |
455 | } | |
456 | ||
457 | int getput_index(int format) | |
458 | { | |
459 | int sign, width, endian; | |
460 | sign = !snd_pcm_format_signed(format); | |
461 | width = snd_pcm_format_width(format) / 8 - 1; | |
462 | if (width < 0 || width > 3) { | |
463 | snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format); | |
464 | width = 0; | |
465 | } | |
466 | #ifdef SNDRV_LITTLE_ENDIAN | |
467 | endian = snd_pcm_format_big_endian(format); | |
468 | #else | |
469 | endian = snd_pcm_format_little_endian(format); | |
470 | #endif | |
471 | if (endian < 0) | |
472 | endian = 0; | |
473 | return width * 4 + endian * 2 + sign; | |
474 | } | |
475 | ||
6ac77bc1 TI |
476 | int snd_pcm_plugin_build_route(struct snd_pcm_substream *plug, |
477 | struct snd_pcm_plugin_format *src_format, | |
478 | struct snd_pcm_plugin_format *dst_format, | |
479 | int *ttable, | |
480 | struct snd_pcm_plugin **r_plugin) | |
1da177e4 | 481 | { |
6ac77bc1 TI |
482 | struct route_priv *data; |
483 | struct snd_pcm_plugin *plugin; | |
1da177e4 LT |
484 | int err; |
485 | ||
486 | snd_assert(r_plugin != NULL, return -ENXIO); | |
487 | *r_plugin = NULL; | |
488 | snd_assert(src_format->rate == dst_format->rate, return -ENXIO); | |
489 | snd_assert(snd_pcm_format_linear(src_format->format) != 0 && | |
490 | snd_pcm_format_linear(dst_format->format) != 0, | |
491 | return -ENXIO); | |
492 | ||
493 | err = snd_pcm_plugin_build(plug, "attenuated route conversion", | |
494 | src_format, dst_format, | |
6ac77bc1 TI |
495 | sizeof(struct route_priv) + |
496 | sizeof(data->ttable[0]) * dst_format->channels, | |
1da177e4 LT |
497 | &plugin); |
498 | if (err < 0) | |
499 | return err; | |
500 | ||
6ac77bc1 | 501 | data = (struct route_priv *)plugin->extra_data; |
1da177e4 LT |
502 | |
503 | data->get = getput_index(src_format->format); | |
504 | snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL); | |
505 | data->put = getput_index(dst_format->format); | |
506 | snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL); | |
507 | data->conv = conv_index(src_format->format, dst_format->format); | |
508 | ||
509 | if (snd_pcm_format_width(src_format->format) == 32) | |
510 | data->sum_type = R_UINT64; | |
511 | else | |
512 | data->sum_type = R_UINT32; | |
513 | data->src_sample_size = snd_pcm_format_width(src_format->format) / 8; | |
514 | ||
515 | if ((err = route_load_ttable(plugin, ttable)) < 0) { | |
516 | snd_pcm_plugin_free(plugin); | |
517 | return err; | |
518 | } | |
519 | plugin->transfer = route_transfer; | |
520 | plugin->src_channels_mask = route_src_channels_mask; | |
521 | plugin->dst_channels_mask = route_dst_channels_mask; | |
522 | *r_plugin = plugin; | |
523 | return 0; | |
524 | } | |
21a3479a JK |
525 | |
526 | #endif |