OSDN Git Service

Fix S24_BE format conversions
[android-x86/external-alsa-lib.git] / src / pcm / pcm_adpcm.c
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@suse.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@suse.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 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 <byteswap.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 char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
93
94 /* Second table lookup for Ima-ADPCM quantizer */
95 static 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
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
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
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
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
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
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
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         
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
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
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
449 static int snd_pcm_adpcm_hw_free(snd_pcm_t *pcm)
450 {
451         snd_pcm_adpcm_t *adpcm = pcm->private_data;
452         if (adpcm->states) {
453                 free(adpcm->states);
454                 adpcm->states = 0;
455         }
456         return snd_pcm_hw_free(adpcm->plug.gen.slave);
457 }
458
459 static int snd_pcm_adpcm_init(snd_pcm_t *pcm)
460 {
461         snd_pcm_adpcm_t *adpcm = pcm->private_data;
462         unsigned int k;
463         for (k = 0; k < pcm->channels; ++k) {
464                 adpcm->states[k].pred_val = 0;
465                 adpcm->states[k].step_idx = 0;
466         }
467         return 0;
468 }
469
470 static snd_pcm_uframes_t
471 snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
472                           const snd_pcm_channel_area_t *areas,
473                           snd_pcm_uframes_t offset,
474                           snd_pcm_uframes_t size,
475                           const snd_pcm_channel_area_t *slave_areas,
476                           snd_pcm_uframes_t slave_offset,
477                           snd_pcm_uframes_t *slave_sizep)
478 {
479         snd_pcm_adpcm_t *adpcm = pcm->private_data;
480         if (size > *slave_sizep)
481                 size = *slave_sizep;
482         adpcm->func(slave_areas, slave_offset,
483                     areas, offset, 
484                     pcm->channels, size,
485                     adpcm->getput_idx, adpcm->states);
486         *slave_sizep = size;
487         return size;
488 }
489
490 static snd_pcm_uframes_t
491 snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
492                          const snd_pcm_channel_area_t *areas,
493                          snd_pcm_uframes_t offset,
494                          snd_pcm_uframes_t size,
495                          const snd_pcm_channel_area_t *slave_areas,
496                          snd_pcm_uframes_t slave_offset,
497                          snd_pcm_uframes_t *slave_sizep)
498 {
499         snd_pcm_adpcm_t *adpcm = pcm->private_data;
500         if (size > *slave_sizep)
501                 size = *slave_sizep;
502         adpcm->func(areas, offset, 
503                     slave_areas, slave_offset,
504                     pcm->channels, size,
505                     adpcm->getput_idx, adpcm->states);
506         *slave_sizep = size;
507         return size;
508 }
509
510 static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, snd_output_t *out)
511 {
512         snd_pcm_adpcm_t *adpcm = pcm->private_data;
513         snd_output_printf(out, "Ima-ADPCM conversion PCM (%s)\n", 
514                 snd_pcm_format_name(adpcm->sformat));
515         if (pcm->setup) {
516                 snd_output_printf(out, "Its setup is:\n");
517                 snd_pcm_dump_setup(pcm, out);
518         }
519         snd_output_printf(out, "Slave: ");
520         snd_pcm_dump(adpcm->plug.gen.slave, out);
521 }
522
523 static snd_pcm_ops_t snd_pcm_adpcm_ops = {
524         .close = snd_pcm_generic_close,
525         .info = snd_pcm_generic_info,
526         .hw_refine = snd_pcm_adpcm_hw_refine,
527         .hw_params = snd_pcm_adpcm_hw_params,
528         .hw_free = snd_pcm_adpcm_hw_free,
529         .sw_params = snd_pcm_generic_sw_params,
530         .channel_info = snd_pcm_generic_channel_info,
531         .dump = snd_pcm_adpcm_dump,
532         .nonblock = snd_pcm_generic_nonblock,
533         .async = snd_pcm_generic_async,
534         .mmap = snd_pcm_generic_mmap,
535         .munmap = snd_pcm_generic_munmap,
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  */
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         snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0);
582         snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0);
583         *pcmp = pcm;
584
585         return 0;
586 }
587
588 /*! \page pcm_plugins
589
590 \section pcm_plugins_adpcm Plugin: Ima-ADPCM
591
592 This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples
593 from master Ima-ADPCM conversion PCM to given slave PCM. The channel count,
594 format and rate must match for both of them.
595
596 \code
597 pcm.name {
598         type adpcm              # Ima-ADPCM conversion PCM
599         slave STR               # Slave name
600         # or
601         slave {                 # Slave definition
602                 pcm STR         # Slave PCM name
603                 # or
604                 pcm { }         # Slave PCM definition
605                 format STR      # Slave format
606         }
607 }
608 \endcode
609
610 \subsection pcm_plugins_adpcm_funcref Function reference
611
612 <UL>
613   <LI>snd_pcm_adpcm_open()
614   <LI>_snd_pcm_adpcm_open()
615 </UL>
616
617 */
618
619 /**
620  * \brief Creates a new Ima-ADPCM conversion PCM
621  * \param pcmp Returns created PCM handle
622  * \param name Name of PCM
623  * \param root Root configuration node
624  * \param conf Configuration node with copy PCM description
625  * \param stream Stream type
626  * \param mode Stream mode
627  * \retval zero on success otherwise a negative error code
628  * \warning Using of this function might be dangerous in the sense
629  *          of compatibility reasons. The prototype might be freely
630  *          changed in future.
631  */
632 int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name,
633                         snd_config_t *root, snd_config_t *conf, 
634                         snd_pcm_stream_t stream, int mode)
635 {
636         snd_config_iterator_t i, next;
637         int err;
638         snd_pcm_t *spcm;
639         snd_config_t *slave = NULL, *sconf;
640         snd_pcm_format_t sformat;
641         snd_config_for_each(i, next, conf) {
642                 snd_config_t *n = snd_config_iterator_entry(i);
643                 const char *id;
644                 if (snd_config_get_id(n, &id) < 0)
645                         continue;
646                 if (snd_pcm_conf_generic_id(id))
647                         continue;
648                 if (strcmp(id, "slave") == 0) {
649                         slave = n;
650                         continue;
651                 }
652                 SNDERR("Unknown field %s", id);
653                 return -EINVAL;
654         }
655         if (!slave) {
656                 SNDERR("slave is not defined");
657                 return -EINVAL;
658         }
659         err = snd_pcm_slave_conf(root, slave, &sconf, 1,
660                                  SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
661         if (err < 0)
662                 return err;
663         if (snd_pcm_format_linear(sformat) != 1 &&
664             sformat != SND_PCM_FORMAT_IMA_ADPCM) {
665                 snd_config_delete(sconf);
666                 SNDERR("invalid slave format");
667                 return -EINVAL;
668         }
669         err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
670         snd_config_delete(sconf);
671         if (err < 0)
672                 return err;
673         err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1);
674         if (err < 0)
675                 snd_pcm_close(spcm);
676         return err;
677 }
678 #ifndef DOC_HIDDEN
679 SND_DLSYM_BUILD_VERSION(_snd_pcm_adpcm_open, SND_PCM_DLSYM_VERSION);
680 #endif