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