OSDN Git Service

Changed Jaroslav Kysela's e-mail from perex@suse.cz to perex@perex.cz
[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@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., 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         free(adpcm->states);
453         adpcm->states = NULL;
454         return snd_pcm_hw_free(adpcm->plug.gen.slave);
455 }
456
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
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
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
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 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 };
535
536 /**
537  * \brief Creates a new Ima-ADPCM conversion PCM
538  * \param pcmp Returns created PCM handle
539  * \param name Name of PCM
540  * \param sformat Slave (destination) format
541  * \param slave Slave PCM handle
542  * \param close_slave When set, the slave PCM handle is closed with copy PCM
543  * \retval zero on success otherwise a negative error code
544  * \warning Using of this function might be dangerous in the sense
545  *          of compatibility reasons. The prototype might be freely
546  *          changed in future.
547  */
548 int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave)
549 {
550         snd_pcm_t *pcm;
551         snd_pcm_adpcm_t *adpcm;
552         int err;
553         assert(pcmp && slave);
554         if (snd_pcm_format_linear(sformat) != 1 &&
555             sformat != SND_PCM_FORMAT_IMA_ADPCM)
556                 return -EINVAL;
557         adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
558         if (!adpcm) {
559                 return -ENOMEM;
560         }
561         adpcm->sformat = sformat;
562         snd_pcm_plugin_init(&adpcm->plug);
563         adpcm->plug.read = snd_pcm_adpcm_read_areas;
564         adpcm->plug.write = snd_pcm_adpcm_write_areas;
565         adpcm->plug.init = snd_pcm_adpcm_init;
566         adpcm->plug.gen.slave = slave;
567         adpcm->plug.gen.close_slave = close_slave;
568
569         err = snd_pcm_new(&pcm, SND_PCM_TYPE_ADPCM, name, slave->stream, slave->mode);
570         if (err < 0) {
571                 free(adpcm);
572                 return err;
573         }
574         pcm->ops = &snd_pcm_adpcm_ops;
575         pcm->fast_ops = &snd_pcm_plugin_fast_ops;
576         pcm->private_data = adpcm;
577         pcm->poll_fd = slave->poll_fd;
578         pcm->poll_events = slave->poll_events;
579         snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0);
580         snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0);
581         *pcmp = pcm;
582
583         return 0;
584 }
585
586 /*! \page pcm_plugins
587
588 \section pcm_plugins_adpcm Plugin: Ima-ADPCM
589
590 This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples
591 from master Ima-ADPCM conversion PCM to given slave PCM. The channel count,
592 format and rate must match for both of them.
593
594 \code
595 pcm.name {
596         type adpcm              # Ima-ADPCM conversion PCM
597         slave STR               # Slave name
598         # or
599         slave {                 # Slave definition
600                 pcm STR         # Slave PCM name
601                 # or
602                 pcm { }         # Slave PCM definition
603                 format STR      # Slave format
604         }
605 }
606 \endcode
607
608 \subsection pcm_plugins_adpcm_funcref Function reference
609
610 <UL>
611   <LI>snd_pcm_adpcm_open()
612   <LI>_snd_pcm_adpcm_open()
613 </UL>
614
615 */
616
617 /**
618  * \brief Creates a new Ima-ADPCM conversion PCM
619  * \param pcmp Returns created PCM handle
620  * \param name Name of PCM
621  * \param root Root configuration node
622  * \param conf Configuration node with copy PCM description
623  * \param stream Stream type
624  * \param mode Stream mode
625  * \retval zero on success otherwise a negative error code
626  * \warning Using of this function might be dangerous in the sense
627  *          of compatibility reasons. The prototype might be freely
628  *          changed in future.
629  */
630 int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name,
631                         snd_config_t *root, snd_config_t *conf, 
632                         snd_pcm_stream_t stream, int mode)
633 {
634         snd_config_iterator_t i, next;
635         int err;
636         snd_pcm_t *spcm;
637         snd_config_t *slave = NULL, *sconf;
638         snd_pcm_format_t sformat;
639         snd_config_for_each(i, next, conf) {
640                 snd_config_t *n = snd_config_iterator_entry(i);
641                 const char *id;
642                 if (snd_config_get_id(n, &id) < 0)
643                         continue;
644                 if (snd_pcm_conf_generic_id(id))
645                         continue;
646                 if (strcmp(id, "slave") == 0) {
647                         slave = n;
648                         continue;
649                 }
650                 SNDERR("Unknown field %s", id);
651                 return -EINVAL;
652         }
653         if (!slave) {
654                 SNDERR("slave is not defined");
655                 return -EINVAL;
656         }
657         err = snd_pcm_slave_conf(root, slave, &sconf, 1,
658                                  SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
659         if (err < 0)
660                 return err;
661         if (snd_pcm_format_linear(sformat) != 1 &&
662             sformat != SND_PCM_FORMAT_IMA_ADPCM) {
663                 snd_config_delete(sconf);
664                 SNDERR("invalid slave format");
665                 return -EINVAL;
666         }
667         err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
668         snd_config_delete(sconf);
669         if (err < 0)
670                 return err;
671         err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1);
672         if (err < 0)
673                 snd_pcm_close(spcm);
674         return err;
675 }
676 #ifndef DOC_HIDDEN
677 SND_DLSYM_BUILD_VERSION(_snd_pcm_adpcm_open, SND_PCM_DLSYM_VERSION);
678 #endif