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