1/**
2 * \file pcm/pcm_adpcm.c
3 * \ingroup PCM_Plugins
4 * \brief PCM Ima-ADPCM Conversion Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \author Uros Bizjak <uros@kss-loka.si>
7 * \author Jaroslav Kysela <perex@perex.cz>
8 * \date 2000-2001
9 */
10/*
11 *  PCM - Ima-ADPCM conversion
12 *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
13 *  Copyright (c) 1999 by Uros Bizjak <uros@kss-loka.si>
14 *                        Jaroslav Kysela <perex@perex.cz>
15 *
16 *  Based on Version 1.2, 18-Dec-92 implementation of Intel/DVI ADPCM code
17 *  by Jack Jansen, CWI, Amsterdam <Jack.Jansen@cwi.nl>, Copyright 1992
18 *  by Stichting Mathematisch Centrum, Amsterdam, The Netherlands.
19 *
20 *   This library is free software; you can redistribute it and/or modify
21 *   it under the terms of the GNU Lesser General Public License as
22 *   published by the Free Software Foundation; either version 2.1 of
23 *   the License, or (at your option) any later version.
24 *
25 *   This program is distributed in the hope that it will be useful,
26 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
27 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28 *   GNU Lesser General Public License for more details.
29 *
30 *   You should have received a copy of the GNU Lesser General Public
31 *   License along with this library; if not, write to the Free Software
32 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
33 *
34 */
35
36/*
37These routines convert 16 bit linear PCM samples to 4 bit ADPCM code
38and vice versa. The ADPCM code used is the Intel/DVI ADPCM code which
39is being recommended by the IMA Digital Audio Technical Working Group.
40
41The algorithm for this coder was taken from:
42Proposal for Standardized Audio Interstreamge Formats,
43IMA compatibility project proceedings, Vol 2, Issue 2, May 1992.
44
45- No, this is *not* a G.721 coder/decoder. The algorithm used by G.721
46  is very complicated, requiring oodles of floating-point ops per
47  sample (resulting in very poor performance). I have not done any
48  tests myself but various people have assured my that 721 quality is
49  actually lower than DVI quality.
50
51- No, it probably isn't a RIFF ADPCM decoder either. Trying to decode
52  RIFF ADPCM with these routines seems to result in something
53  recognizable but very distorted.
54
55- No, it is not a CDROM-XA coder either, as far as I know. I haven't
56  come across a good description of XA yet.
57 */
58
59#include <byteswap.h>
60#include "pcm_local.h"
61#include "pcm_plugin.h"
62
63#include "plugin_ops.h"
64
65#ifndef PIC
66/* entry for static linking */
67const char *_snd_module_pcm_adpcm = "";
68#endif
69
70#ifndef DOC_HIDDEN
71
72typedef void (*adpcm_f)(const snd_pcm_channel_area_t *dst_areas,
73			snd_pcm_uframes_t dst_offset,
74			const snd_pcm_channel_area_t *src_areas,
75			snd_pcm_uframes_t src_offset,
76			unsigned int channels, snd_pcm_uframes_t frames,
77			unsigned int getputidx,
78			snd_pcm_adpcm_state_t *states);
79
80typedef struct {
81	/* This field need to be the first */
82	snd_pcm_plugin_t plug;
83	unsigned int getput_idx;
84	adpcm_f func;
85	snd_pcm_format_t sformat;
86	snd_pcm_adpcm_state_t *states;
87} snd_pcm_adpcm_t;
88
89#endif
90
91/* First table lookup for Ima-ADPCM quantizer */
92static const char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
93
94/* Second table lookup for Ima-ADPCM quantizer */
95static const short StepSize[89] = {
96	7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
97	19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
98	50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
99	130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
100	337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
101	876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
102	2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
103	5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
104	15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
105};
106
107static char adpcm_encoder(int sl, snd_pcm_adpcm_state_t * state)
108{
109	short diff;		/* Difference between sl and predicted sample */
110	short pred_diff;	/* Predicted difference to next sample */
111
112	unsigned char sign;	/* sign of diff */
113	short step;		/* holds previous StepSize value */
114	unsigned char adjust_idx;	/* Index to IndexAdjust lookup table */
115
116	int i;
117
118	/* Compute difference to previous predicted value */
119	diff = sl - state->pred_val;
120	sign = (diff < 0) ? 0x8 : 0x0;
121	if (sign) {
122		diff = -diff;
123	}
124
125	/*
126	 * This code *approximately* computes:
127	 *    adjust_idx = diff * 4 / step;
128	 *    pred_diff = (adjust_idx + 0.5) * step / 4;
129	 *
130	 * But in shift step bits are dropped. The net result of this is
131	 * that even if you have fast mul/div hardware you cannot put it to
132	 * good use since the fix-up would be too expensive.
133	 */
134
135	step = StepSize[state->step_idx];
136
137	/* Divide and clamp */
138	pred_diff = step >> 3;
139	for (adjust_idx = 0, i = 0x4; i; i >>= 1, step >>= 1) {
140		if (diff >= step) {
141			adjust_idx |= i;
142			diff -= step;
143			pred_diff += step;
144		}
145	}
146
147	/* Update and clamp previous predicted value */
148	state->pred_val += sign ? -pred_diff : pred_diff;
149
150	if (state->pred_val > 32767) {
151		state->pred_val = 32767;
152	} else if (state->pred_val < -32768) {
153		state->pred_val = -32768;
154	}
155
156	/* Update and clamp StepSize lookup table index */
157	state->step_idx += IndexAdjust[adjust_idx];
158
159	if (state->step_idx < 0) {
160		state->step_idx = 0;
161	} else if (state->step_idx > 88) {
162		state->step_idx = 88;
163	}
164	return (sign | adjust_idx);
165}
166
167
168static int adpcm_decoder(unsigned char code, snd_pcm_adpcm_state_t * state)
169{
170	short pred_diff;	/* Predicted difference to next sample */
171	short step;		/* holds previous StepSize value */
172	char sign;
173
174	int i;
175
176	/* Separate sign and magnitude */
177	sign = code & 0x8;
178	code &= 0x7;
179
180	/*
181	 * Computes pred_diff = (code + 0.5) * step / 4,
182	 * but see comment in adpcm_coder.
183	 */
184
185	step = StepSize[state->step_idx];
186
187	/* Compute difference and new predicted value */
188	pred_diff = step >> 3;
189	for (i = 0x4; i; i >>= 1, step >>= 1) {
190		if (code & i) {
191			pred_diff += step;
192		}
193	}
194	state->pred_val += (sign) ? -pred_diff : pred_diff;
195
196	/* Clamp output value */
197	if (state->pred_val > 32767) {
198		state->pred_val = 32767;
199	} else if (state->pred_val < -32768) {
200		state->pred_val = -32768;
201	}
202
203	/* Find new StepSize index value */
204	state->step_idx += IndexAdjust[code];
205
206	if (state->step_idx < 0) {
207		state->step_idx = 0;
208	} else if (state->step_idx > 88) {
209		state->step_idx = 88;
210	}
211	return (state->pred_val);
212}
213
214#ifndef DOC_HIDDEN
215
216void snd_pcm_adpcm_decode(const snd_pcm_channel_area_t *dst_areas,
217			  snd_pcm_uframes_t dst_offset,
218			  const snd_pcm_channel_area_t *src_areas,
219			  snd_pcm_uframes_t src_offset,
220			  unsigned int channels, snd_pcm_uframes_t frames,
221			  unsigned int putidx,
222			  snd_pcm_adpcm_state_t *states)
223{
224#define PUT16_LABELS
225#include "plugin_ops.h"
226#undef PUT16_LABELS
227	void *put = put16_labels[putidx];
228	unsigned int channel;
229	for (channel = 0; channel < channels; ++channel, ++states) {
230		const char *src;
231		int srcbit;
232		char *dst;
233		int src_step, srcbit_step, dst_step;
234		snd_pcm_uframes_t frames1;
235		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
236		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
237		srcbit = src_area->first + src_area->step * src_offset;
238		src = (const char *) src_area->addr + srcbit / 8;
239		srcbit %= 8;
240		src_step = src_area->step / 8;
241		srcbit_step = src_area->step % 8;
242		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
243		dst_step = snd_pcm_channel_area_step(dst_area);
244		frames1 = frames;
245		while (frames1-- > 0) {
246			int16_t sample;
247			unsigned char v;
248			if (srcbit)
249				v = *src & 0x0f;
250			else
251				v = (*src >> 4) & 0x0f;
252			sample = adpcm_decoder(v, states);
253			goto *put;
254#define PUT16_END after
255#include "plugin_ops.h"
256#undef PUT16_END
257		after:
258			src += src_step;
259			srcbit += srcbit_step;
260			if (srcbit == 8) {
261				src++;
262				srcbit = 0;
263			}
264			dst += dst_step;
265		}
266	}
267}
268
269void snd_pcm_adpcm_encode(const snd_pcm_channel_area_t *dst_areas,
270			  snd_pcm_uframes_t dst_offset,
271			  const snd_pcm_channel_area_t *src_areas,
272			  snd_pcm_uframes_t src_offset,
273			  unsigned int channels, snd_pcm_uframes_t frames,
274			  unsigned int getidx,
275			  snd_pcm_adpcm_state_t *states)
276{
277#define GET16_LABELS
278#include "plugin_ops.h"
279#undef GET16_LABELS
280	void *get = get16_labels[getidx];
281	unsigned int channel;
282	int16_t sample = 0;
283	for (channel = 0; channel < channels; ++channel, ++states) {
284		const char *src;
285		char *dst;
286		int dstbit;
287		int src_step, dst_step, dstbit_step;
288		snd_pcm_uframes_t frames1;
289		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
290		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
291		src = snd_pcm_channel_area_addr(src_area, src_offset);
292		src_step = snd_pcm_channel_area_step(src_area);
293		dstbit = dst_area->first + dst_area->step * dst_offset;
294		dst = (char *) dst_area->addr + dstbit / 8;
295		dstbit %= 8;
296		dst_step = dst_area->step / 8;
297		dstbit_step = dst_area->step % 8;
298		frames1 = frames;
299		while (frames1-- > 0) {
300			int v;
301			goto *get;
302#define GET16_END after
303#include "plugin_ops.h"
304#undef GET16_END
305		after:
306			v = adpcm_encoder(sample, states);
307			if (dstbit)
308				*dst = (*dst & 0xf0) | v;
309			else
310				*dst = (*dst & 0x0f) | (v << 4);
311			src += src_step;
312			dst += dst_step;
313			dstbit += dstbit_step;
314			if (dstbit == 8) {
315				dst++;
316				dstbit = 0;
317			}
318		}
319	}
320}
321
322#endif
323
324static int snd_pcm_adpcm_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
325{
326	snd_pcm_adpcm_t *adpcm = pcm->private_data;
327	int err;
328	snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
329	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
330					 &access_mask);
331	if (err < 0)
332		return err;
333	if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
334		snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR };
335		err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
336						 &format_mask);
337	} else {
338		err = _snd_pcm_hw_params_set_format(params,
339						   SND_PCM_FORMAT_IMA_ADPCM);
340	}
341	if (err < 0)
342		return err;
343	err = _snd_pcm_hw_params_set_subformat(params,
344					       SND_PCM_SUBFORMAT_STD);
345	if (err < 0)
346		return err;
347	params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
348	return 0;
349}
350
351static int snd_pcm_adpcm_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
352{
353	snd_pcm_adpcm_t *adpcm = pcm->private_data;
354	snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
355	_snd_pcm_hw_params_any(sparams);
356	_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
357				   &saccess_mask);
358	_snd_pcm_hw_params_set_format(sparams, adpcm->sformat);
359	_snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
360	return 0;
361}
362
363static int snd_pcm_adpcm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
364					    snd_pcm_hw_params_t *sparams)
365{
366	int err;
367	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
368			      SND_PCM_HW_PARBIT_RATE |
369			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
370			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
371			      SND_PCM_HW_PARBIT_PERIODS |
372			      SND_PCM_HW_PARBIT_PERIOD_TIME |
373			      SND_PCM_HW_PARBIT_BUFFER_TIME |
374			      SND_PCM_HW_PARBIT_TICK_TIME);
375	err = _snd_pcm_hw_params_refine(sparams, links, params);
376	if (err < 0)
377		return err;
378	return 0;
379}
380
381static int snd_pcm_adpcm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
382					    snd_pcm_hw_params_t *sparams)
383{
384	int err;
385	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
386			      SND_PCM_HW_PARBIT_RATE |
387			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
388			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
389			      SND_PCM_HW_PARBIT_PERIODS |
390			      SND_PCM_HW_PARBIT_PERIOD_TIME |
391			      SND_PCM_HW_PARBIT_BUFFER_TIME |
392			      SND_PCM_HW_PARBIT_TICK_TIME);
393	err = _snd_pcm_hw_params_refine(params, links, sparams);
394	if (err < 0)
395		return err;
396	return 0;
397}
398
399static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
400{
401	return snd_pcm_hw_refine_slave(pcm, params,
402				       snd_pcm_adpcm_hw_refine_cprepare,
403				       snd_pcm_adpcm_hw_refine_cchange,
404				       snd_pcm_adpcm_hw_refine_sprepare,
405				       snd_pcm_adpcm_hw_refine_schange,
406				       snd_pcm_generic_hw_refine);
407}
408
409static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
410{
411	snd_pcm_adpcm_t *adpcm = pcm->private_data;
412	snd_pcm_format_t format;
413	int err = snd_pcm_hw_params_slave(pcm, params,
414					  snd_pcm_adpcm_hw_refine_cchange,
415					  snd_pcm_adpcm_hw_refine_sprepare,
416					  snd_pcm_adpcm_hw_refine_schange,
417					  snd_pcm_generic_hw_params);
418	if (err < 0)
419		return err;
420
421	err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format);
422	if (err < 0)
423		return err;
424
425	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
426		if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
427			adpcm->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S16);
428			adpcm->func = snd_pcm_adpcm_encode;
429		} else {
430			adpcm->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, adpcm->sformat);
431			adpcm->func = snd_pcm_adpcm_decode;
432		}
433	} else {
434		if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
435			adpcm->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, format);
436			adpcm->func = snd_pcm_adpcm_decode;
437		} else {
438			adpcm->getput_idx = snd_pcm_linear_get_index(adpcm->sformat, SND_PCM_FORMAT_S16);
439			adpcm->func = snd_pcm_adpcm_encode;
440		}
441	}
442	assert(!adpcm->states);
443	adpcm->states = malloc(adpcm->plug.gen.slave->channels * sizeof(*adpcm->states));
444	if (adpcm->states == NULL)
445		return -ENOMEM;
446	return 0;
447}
448
449static int snd_pcm_adpcm_hw_free(snd_pcm_t *pcm)
450{
451	snd_pcm_adpcm_t *adpcm = pcm->private_data;
452	free(adpcm->states);
453	adpcm->states = NULL;
454	return snd_pcm_hw_free(adpcm->plug.gen.slave);
455}
456
457static int snd_pcm_adpcm_init(snd_pcm_t *pcm)
458{
459	snd_pcm_adpcm_t *adpcm = pcm->private_data;
460	unsigned int k;
461	for (k = 0; k < pcm->channels; ++k) {
462		adpcm->states[k].pred_val = 0;
463		adpcm->states[k].step_idx = 0;
464	}
465	return 0;
466}
467
468static snd_pcm_uframes_t
469snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
470			  const snd_pcm_channel_area_t *areas,
471			  snd_pcm_uframes_t offset,
472			  snd_pcm_uframes_t size,
473			  const snd_pcm_channel_area_t *slave_areas,
474			  snd_pcm_uframes_t slave_offset,
475			  snd_pcm_uframes_t *slave_sizep)
476{
477	snd_pcm_adpcm_t *adpcm = pcm->private_data;
478	if (size > *slave_sizep)
479		size = *slave_sizep;
480	adpcm->func(slave_areas, slave_offset,
481		    areas, offset,
482		    pcm->channels, size,
483		    adpcm->getput_idx, adpcm->states);
484	*slave_sizep = size;
485	return size;
486}
487
488static snd_pcm_uframes_t
489snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
490			 const snd_pcm_channel_area_t *areas,
491			 snd_pcm_uframes_t offset,
492			 snd_pcm_uframes_t size,
493			 const snd_pcm_channel_area_t *slave_areas,
494			 snd_pcm_uframes_t slave_offset,
495			 snd_pcm_uframes_t *slave_sizep)
496{
497	snd_pcm_adpcm_t *adpcm = pcm->private_data;
498	if (size > *slave_sizep)
499		size = *slave_sizep;
500	adpcm->func(areas, offset,
501		    slave_areas, slave_offset,
502		    pcm->channels, size,
503		    adpcm->getput_idx, adpcm->states);
504	*slave_sizep = size;
505	return size;
506}
507
508static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, snd_output_t *out)
509{
510	snd_pcm_adpcm_t *adpcm = pcm->private_data;
511	snd_output_printf(out, "Ima-ADPCM conversion PCM (%s)\n",
512		snd_pcm_format_name(adpcm->sformat));
513	if (pcm->setup) {
514		snd_output_printf(out, "Its setup is:\n");
515		snd_pcm_dump_setup(pcm, out);
516	}
517	snd_output_printf(out, "Slave: ");
518	snd_pcm_dump(adpcm->plug.gen.slave, out);
519}
520
521static const snd_pcm_ops_t snd_pcm_adpcm_ops = {
522	.close = snd_pcm_generic_close,
523	.info = snd_pcm_generic_info,
524	.hw_refine = snd_pcm_adpcm_hw_refine,
525	.hw_params = snd_pcm_adpcm_hw_params,
526	.hw_free = snd_pcm_adpcm_hw_free,
527	.sw_params = snd_pcm_generic_sw_params,
528	.channel_info = snd_pcm_generic_channel_info,
529	.dump = snd_pcm_adpcm_dump,
530	.nonblock = snd_pcm_generic_nonblock,
531	.async = snd_pcm_generic_async,
532	.mmap = snd_pcm_generic_mmap,
533	.munmap = snd_pcm_generic_munmap,
534};
535
536/**
537 * \brief Creates a new Ima-ADPCM conversion PCM
538 * \param pcmp Returns created PCM handle
539 * \param name Name of PCM
540 * \param sformat Slave (destination) format
541 * \param slave Slave PCM handle
542 * \param close_slave When set, the slave PCM handle is closed with copy PCM
543 * \retval zero on success otherwise a negative error code
544 * \warning Using of this function might be dangerous in the sense
545 *          of compatibility reasons. The prototype might be freely
546 *          changed in future.
547 */
548int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave)
549{
550	snd_pcm_t *pcm;
551	snd_pcm_adpcm_t *adpcm;
552	int err;
553	assert(pcmp && slave);
554	if (snd_pcm_format_linear(sformat) != 1 &&
555	    sformat != SND_PCM_FORMAT_IMA_ADPCM)
556		return -EINVAL;
557	adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
558	if (!adpcm) {
559		return -ENOMEM;
560	}
561	adpcm->sformat = sformat;
562	snd_pcm_plugin_init(&adpcm->plug);
563	adpcm->plug.read = snd_pcm_adpcm_read_areas;
564	adpcm->plug.write = snd_pcm_adpcm_write_areas;
565	adpcm->plug.init = snd_pcm_adpcm_init;
566	adpcm->plug.gen.slave = slave;
567	adpcm->plug.gen.close_slave = close_slave;
568
569	err = snd_pcm_new(&pcm, SND_PCM_TYPE_ADPCM, name, slave->stream, slave->mode);
570	if (err < 0) {
571		free(adpcm);
572		return err;
573	}
574	pcm->ops = &snd_pcm_adpcm_ops;
575	pcm->fast_ops = &snd_pcm_plugin_fast_ops;
576	pcm->private_data = adpcm;
577	pcm->poll_fd = slave->poll_fd;
578	pcm->poll_events = slave->poll_events;
579	pcm->monotonic = slave->monotonic;
580	snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0);
581	snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0);
582	*pcmp = pcm;
583
584	return 0;
585}
586
587/*! \page pcm_plugins
588
589\section pcm_plugins_adpcm Plugin: Ima-ADPCM
590
591This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples
592from master Ima-ADPCM conversion PCM to given slave PCM. The channel count,
593format and rate must match for both of them.
594
595\code
596pcm.name {
597        type adpcm              # Ima-ADPCM conversion PCM
598        slave STR               # Slave name
599        # or
600        slave {                 # Slave definition
601                pcm STR         # Slave PCM name
602                # or
603                pcm { }         # Slave PCM definition
604                format STR      # Slave format
605        }
606}
607\endcode
608
609\subsection pcm_plugins_adpcm_funcref Function reference
610
611<UL>
612  <LI>snd_pcm_adpcm_open()
613  <LI>_snd_pcm_adpcm_open()
614</UL>
615
616*/
617
618/**
619 * \brief Creates a new Ima-ADPCM conversion PCM
620 * \param pcmp Returns created PCM handle
621 * \param name Name of PCM
622 * \param root Root configuration node
623 * \param conf Configuration node with copy PCM description
624 * \param stream Stream type
625 * \param mode Stream mode
626 * \retval zero on success otherwise a negative error code
627 * \warning Using of this function might be dangerous in the sense
628 *          of compatibility reasons. The prototype might be freely
629 *          changed in future.
630 */
631int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name,
632			snd_config_t *root, snd_config_t *conf,
633			snd_pcm_stream_t stream, int mode)
634{
635	snd_config_iterator_t i, next;
636	int err;
637	snd_pcm_t *spcm;
638	snd_config_t *slave = NULL, *sconf;
639	snd_pcm_format_t sformat;
640	snd_config_for_each(i, next, conf) {
641		snd_config_t *n = snd_config_iterator_entry(i);
642		const char *id;
643		if (snd_config_get_id(n, &id) < 0)
644			continue;
645		if (snd_pcm_conf_generic_id(id))
646			continue;
647		if (strcmp(id, "slave") == 0) {
648			slave = n;
649			continue;
650		}
651		SNDERR("Unknown field %s", id);
652		return -EINVAL;
653	}
654	if (!slave) {
655		SNDERR("slave is not defined");
656		return -EINVAL;
657	}
658	err = snd_pcm_slave_conf(root, slave, &sconf, 1,
659				 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
660	if (err < 0)
661		return err;
662	if (snd_pcm_format_linear(sformat) != 1 &&
663	    sformat != SND_PCM_FORMAT_IMA_ADPCM) {
664	    	snd_config_delete(sconf);
665		SNDERR("invalid slave format");
666		return -EINVAL;
667	}
668	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
669	snd_config_delete(sconf);
670	if (err < 0)
671		return err;
672	err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1);
673	if (err < 0)
674		snd_pcm_close(spcm);
675	return err;
676}
677#ifndef DOC_HIDDEN
678SND_DLSYM_BUILD_VERSION(_snd_pcm_adpcm_open, SND_PCM_DLSYM_VERSION);
679#endif
680