1 /* 2 * PCM Plug-In shared (kernel/library) code 3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> 4 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 5 * 6 * 7 * This library is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU Library General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 */ 22 23 #if 0 24 #define PLUGIN_DEBUG 25 #endif 26 27 #include <sound/driver.h> 28 29 #ifdef CONFIG_SND_PCM_OSS_PLUGINS 30 31 #include <linux/slab.h> 32 #include <linux/time.h> 33 #include <linux/vmalloc.h> 34 #include <sound/core.h> 35 #include <sound/pcm.h> 36 #include <sound/pcm_params.h> 37 #include "pcm_plugin.h" 38 39 #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first) 40 #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last) 41 42 /* 43 * because some cards might have rates "very close", we ignore 44 * all "resampling" requests within +-5% 45 */ 46 static int rate_match(unsigned int src_rate, unsigned int dst_rate) 47 { 48 unsigned int low = (src_rate * 95) / 100; 49 unsigned int high = (src_rate * 105) / 100; 50 return dst_rate >= low && dst_rate <= high; 51 } 52 53 static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames) 54 { 55 struct snd_pcm_plugin_format *format; 56 ssize_t width; 57 size_t size; 58 unsigned int channel; 59 struct snd_pcm_plugin_channel *c; 60 61 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) { 62 format = &plugin->src_format; 63 } else { 64 format = &plugin->dst_format; 65 } 66 if ((width = snd_pcm_format_physical_width(format->format)) < 0) 67 return width; 68 size = frames * format->channels * width; 69 snd_assert((size % 8) == 0, return -ENXIO); 70 size /= 8; 71 if (plugin->buf_frames < frames) { 72 vfree(plugin->buf); 73 plugin->buf = vmalloc(size); 74 plugin->buf_frames = frames; 75 } 76 if (!plugin->buf) { 77 plugin->buf_frames = 0; 78 return -ENOMEM; 79 } 80 c = plugin->buf_channels; 81 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { 82 for (channel = 0; channel < format->channels; channel++, c++) { 83 c->frames = frames; 84 c->enabled = 1; 85 c->wanted = 0; 86 c->area.addr = plugin->buf; 87 c->area.first = channel * width; 88 c->area.step = format->channels * width; 89 } 90 } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { 91 snd_assert((size % format->channels) == 0,); 92 size /= format->channels; 93 for (channel = 0; channel < format->channels; channel++, c++) { 94 c->frames = frames; 95 c->enabled = 1; 96 c->wanted = 0; 97 c->area.addr = plugin->buf + (channel * size); 98 c->area.first = 0; 99 c->area.step = width; 100 } 101 } else 102 return -EINVAL; 103 return 0; 104 } 105 106 int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) 107 { 108 int err; 109 snd_assert(snd_pcm_plug_first(plug) != NULL, return -ENXIO); 110 if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) { 111 struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug); 112 while (plugin->next) { 113 if (plugin->dst_frames) 114 frames = plugin->dst_frames(plugin, frames); 115 snd_assert(frames > 0, return -ENXIO); 116 plugin = plugin->next; 117 err = snd_pcm_plugin_alloc(plugin, frames); 118 if (err < 0) 119 return err; 120 } 121 } else { 122 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug); 123 while (plugin->prev) { 124 if (plugin->src_frames) 125 frames = plugin->src_frames(plugin, frames); 126 snd_assert(frames > 0, return -ENXIO); 127 plugin = plugin->prev; 128 err = snd_pcm_plugin_alloc(plugin, frames); 129 if (err < 0) 130 return err; 131 } 132 } 133 return 0; 134 } 135 136 137 snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin, 138 snd_pcm_uframes_t frames, 139 struct snd_pcm_plugin_channel **channels) 140 { 141 *channels = plugin->buf_channels; 142 return frames; 143 } 144 145 int snd_pcm_plugin_build(struct snd_pcm_substream *plug, 146 const char *name, 147 struct snd_pcm_plugin_format *src_format, 148 struct snd_pcm_plugin_format *dst_format, 149 size_t extra, 150 struct snd_pcm_plugin **ret) 151 { 152 struct snd_pcm_plugin *plugin; 153 unsigned int channels; 154 155 snd_assert(plug != NULL, return -ENXIO); 156 snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO); 157 plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL); 158 if (plugin == NULL) 159 return -ENOMEM; 160 plugin->name = name; 161 plugin->plug = plug; 162 plugin->stream = snd_pcm_plug_stream(plug); 163 plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 164 plugin->src_format = *src_format; 165 plugin->src_width = snd_pcm_format_physical_width(src_format->format); 166 snd_assert(plugin->src_width > 0, ); 167 plugin->dst_format = *dst_format; 168 plugin->dst_width = snd_pcm_format_physical_width(dst_format->format); 169 snd_assert(plugin->dst_width > 0, ); 170 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) 171 channels = src_format->channels; 172 else 173 channels = dst_format->channels; 174 plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL); 175 if (plugin->buf_channels == NULL) { 176 snd_pcm_plugin_free(plugin); 177 return -ENOMEM; 178 } 179 plugin->client_channels = snd_pcm_plugin_client_channels; 180 *ret = plugin; 181 return 0; 182 } 183 184 int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin) 185 { 186 if (! plugin) 187 return 0; 188 if (plugin->private_free) 189 plugin->private_free(plugin); 190 kfree(plugin->buf_channels); 191 vfree(plugin->buf); 192 kfree(plugin); 193 return 0; 194 } 195 196 snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames) 197 { 198 struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; 199 int stream = snd_pcm_plug_stream(plug); 200 201 snd_assert(plug != NULL, return -ENXIO); 202 if (drv_frames == 0) 203 return 0; 204 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 205 plugin = snd_pcm_plug_last(plug); 206 while (plugin && drv_frames > 0) { 207 plugin_prev = plugin->prev; 208 if (plugin->src_frames) 209 drv_frames = plugin->src_frames(plugin, drv_frames); 210 plugin = plugin_prev; 211 } 212 } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { 213 plugin = snd_pcm_plug_first(plug); 214 while (plugin && drv_frames > 0) { 215 plugin_next = plugin->next; 216 if (plugin->dst_frames) 217 drv_frames = plugin->dst_frames(plugin, drv_frames); 218 plugin = plugin_next; 219 } 220 } else 221 snd_BUG(); 222 return drv_frames; 223 } 224 225 snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames) 226 { 227 struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; 228 snd_pcm_sframes_t frames; 229 int stream = snd_pcm_plug_stream(plug); 230 231 snd_assert(plug != NULL, return -ENXIO); 232 if (clt_frames == 0) 233 return 0; 234 frames = clt_frames; 235 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 236 plugin = snd_pcm_plug_first(plug); 237 while (plugin && frames > 0) { 238 plugin_next = plugin->next; 239 if (plugin->dst_frames) { 240 frames = plugin->dst_frames(plugin, frames); 241 if (frames < 0) 242 return frames; 243 } 244 plugin = plugin_next; 245 } 246 } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { 247 plugin = snd_pcm_plug_last(plug); 248 while (plugin) { 249 plugin_prev = plugin->prev; 250 if (plugin->src_frames) { 251 frames = plugin->src_frames(plugin, frames); 252 if (frames < 0) 253 return frames; 254 } 255 plugin = plugin_prev; 256 } 257 } else 258 snd_BUG(); 259 return frames; 260 } 261 262 static int snd_pcm_plug_formats(struct snd_mask *mask, int format) 263 { 264 struct snd_mask formats = *mask; 265 u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | 266 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | 267 SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | 268 SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE | 269 SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE | 270 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | 271 SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE); 272 snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW); 273 274 if (formats.bits[0] & (u32)linfmts) 275 formats.bits[0] |= (u32)linfmts; 276 if (formats.bits[1] & (u32)(linfmts >> 32)) 277 formats.bits[1] |= (u32)(linfmts >> 32); 278 return snd_mask_test(&formats, format); 279 } 280 281 static int preferred_formats[] = { 282 SNDRV_PCM_FORMAT_S16_LE, 283 SNDRV_PCM_FORMAT_S16_BE, 284 SNDRV_PCM_FORMAT_U16_LE, 285 SNDRV_PCM_FORMAT_U16_BE, 286 SNDRV_PCM_FORMAT_S24_LE, 287 SNDRV_PCM_FORMAT_S24_BE, 288 SNDRV_PCM_FORMAT_U24_LE, 289 SNDRV_PCM_FORMAT_U24_BE, 290 SNDRV_PCM_FORMAT_S32_LE, 291 SNDRV_PCM_FORMAT_S32_BE, 292 SNDRV_PCM_FORMAT_U32_LE, 293 SNDRV_PCM_FORMAT_U32_BE, 294 SNDRV_PCM_FORMAT_S8, 295 SNDRV_PCM_FORMAT_U8 296 }; 297 298 int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) 299 { 300 if (snd_mask_test(format_mask, format)) 301 return format; 302 if (! snd_pcm_plug_formats(format_mask, format)) 303 return -EINVAL; 304 if (snd_pcm_format_linear(format)) { 305 int width = snd_pcm_format_width(format); 306 int unsignd = snd_pcm_format_unsigned(format); 307 int big = snd_pcm_format_big_endian(format); 308 int format1; 309 int wid, width1=width; 310 int dwidth1 = 8; 311 for (wid = 0; wid < 4; ++wid) { 312 int end, big1 = big; 313 for (end = 0; end < 2; ++end) { 314 int sgn, unsignd1 = unsignd; 315 for (sgn = 0; sgn < 2; ++sgn) { 316 format1 = snd_pcm_build_linear_format(width1, unsignd1, big1); 317 if (format1 >= 0 && 318 snd_mask_test(format_mask, format1)) 319 goto _found; 320 unsignd1 = !unsignd1; 321 } 322 big1 = !big1; 323 } 324 if (width1 == 32) { 325 dwidth1 = -dwidth1; 326 width1 = width; 327 } 328 width1 += dwidth1; 329 } 330 return -EINVAL; 331 _found: 332 return format1; 333 } else { 334 unsigned int i; 335 switch (format) { 336 case SNDRV_PCM_FORMAT_MU_LAW: 337 for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) { 338 int format1 = preferred_formats[i]; 339 if (snd_mask_test(format_mask, format1)) 340 return format1; 341 } 342 default: 343 return -EINVAL; 344 } 345 } 346 } 347 348 int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug, 349 struct snd_pcm_hw_params *params, 350 struct snd_pcm_hw_params *slave_params) 351 { 352 struct snd_pcm_plugin_format tmpformat; 353 struct snd_pcm_plugin_format dstformat; 354 struct snd_pcm_plugin_format srcformat; 355 int src_access, dst_access; 356 struct snd_pcm_plugin *plugin = NULL; 357 int err; 358 int stream = snd_pcm_plug_stream(plug); 359 int slave_interleaved = (params_channels(slave_params) == 1 || 360 params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED); 361 362 switch (stream) { 363 case SNDRV_PCM_STREAM_PLAYBACK: 364 dstformat.format = params_format(slave_params); 365 dstformat.rate = params_rate(slave_params); 366 dstformat.channels = params_channels(slave_params); 367 srcformat.format = params_format(params); 368 srcformat.rate = params_rate(params); 369 srcformat.channels = params_channels(params); 370 src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 371 dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED : 372 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); 373 break; 374 case SNDRV_PCM_STREAM_CAPTURE: 375 dstformat.format = params_format(params); 376 dstformat.rate = params_rate(params); 377 dstformat.channels = params_channels(params); 378 srcformat.format = params_format(slave_params); 379 srcformat.rate = params_rate(slave_params); 380 srcformat.channels = params_channels(slave_params); 381 src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED : 382 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); 383 dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 384 break; 385 default: 386 snd_BUG(); 387 return -EINVAL; 388 } 389 tmpformat = srcformat; 390 391 pdprintf("srcformat: format=%i, rate=%i, channels=%i\n", 392 srcformat.format, 393 srcformat.rate, 394 srcformat.channels); 395 pdprintf("dstformat: format=%i, rate=%i, channels=%i\n", 396 dstformat.format, 397 dstformat.rate, 398 dstformat.channels); 399 400 /* Format change (linearization) */ 401 if (! rate_match(srcformat.rate, dstformat.rate) && 402 ! snd_pcm_format_linear(srcformat.format)) { 403 if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW) 404 return -EINVAL; 405 tmpformat.format = SNDRV_PCM_FORMAT_S16; 406 err = snd_pcm_plugin_build_mulaw(plug, 407 &srcformat, &tmpformat, 408 &plugin); 409 if (err < 0) 410 return err; 411 err = snd_pcm_plugin_append(plugin); 412 if (err < 0) { 413 snd_pcm_plugin_free(plugin); 414 return err; 415 } 416 srcformat = tmpformat; 417 src_access = dst_access; 418 } 419 420 /* channels reduction */ 421 if (srcformat.channels > dstformat.channels) { 422 tmpformat.channels = dstformat.channels; 423 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin); 424 pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err); 425 if (err < 0) 426 return err; 427 err = snd_pcm_plugin_append(plugin); 428 if (err < 0) { 429 snd_pcm_plugin_free(plugin); 430 return err; 431 } 432 srcformat = tmpformat; 433 src_access = dst_access; 434 } 435 436 /* rate resampling */ 437 if (!rate_match(srcformat.rate, dstformat.rate)) { 438 if (srcformat.format != SNDRV_PCM_FORMAT_S16) { 439 /* convert to S16 for resampling */ 440 tmpformat.format = SNDRV_PCM_FORMAT_S16; 441 err = snd_pcm_plugin_build_linear(plug, 442 &srcformat, &tmpformat, 443 &plugin); 444 if (err < 0) 445 return err; 446 err = snd_pcm_plugin_append(plugin); 447 if (err < 0) { 448 snd_pcm_plugin_free(plugin); 449 return err; 450 } 451 srcformat = tmpformat; 452 src_access = dst_access; 453 } 454 tmpformat.rate = dstformat.rate; 455 err = snd_pcm_plugin_build_rate(plug, 456 &srcformat, &tmpformat, 457 &plugin); 458 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err); 459 if (err < 0) 460 return err; 461 err = snd_pcm_plugin_append(plugin); 462 if (err < 0) { 463 snd_pcm_plugin_free(plugin); 464 return err; 465 } 466 srcformat = tmpformat; 467 src_access = dst_access; 468 } 469 470 /* format change */ 471 if (srcformat.format != dstformat.format) { 472 tmpformat.format = dstformat.format; 473 if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW || 474 tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) { 475 err = snd_pcm_plugin_build_mulaw(plug, 476 &srcformat, &tmpformat, 477 &plugin); 478 } 479 else if (snd_pcm_format_linear(srcformat.format) && 480 snd_pcm_format_linear(tmpformat.format)) { 481 err = snd_pcm_plugin_build_linear(plug, 482 &srcformat, &tmpformat, 483 &plugin); 484 } 485 else 486 return -EINVAL; 487 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err); 488 if (err < 0) 489 return err; 490 err = snd_pcm_plugin_append(plugin); 491 if (err < 0) { 492 snd_pcm_plugin_free(plugin); 493 return err; 494 } 495 srcformat = tmpformat; 496 src_access = dst_access; 497 } 498 499 /* channels extension */ 500 if (srcformat.channels < dstformat.channels) { 501 tmpformat.channels = dstformat.channels; 502 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin); 503 pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err); 504 if (err < 0) 505 return err; 506 err = snd_pcm_plugin_append(plugin); 507 if (err < 0) { 508 snd_pcm_plugin_free(plugin); 509 return err; 510 } 511 srcformat = tmpformat; 512 src_access = dst_access; 513 } 514 515 /* de-interleave */ 516 if (src_access != dst_access) { 517 err = snd_pcm_plugin_build_copy(plug, 518 &srcformat, 519 &tmpformat, 520 &plugin); 521 pdprintf("interleave change (copy: returns %i)\n", err); 522 if (err < 0) 523 return err; 524 err = snd_pcm_plugin_append(plugin); 525 if (err < 0) { 526 snd_pcm_plugin_free(plugin); 527 return err; 528 } 529 } 530 531 return 0; 532 } 533 534 snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plug, 535 char *buf, 536 snd_pcm_uframes_t count, 537 struct snd_pcm_plugin_channel **channels) 538 { 539 struct snd_pcm_plugin *plugin; 540 struct snd_pcm_plugin_channel *v; 541 struct snd_pcm_plugin_format *format; 542 int width, nchannels, channel; 543 int stream = snd_pcm_plug_stream(plug); 544 545 snd_assert(buf != NULL, return -ENXIO); 546 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 547 plugin = snd_pcm_plug_first(plug); 548 format = &plugin->src_format; 549 } else { 550 plugin = snd_pcm_plug_last(plug); 551 format = &plugin->dst_format; 552 } 553 v = plugin->buf_channels; 554 *channels = v; 555 if ((width = snd_pcm_format_physical_width(format->format)) < 0) 556 return width; 557 nchannels = format->channels; 558 snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO); 559 for (channel = 0; channel < nchannels; channel++, v++) { 560 v->frames = count; 561 v->enabled = 1; 562 v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE); 563 v->area.addr = buf; 564 v->area.first = channel * width; 565 v->area.step = nchannels * width; 566 } 567 return count; 568 } 569 570 snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *src_channels, snd_pcm_uframes_t size) 571 { 572 struct snd_pcm_plugin *plugin, *next; 573 struct snd_pcm_plugin_channel *dst_channels; 574 int err; 575 snd_pcm_sframes_t frames = size; 576 577 plugin = snd_pcm_plug_first(plug); 578 while (plugin && frames > 0) { 579 if ((next = plugin->next) != NULL) { 580 snd_pcm_sframes_t frames1 = frames; 581 if (plugin->dst_frames) 582 frames1 = plugin->dst_frames(plugin, frames); 583 if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) { 584 return err; 585 } 586 if (err != frames1) { 587 frames = err; 588 if (plugin->src_frames) 589 frames = plugin->src_frames(plugin, frames1); 590 } 591 } else 592 dst_channels = NULL; 593 pdprintf("write plugin: %s, %li\n", plugin->name, frames); 594 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) 595 return frames; 596 src_channels = dst_channels; 597 plugin = next; 598 } 599 return snd_pcm_plug_client_size(plug, frames); 600 } 601 602 snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size) 603 { 604 struct snd_pcm_plugin *plugin, *next; 605 struct snd_pcm_plugin_channel *src_channels, *dst_channels; 606 snd_pcm_sframes_t frames = size; 607 int err; 608 609 frames = snd_pcm_plug_slave_size(plug, frames); 610 if (frames < 0) 611 return frames; 612 613 src_channels = NULL; 614 plugin = snd_pcm_plug_first(plug); 615 while (plugin && frames > 0) { 616 if ((next = plugin->next) != NULL) { 617 if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) { 618 return err; 619 } 620 frames = err; 621 } else { 622 dst_channels = dst_channels_final; 623 } 624 pdprintf("read plugin: %s, %li\n", plugin->name, frames); 625 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) 626 return frames; 627 plugin = next; 628 src_channels = dst_channels; 629 } 630 return frames; 631 } 632 633 int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst_offset, 634 size_t samples, int format) 635 { 636 /* FIXME: sub byte resolution and odd dst_offset */ 637 unsigned char *dst; 638 unsigned int dst_step; 639 int width; 640 const unsigned char *silence; 641 if (!dst_area->addr) 642 return 0; 643 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; 644 width = snd_pcm_format_physical_width(format); 645 if (width <= 0) 646 return -EINVAL; 647 if (dst_area->step == (unsigned int) width && width >= 8) 648 return snd_pcm_format_set_silence(format, dst, samples); 649 silence = snd_pcm_format_silence_64(format); 650 if (! silence) 651 return -EINVAL; 652 dst_step = dst_area->step / 8; 653 if (width == 4) { 654 /* Ima ADPCM */ 655 int dstbit = dst_area->first % 8; 656 int dstbit_step = dst_area->step % 8; 657 while (samples-- > 0) { 658 if (dstbit) 659 *dst &= 0xf0; 660 else 661 *dst &= 0x0f; 662 dst += dst_step; 663 dstbit += dstbit_step; 664 if (dstbit == 8) { 665 dst++; 666 dstbit = 0; 667 } 668 } 669 } else { 670 width /= 8; 671 while (samples-- > 0) { 672 memcpy(dst, silence, width); 673 dst += dst_step; 674 } 675 } 676 return 0; 677 } 678 679 int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_offset, 680 const struct snd_pcm_channel_area *dst_area, size_t dst_offset, 681 size_t samples, int format) 682 { 683 /* FIXME: sub byte resolution and odd dst_offset */ 684 char *src, *dst; 685 int width; 686 int src_step, dst_step; 687 src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8; 688 if (!src_area->addr) 689 return snd_pcm_area_silence(dst_area, dst_offset, samples, format); 690 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; 691 if (!dst_area->addr) 692 return 0; 693 width = snd_pcm_format_physical_width(format); 694 if (width <= 0) 695 return -EINVAL; 696 if (src_area->step == (unsigned int) width && 697 dst_area->step == (unsigned int) width && width >= 8) { 698 size_t bytes = samples * width / 8; 699 memcpy(dst, src, bytes); 700 return 0; 701 } 702 src_step = src_area->step / 8; 703 dst_step = dst_area->step / 8; 704 if (width == 4) { 705 /* Ima ADPCM */ 706 int srcbit = src_area->first % 8; 707 int srcbit_step = src_area->step % 8; 708 int dstbit = dst_area->first % 8; 709 int dstbit_step = dst_area->step % 8; 710 while (samples-- > 0) { 711 unsigned char srcval; 712 if (srcbit) 713 srcval = *src & 0x0f; 714 else 715 srcval = (*src & 0xf0) >> 4; 716 if (dstbit) 717 *dst = (*dst & 0xf0) | srcval; 718 else 719 *dst = (*dst & 0x0f) | (srcval << 4); 720 src += src_step; 721 srcbit += srcbit_step; 722 if (srcbit == 8) { 723 src++; 724 srcbit = 0; 725 } 726 dst += dst_step; 727 dstbit += dstbit_step; 728 if (dstbit == 8) { 729 dst++; 730 dstbit = 0; 731 } 732 } 733 } else { 734 width /= 8; 735 while (samples-- > 0) { 736 memcpy(dst, src, width); 737 src += src_step; 738 dst += dst_step; 739 } 740 } 741 return 0; 742 } 743 744 #endif 745