route.c 14 KB

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