• 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 "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 */
66 const char *_snd_module_pcm_adpcm = "";
67 #endif
68 
69 #ifndef DOC_HIDDEN
70 
71 typedef 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 
79 typedef 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 */
91 static const char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
92 
93 /* Second table lookup for Ima-ADPCM quantizer */
94 static 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 
adpcm_encoder(int sl,snd_pcm_adpcm_state_t * state)106 static 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 
adpcm_decoder(unsigned char code,snd_pcm_adpcm_state_t * state)167 static 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 
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)215 void 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 
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)268 void 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 
snd_pcm_adpcm_hw_refine_cprepare(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)323 static 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 
snd_pcm_adpcm_hw_refine_sprepare(snd_pcm_t * pcm,snd_pcm_hw_params_t * sparams)350 static 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 
snd_pcm_adpcm_hw_refine_schange(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams)362 static 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 
snd_pcm_adpcm_hw_refine_cchange(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams)380 static 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 
snd_pcm_adpcm_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)398 static 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 
snd_pcm_adpcm_hw_params(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)408 static 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 
snd_pcm_adpcm_hw_free(snd_pcm_t * pcm)448 static 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 
snd_pcm_adpcm_init(snd_pcm_t * pcm)456 static 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 
467 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)468 snd_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 
487 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)488 snd_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 
snd_pcm_adpcm_dump(snd_pcm_t * pcm,snd_output_t * out)507 static 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 
520 static 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  */
snd_pcm_adpcm_open(snd_pcm_t ** pcmp,const char * name,snd_pcm_format_t sformat,snd_pcm_t * slave,int close_slave)550 int 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 
593 This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples
594 from master Ima-ADPCM conversion PCM to given slave PCM. The channel count,
595 format and rate must match for both of them.
596 
597 \code
598 pcm.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  */
_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)633 int _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
680 SND_DLSYM_BUILD_VERSION(_snd_pcm_adpcm_open, SND_PCM_DLSYM_VERSION);
681 #endif
682