• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /*
37 These routines convert 16 bit linear PCM samples to 4 bit ADPCM code
38 and vice versa. The ADPCM code used is the Intel/DVI ADPCM code which
39 is being recommended by the IMA Digital Audio Technical Working Group.
40 
41 The algorithm for this coder was taken from:
42 Proposal for Standardized Audio Interstreamge Formats,
43 IMA 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 "bswap.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 */
67 const char *_snd_module_pcm_adpcm = "";
68 #endif
69 
70 #ifndef DOC_HIDDEN
71 
72 typedef 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 
80 typedef 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 */
92 static const char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
93 
94 /* Second table lookup for Ima-ADPCM quantizer */
95 static 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 
adpcm_encoder(int sl,snd_pcm_adpcm_state_t * state)107 static 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 
adpcm_decoder(unsigned char code,snd_pcm_adpcm_state_t * state)168 static 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 
snd_pcm_adpcm_decode(const snd_pcm_channel_area_t * dst_areas,snd_pcm_uframes_t dst_offset,const snd_pcm_channel_area_t * src_areas,snd_pcm_uframes_t src_offset,unsigned int channels,snd_pcm_uframes_t frames,unsigned int putidx,snd_pcm_adpcm_state_t * states)216 void 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 
snd_pcm_adpcm_encode(const snd_pcm_channel_area_t * dst_areas,snd_pcm_uframes_t dst_offset,const snd_pcm_channel_area_t * src_areas,snd_pcm_uframes_t src_offset,unsigned int channels,snd_pcm_uframes_t frames,unsigned int getidx,snd_pcm_adpcm_state_t * states)269 void 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 
snd_pcm_adpcm_hw_refine_cprepare(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)324 static 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 
snd_pcm_adpcm_hw_refine_sprepare(snd_pcm_t * pcm,snd_pcm_hw_params_t * sparams)351 static 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 
snd_pcm_adpcm_hw_refine_schange(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams)363 static 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 
snd_pcm_adpcm_hw_refine_cchange(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams)381 static 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 
snd_pcm_adpcm_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)399 static 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 
snd_pcm_adpcm_hw_params(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)409 static 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 
snd_pcm_adpcm_hw_free(snd_pcm_t * pcm)449 static 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 
snd_pcm_adpcm_init(snd_pcm_t * pcm)457 static 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 
468 static snd_pcm_uframes_t
snd_pcm_adpcm_write_areas(snd_pcm_t * pcm,const snd_pcm_channel_area_t * areas,snd_pcm_uframes_t offset,snd_pcm_uframes_t size,const snd_pcm_channel_area_t * slave_areas,snd_pcm_uframes_t slave_offset,snd_pcm_uframes_t * slave_sizep)469 snd_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 
488 static snd_pcm_uframes_t
snd_pcm_adpcm_read_areas(snd_pcm_t * pcm,const snd_pcm_channel_area_t * areas,snd_pcm_uframes_t offset,snd_pcm_uframes_t size,const snd_pcm_channel_area_t * slave_areas,snd_pcm_uframes_t slave_offset,snd_pcm_uframes_t * slave_sizep)489 snd_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 
snd_pcm_adpcm_dump(snd_pcm_t * pcm,snd_output_t * out)508 static 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 
521 static 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 	.query_chmaps = snd_pcm_generic_query_chmaps,
535 	.get_chmap = snd_pcm_generic_get_chmap,
536 	.set_chmap = snd_pcm_generic_set_chmap,
537 };
538 
539 /**
540  * \brief Creates a new Ima-ADPCM conversion PCM
541  * \param pcmp Returns created PCM handle
542  * \param name Name of PCM
543  * \param sformat Slave (destination) format
544  * \param slave Slave PCM handle
545  * \param close_slave When set, the slave PCM handle is closed with copy PCM
546  * \retval zero on success otherwise a negative error code
547  * \warning Using of this function might be dangerous in the sense
548  *          of compatibility reasons. The prototype might be freely
549  *          changed in future.
550  */
snd_pcm_adpcm_open(snd_pcm_t ** pcmp,const char * name,snd_pcm_format_t sformat,snd_pcm_t * slave,int close_slave)551 int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave)
552 {
553 	snd_pcm_t *pcm;
554 	snd_pcm_adpcm_t *adpcm;
555 	int err;
556 	assert(pcmp && slave);
557 	if (snd_pcm_format_linear(sformat) != 1 &&
558 	    sformat != SND_PCM_FORMAT_IMA_ADPCM)
559 		return -EINVAL;
560 	adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
561 	if (!adpcm) {
562 		return -ENOMEM;
563 	}
564 	adpcm->sformat = sformat;
565 	snd_pcm_plugin_init(&adpcm->plug);
566 	adpcm->plug.read = snd_pcm_adpcm_read_areas;
567 	adpcm->plug.write = snd_pcm_adpcm_write_areas;
568 	adpcm->plug.init = snd_pcm_adpcm_init;
569 	adpcm->plug.gen.slave = slave;
570 	adpcm->plug.gen.close_slave = close_slave;
571 
572 	err = snd_pcm_new(&pcm, SND_PCM_TYPE_ADPCM, name, slave->stream, slave->mode);
573 	if (err < 0) {
574 		free(adpcm);
575 		return err;
576 	}
577 	pcm->ops = &snd_pcm_adpcm_ops;
578 	pcm->fast_ops = &snd_pcm_plugin_fast_ops;
579 	pcm->private_data = adpcm;
580 	pcm->poll_fd = slave->poll_fd;
581 	pcm->poll_events = slave->poll_events;
582 	pcm->tstamp_type = slave->tstamp_type;
583 	snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0);
584 	snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0);
585 	*pcmp = pcm;
586 
587 	return 0;
588 }
589 
590 /*! \page pcm_plugins
591 
592 \section pcm_plugins_adpcm Plugin: Ima-ADPCM
593 
594 This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples
595 from master Ima-ADPCM conversion PCM to given slave PCM. The channel count,
596 format and rate must match for both of them.
597 
598 \code
599 pcm.name {
600         type adpcm              # Ima-ADPCM conversion PCM
601         slave STR               # Slave name
602         # or
603         slave {                 # Slave definition
604                 pcm STR         # Slave PCM name
605                 # or
606                 pcm { }         # Slave PCM definition
607                 format STR      # Slave format
608         }
609 }
610 \endcode
611 
612 \subsection pcm_plugins_adpcm_funcref Function reference
613 
614 <UL>
615   <LI>snd_pcm_adpcm_open()
616   <LI>_snd_pcm_adpcm_open()
617 </UL>
618 
619 */
620 
621 /**
622  * \brief Creates a new Ima-ADPCM conversion PCM
623  * \param pcmp Returns created PCM handle
624  * \param name Name of PCM
625  * \param root Root configuration node
626  * \param conf Configuration node with copy PCM description
627  * \param stream Stream type
628  * \param mode Stream mode
629  * \retval zero on success otherwise a negative error code
630  * \warning Using of this function might be dangerous in the sense
631  *          of compatibility reasons. The prototype might be freely
632  *          changed in future.
633  */
_snd_pcm_adpcm_open(snd_pcm_t ** pcmp,const char * name,snd_config_t * root,snd_config_t * conf,snd_pcm_stream_t stream,int mode)634 int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name,
635 			snd_config_t *root, snd_config_t *conf,
636 			snd_pcm_stream_t stream, int mode)
637 {
638 	snd_config_iterator_t i, next;
639 	int err;
640 	snd_pcm_t *spcm;
641 	snd_config_t *slave = NULL, *sconf;
642 	snd_pcm_format_t sformat;
643 	snd_config_for_each(i, next, conf) {
644 		snd_config_t *n = snd_config_iterator_entry(i);
645 		const char *id;
646 		if (snd_config_get_id(n, &id) < 0)
647 			continue;
648 		if (snd_pcm_conf_generic_id(id))
649 			continue;
650 		if (strcmp(id, "slave") == 0) {
651 			slave = n;
652 			continue;
653 		}
654 		SNDERR("Unknown field %s", id);
655 		return -EINVAL;
656 	}
657 	if (!slave) {
658 		SNDERR("slave is not defined");
659 		return -EINVAL;
660 	}
661 	err = snd_pcm_slave_conf(root, slave, &sconf, 1,
662 				 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
663 	if (err < 0)
664 		return err;
665 	if (snd_pcm_format_linear(sformat) != 1 &&
666 	    sformat != SND_PCM_FORMAT_IMA_ADPCM) {
667 	    	snd_config_delete(sconf);
668 		SNDERR("invalid slave format");
669 		return -EINVAL;
670 	}
671 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
672 	snd_config_delete(sconf);
673 	if (err < 0)
674 		return err;
675 	err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1);
676 	if (err < 0)
677 		snd_pcm_close(spcm);
678 	return err;
679 }
680 #ifndef DOC_HIDDEN
681 SND_DLSYM_BUILD_VERSION(_snd_pcm_adpcm_open, SND_PCM_DLSYM_VERSION);
682 #endif
683