2 * PCM Plug-In shared (kernel/library) code
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
4 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
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.
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.
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
27 #include <linux/slab.h>
28 #include <linux/time.h>
29 #include <linux/vmalloc.h>
30 #include <sound/core.h>
31 #include <sound/pcm.h>
32 #include <sound/pcm_params.h>
33 #include "pcm_plugin.h"
35 #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
36 #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
39 * because some cards might have rates "very close", we ignore
40 * all "resampling" requests within +-5%
42 static int rate_match(unsigned int src_rate, unsigned int dst_rate)
44 unsigned int low = (src_rate * 95) / 100;
45 unsigned int high = (src_rate * 105) / 100;
46 return dst_rate >= low && dst_rate <= high;
49 static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
51 struct snd_pcm_plugin_format *format;
55 struct snd_pcm_plugin_channel *c;
57 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) {
58 format = &plugin->src_format;
60 format = &plugin->dst_format;
62 width = snd_pcm_format_physical_width(format->format);
65 size = frames * format->channels * width;
66 if (snd_BUG_ON(size % 8))
69 if (plugin->buf_frames < frames) {
71 plugin->buf = kvzalloc(size, GFP_KERNEL);
72 plugin->buf_frames = frames;
75 plugin->buf_frames = 0;
78 c = plugin->buf_channels;
79 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
80 for (channel = 0; channel < format->channels; channel++, c++) {
84 c->area.addr = plugin->buf;
85 c->area.first = channel * width;
86 c->area.step = format->channels * width;
88 } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
89 if (snd_BUG_ON(size % format->channels))
91 size /= format->channels;
92 for (channel = 0; channel < format->channels; channel++, c++) {
96 c->area.addr = plugin->buf + (channel * size);
105 int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
108 if (snd_BUG_ON(!snd_pcm_plug_first(plug)))
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 if ((snd_pcm_sframes_t)frames <= 0)
117 plugin = plugin->next;
118 err = snd_pcm_plugin_alloc(plugin, frames);
123 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
124 while (plugin->prev) {
125 if (plugin->src_frames)
126 frames = plugin->src_frames(plugin, frames);
127 if ((snd_pcm_sframes_t)frames <= 0)
129 plugin = plugin->prev;
130 err = snd_pcm_plugin_alloc(plugin, frames);
139 snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin,
140 snd_pcm_uframes_t frames,
141 struct snd_pcm_plugin_channel **channels)
143 *channels = plugin->buf_channels;
147 int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
149 struct snd_pcm_plugin_format *src_format,
150 struct snd_pcm_plugin_format *dst_format,
152 struct snd_pcm_plugin **ret)
154 struct snd_pcm_plugin *plugin;
155 unsigned int channels;
157 if (snd_BUG_ON(!plug))
159 if (snd_BUG_ON(!src_format || !dst_format))
161 plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
166 plugin->stream = snd_pcm_plug_stream(plug);
167 plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
168 plugin->src_format = *src_format;
169 plugin->src_width = snd_pcm_format_physical_width(src_format->format);
170 snd_BUG_ON(plugin->src_width <= 0);
171 plugin->dst_format = *dst_format;
172 plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
173 snd_BUG_ON(plugin->dst_width <= 0);
174 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK)
175 channels = src_format->channels;
177 channels = dst_format->channels;
178 plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL);
179 if (plugin->buf_channels == NULL) {
180 snd_pcm_plugin_free(plugin);
183 plugin->client_channels = snd_pcm_plugin_client_channels;
188 int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
192 if (plugin->private_free)
193 plugin->private_free(plugin);
194 kfree(plugin->buf_channels);
200 static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
201 snd_pcm_sframes_t frames,
204 struct snd_pcm_plugin *plugin, *plugin_next;
206 plugin = snd_pcm_plug_first(plug);
207 while (plugin && frames > 0) {
208 plugin_next = plugin->next;
209 if (check_size && plugin->buf_frames &&
210 frames > plugin->buf_frames)
211 frames = plugin->buf_frames;
212 if (plugin->dst_frames) {
213 frames = plugin->dst_frames(plugin, frames);
217 plugin = plugin_next;
222 static snd_pcm_sframes_t calc_src_frames(struct snd_pcm_substream *plug,
223 snd_pcm_sframes_t frames,
226 struct snd_pcm_plugin *plugin, *plugin_prev;
228 plugin = snd_pcm_plug_last(plug);
229 while (plugin && frames > 0) {
230 plugin_prev = plugin->prev;
231 if (plugin->src_frames) {
232 frames = plugin->src_frames(plugin, frames);
236 if (check_size && plugin->buf_frames &&
237 frames > plugin->buf_frames)
238 frames = plugin->buf_frames;
239 plugin = plugin_prev;
244 snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames)
246 if (snd_BUG_ON(!plug))
248 switch (snd_pcm_plug_stream(plug)) {
249 case SNDRV_PCM_STREAM_PLAYBACK:
250 return calc_src_frames(plug, drv_frames, false);
251 case SNDRV_PCM_STREAM_CAPTURE:
252 return calc_dst_frames(plug, drv_frames, false);
259 snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames)
261 if (snd_BUG_ON(!plug))
263 switch (snd_pcm_plug_stream(plug)) {
264 case SNDRV_PCM_STREAM_PLAYBACK:
265 return calc_dst_frames(plug, clt_frames, false);
266 case SNDRV_PCM_STREAM_CAPTURE:
267 return calc_src_frames(plug, clt_frames, false);
274 static int snd_pcm_plug_formats(const struct snd_mask *mask,
275 snd_pcm_format_t format)
277 struct snd_mask formats = *mask;
278 u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
279 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
280 SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
281 SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE |
282 SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE |
283 SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_S24_3LE |
284 SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE |
285 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
286 SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
287 snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW);
289 if (formats.bits[0] & lower_32_bits(linfmts))
290 formats.bits[0] |= lower_32_bits(linfmts);
291 if (formats.bits[1] & upper_32_bits(linfmts))
292 formats.bits[1] |= upper_32_bits(linfmts);
293 return snd_mask_test(&formats, (__force int)format);
296 static const snd_pcm_format_t preferred_formats[] = {
297 SNDRV_PCM_FORMAT_S16_LE,
298 SNDRV_PCM_FORMAT_S16_BE,
299 SNDRV_PCM_FORMAT_U16_LE,
300 SNDRV_PCM_FORMAT_U16_BE,
301 SNDRV_PCM_FORMAT_S24_3LE,
302 SNDRV_PCM_FORMAT_S24_3BE,
303 SNDRV_PCM_FORMAT_U24_3LE,
304 SNDRV_PCM_FORMAT_U24_3BE,
305 SNDRV_PCM_FORMAT_S24_LE,
306 SNDRV_PCM_FORMAT_S24_BE,
307 SNDRV_PCM_FORMAT_U24_LE,
308 SNDRV_PCM_FORMAT_U24_BE,
309 SNDRV_PCM_FORMAT_S32_LE,
310 SNDRV_PCM_FORMAT_S32_BE,
311 SNDRV_PCM_FORMAT_U32_LE,
312 SNDRV_PCM_FORMAT_U32_BE,
317 snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
318 const struct snd_mask *format_mask)
322 if (snd_mask_test(format_mask, (__force int)format))
324 if (!snd_pcm_plug_formats(format_mask, format))
325 return (__force snd_pcm_format_t)-EINVAL;
326 if (snd_pcm_format_linear(format)) {
327 unsigned int width = snd_pcm_format_width(format);
328 int unsignd = snd_pcm_format_unsigned(format) > 0;
329 int big = snd_pcm_format_big_endian(format) > 0;
330 unsigned int badness, best = -1;
331 snd_pcm_format_t best_format = (__force snd_pcm_format_t)-1;
332 for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) {
333 snd_pcm_format_t f = preferred_formats[i];
335 if (!snd_mask_test(format_mask, (__force int)f))
337 w = snd_pcm_format_width(f);
341 badness = width - w + 32;
342 badness += snd_pcm_format_unsigned(f) != unsignd;
343 badness += snd_pcm_format_big_endian(f) != big;
344 if (badness < best) {
349 if ((__force int)best_format >= 0)
352 return (__force snd_pcm_format_t)-EINVAL;
355 case SNDRV_PCM_FORMAT_MU_LAW:
356 for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
357 snd_pcm_format_t format1 = preferred_formats[i];
358 if (snd_mask_test(format_mask, (__force int)format1))
363 return (__force snd_pcm_format_t)-EINVAL;
368 int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
369 struct snd_pcm_hw_params *params,
370 struct snd_pcm_hw_params *slave_params)
372 struct snd_pcm_plugin_format tmpformat;
373 struct snd_pcm_plugin_format dstformat;
374 struct snd_pcm_plugin_format srcformat;
375 snd_pcm_access_t src_access, dst_access;
376 struct snd_pcm_plugin *plugin = NULL;
378 int stream = snd_pcm_plug_stream(plug);
379 int slave_interleaved = (params_channels(slave_params) == 1 ||
380 params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED);
383 case SNDRV_PCM_STREAM_PLAYBACK:
384 dstformat.format = params_format(slave_params);
385 dstformat.rate = params_rate(slave_params);
386 dstformat.channels = params_channels(slave_params);
387 srcformat.format = params_format(params);
388 srcformat.rate = params_rate(params);
389 srcformat.channels = params_channels(params);
390 src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
391 dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
392 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
394 case SNDRV_PCM_STREAM_CAPTURE:
395 dstformat.format = params_format(params);
396 dstformat.rate = params_rate(params);
397 dstformat.channels = params_channels(params);
398 srcformat.format = params_format(slave_params);
399 srcformat.rate = params_rate(slave_params);
400 srcformat.channels = params_channels(slave_params);
401 src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
402 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
403 dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
409 tmpformat = srcformat;
411 pdprintf("srcformat: format=%i, rate=%i, channels=%i\n",
415 pdprintf("dstformat: format=%i, rate=%i, channels=%i\n",
420 /* Format change (linearization) */
421 if (! rate_match(srcformat.rate, dstformat.rate) &&
422 ! snd_pcm_format_linear(srcformat.format)) {
423 if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW)
425 tmpformat.format = SNDRV_PCM_FORMAT_S16;
426 err = snd_pcm_plugin_build_mulaw(plug,
427 &srcformat, &tmpformat,
431 err = snd_pcm_plugin_append(plugin);
433 snd_pcm_plugin_free(plugin);
436 srcformat = tmpformat;
437 src_access = dst_access;
440 /* channels reduction */
441 if (srcformat.channels > dstformat.channels) {
442 tmpformat.channels = dstformat.channels;
443 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
444 pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
447 err = snd_pcm_plugin_append(plugin);
449 snd_pcm_plugin_free(plugin);
452 srcformat = tmpformat;
453 src_access = dst_access;
456 /* rate resampling */
457 if (!rate_match(srcformat.rate, dstformat.rate)) {
458 if (srcformat.format != SNDRV_PCM_FORMAT_S16) {
459 /* convert to S16 for resampling */
460 tmpformat.format = SNDRV_PCM_FORMAT_S16;
461 err = snd_pcm_plugin_build_linear(plug,
462 &srcformat, &tmpformat,
466 err = snd_pcm_plugin_append(plugin);
468 snd_pcm_plugin_free(plugin);
471 srcformat = tmpformat;
472 src_access = dst_access;
474 tmpformat.rate = dstformat.rate;
475 err = snd_pcm_plugin_build_rate(plug,
476 &srcformat, &tmpformat,
478 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
481 err = snd_pcm_plugin_append(plugin);
483 snd_pcm_plugin_free(plugin);
486 srcformat = tmpformat;
487 src_access = dst_access;
491 if (srcformat.format != dstformat.format) {
492 tmpformat.format = dstformat.format;
493 if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW ||
494 tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
495 err = snd_pcm_plugin_build_mulaw(plug,
496 &srcformat, &tmpformat,
499 else if (snd_pcm_format_linear(srcformat.format) &&
500 snd_pcm_format_linear(tmpformat.format)) {
501 err = snd_pcm_plugin_build_linear(plug,
502 &srcformat, &tmpformat,
507 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
510 err = snd_pcm_plugin_append(plugin);
512 snd_pcm_plugin_free(plugin);
515 srcformat = tmpformat;
516 src_access = dst_access;
519 /* channels extension */
520 if (srcformat.channels < dstformat.channels) {
521 tmpformat.channels = dstformat.channels;
522 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
523 pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
526 err = snd_pcm_plugin_append(plugin);
528 snd_pcm_plugin_free(plugin);
531 srcformat = tmpformat;
532 src_access = dst_access;
536 if (src_access != dst_access) {
537 err = snd_pcm_plugin_build_copy(plug,
541 pdprintf("interleave change (copy: returns %i)\n", err);
544 err = snd_pcm_plugin_append(plugin);
546 snd_pcm_plugin_free(plugin);
554 snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plug,
556 snd_pcm_uframes_t count,
557 struct snd_pcm_plugin_channel **channels)
559 struct snd_pcm_plugin *plugin;
560 struct snd_pcm_plugin_channel *v;
561 struct snd_pcm_plugin_format *format;
562 int width, nchannels, channel;
563 int stream = snd_pcm_plug_stream(plug);
565 if (snd_BUG_ON(!buf))
567 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
568 plugin = snd_pcm_plug_first(plug);
569 format = &plugin->src_format;
571 plugin = snd_pcm_plug_last(plug);
572 format = &plugin->dst_format;
574 v = plugin->buf_channels;
576 width = snd_pcm_format_physical_width(format->format);
579 nchannels = format->channels;
580 if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
581 format->channels > 1))
583 for (channel = 0; channel < nchannels; channel++, v++) {
586 v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE);
588 v->area.first = channel * width;
589 v->area.step = nchannels * width;
594 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)
596 struct snd_pcm_plugin *plugin, *next;
597 struct snd_pcm_plugin_channel *dst_channels;
599 snd_pcm_sframes_t frames = size;
601 plugin = snd_pcm_plug_first(plug);
607 snd_pcm_sframes_t frames1 = frames;
608 if (plugin->dst_frames) {
609 frames1 = plugin->dst_frames(plugin, frames);
613 err = next->client_channels(next, frames1, &dst_channels);
616 if (err != frames1) {
618 if (plugin->src_frames) {
619 frames = plugin->src_frames(plugin, frames1);
626 pdprintf("write plugin: %s, %li\n", plugin->name, frames);
627 frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
630 src_channels = dst_channels;
633 return calc_src_frames(plug, frames, true);
636 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)
638 struct snd_pcm_plugin *plugin, *next;
639 struct snd_pcm_plugin_channel *src_channels, *dst_channels;
640 snd_pcm_sframes_t frames = size;
643 frames = calc_src_frames(plug, frames, true);
648 plugin = snd_pcm_plug_first(plug);
649 while (plugin && frames > 0) {
652 err = plugin->client_channels(plugin, frames, &dst_channels);
657 dst_channels = dst_channels_final;
659 pdprintf("read plugin: %s, %li\n", plugin->name, frames);
660 frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
664 src_channels = dst_channels;
669 int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
670 size_t samples, snd_pcm_format_t format)
672 /* FIXME: sub byte resolution and odd dst_offset */
674 unsigned int dst_step;
676 const unsigned char *silence;
679 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
680 width = snd_pcm_format_physical_width(format);
683 if (dst_area->step == (unsigned int) width && width >= 8)
684 return snd_pcm_format_set_silence(format, dst, samples);
685 silence = snd_pcm_format_silence_64(format);
688 dst_step = dst_area->step / 8;
691 int dstbit = dst_area->first % 8;
692 int dstbit_step = dst_area->step % 8;
693 while (samples-- > 0) {
699 dstbit += dstbit_step;
707 while (samples-- > 0) {
708 memcpy(dst, silence, width);
715 int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_offset,
716 const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
717 size_t samples, snd_pcm_format_t format)
719 /* FIXME: sub byte resolution and odd dst_offset */
722 int src_step, dst_step;
723 src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8;
725 return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
726 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
729 width = snd_pcm_format_physical_width(format);
732 if (src_area->step == (unsigned int) width &&
733 dst_area->step == (unsigned int) width && width >= 8) {
734 size_t bytes = samples * width / 8;
735 memcpy(dst, src, bytes);
738 src_step = src_area->step / 8;
739 dst_step = dst_area->step / 8;
742 int srcbit = src_area->first % 8;
743 int srcbit_step = src_area->step % 8;
744 int dstbit = dst_area->first % 8;
745 int dstbit_step = dst_area->step % 8;
746 while (samples-- > 0) {
747 unsigned char srcval;
749 srcval = *src & 0x0f;
751 srcval = (*src & 0xf0) >> 4;
753 *dst = (*dst & 0xf0) | srcval;
755 *dst = (*dst & 0x0f) | (srcval << 4);
757 srcbit += srcbit_step;
763 dstbit += dstbit_step;
771 while (samples-- > 0) {
772 memcpy(dst, src, width);