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