route.c 14 KB

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