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