OSDN Git Service

Added I/O classes
[android-x86/external-alsa-lib.git] / src / pcm / pcm_adpcm.c
1 /*
2  *  PCM - Ima-ADPC conversion
3  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
4  *  Copyright (c) 1999 by Uros Bizjak <uros@kss-loka.si>
5  *                        Jaroslav Kysela <perex@suse.cz>
6  *
7  *  Based on Version 1.2, 18-Dec-92 implementation of Intel/DVI ADPCM code
8  *  by Jack Jansen, CWI, Amsterdam <Jack.Jansen@cwi.nl>, Copyright 1992
9  *  by Stichting Mathematisch Centrum, Amsterdam, The Netherlands.
10  *
11  *   This library is free software; you can redistribute it and/or modify
12  *   it under the terms of the GNU Library General Public License as
13  *   published by the Free Software Foundation; either version 2 of
14  *   the License, or (at your option) any later version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU Library General Public License for more details.
20  *
21  *   You should have received a copy of the GNU Library General Public
22  *   License along with this library; if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  */
26   
27 /*
28 These routines convert 16 bit linear PCM samples to 4 bit ADPCM code
29 and vice versa. The ADPCM code used is the Intel/DVI ADPCM code which
30 is being recommended by the IMA Digital Audio Technical Working Group.
31
32 The algorithm for this coder was taken from:
33 Proposal for Standardized Audio Interstreamge Formats,
34 IMA compatability project proceedings, Vol 2, Issue 2, May 1992.
35
36 - No, this is *not* a G.721 coder/decoder. The algorithm used by G.721
37   is very complicated, requiring oodles of floating-point ops per
38   sample (resulting in very poor performance). I have not done any
39   tests myself but various people have assured my that 721 quality is
40   actually lower than DVI quality.
41
42 - No, it probably isn't a RIFF ADPCM decoder either. Trying to decode
43   RIFF ADPCM with these routines seems to result in something
44   recognizable but very distorted.
45
46 - No, it is not a CDROM-XA coder either, as far as I know. I haven't
47   come across a good description of XA yet.
48  */
49
50 #include <byteswap.h>
51 #include "pcm_local.h"
52 #include "pcm_plugin.h"
53
54 typedef struct {
55         int pred_val;           /* Calculated predicted value */
56         int step_idx;           /* Previous StepSize lookup index */
57 } adpcm_state_t;
58
59 typedef void (*adpcm_f)(const snd_pcm_channel_area_t *src_areas,
60                         snd_pcm_uframes_t src_offset,
61                         const snd_pcm_channel_area_t *dst_areas,
62                         snd_pcm_uframes_t dst_offset,
63                         unsigned int channels, snd_pcm_uframes_t frames, int getputidx,
64                         adpcm_state_t *states);
65
66 typedef struct {
67         /* This field need to be the first */
68         snd_pcm_plugin_t plug;
69         int getput_idx;
70         adpcm_f func;
71         int sformat;
72         adpcm_state_t *states;
73 } snd_pcm_adpcm_t;
74
75 /* First table lookup for Ima-ADPCM quantizer */
76 static char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
77
78 /* Second table lookup for Ima-ADPCM quantizer */
79 static short StepSize[89] = {
80         7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
81         19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
82         50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
83         130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
84         337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
85         876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
86         2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
87         5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
88         15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
89 };
90
91 static char adpcm_encoder(int sl, adpcm_state_t * state)
92 {
93         short diff;             /* Difference between sl and predicted sample */
94         short pred_diff;        /* Predicted difference to next sample */
95
96         unsigned char sign;     /* sign of diff */
97         short step;             /* holds previous StepSize value */
98         unsigned char adjust_idx;       /* Index to IndexAdjust lookup table */
99
100         int i;
101
102         /* Compute difference to previous predicted value */
103         diff = sl - state->pred_val;
104         sign = (diff < 0) ? 0x8 : 0x0;
105         if (sign) {
106                 diff = -diff;
107         }
108
109         /*
110          * This code *approximately* computes:
111          *    adjust_idx = diff * 4 / step;
112          *    pred_diff = (adjust_idx + 0.5) * step / 4;
113          *
114          * But in shift step bits are dropped. The net result of this is
115          * that even if you have fast mul/div hardware you cannot put it to
116          * good use since the fixup would be too expensive.
117          */
118
119         step = StepSize[state->step_idx];
120
121         /* Divide and clamp */
122         pred_diff = step >> 3;
123         for (adjust_idx = 0, i = 0x4; i; i >>= 1, step >>= 1) {
124                 if (diff >= step) {
125                         adjust_idx |= i;
126                         diff -= step;
127                         pred_diff += step;
128                 }
129         }
130
131         /* Update and clamp previous predicted value */
132         state->pred_val += sign ? -pred_diff : pred_diff;
133
134         if (state->pred_val > 32767) {
135                 state->pred_val = 32767;
136         } else if (state->pred_val < -32768) {
137                 state->pred_val = -32768;
138         }
139
140         /* Update and clamp StepSize lookup table index */
141         state->step_idx += IndexAdjust[adjust_idx];
142
143         if (state->step_idx < 0) {
144                 state->step_idx = 0;
145         } else if (state->step_idx > 88) {
146                 state->step_idx = 88;
147         }
148         return (sign | adjust_idx);
149 }
150
151
152 static int adpcm_decoder(unsigned char code, adpcm_state_t * state)
153 {
154         short pred_diff;        /* Predicted difference to next sample */
155         short step;             /* holds previous StepSize value */
156         char sign;
157
158         int i;
159
160         /* Separate sign and magnitude */
161         sign = code & 0x8;
162         code &= 0x7;
163
164         /*
165          * Computes pred_diff = (code + 0.5) * step / 4,
166          * but see comment in adpcm_coder.
167          */
168
169         step = StepSize[state->step_idx];
170
171         /* Compute difference and new predicted value */
172         pred_diff = step >> 3;
173         for (i = 0x4; i; i >>= 1, step >>= 1) {
174                 if (code & i) {
175                         pred_diff += step;
176                 }
177         }
178         state->pred_val += (sign) ? -pred_diff : pred_diff;
179
180         /* Clamp output value */
181         if (state->pred_val > 32767) {
182                 state->pred_val = 32767;
183         } else if (state->pred_val < -32768) {
184                 state->pred_val = -32768;
185         }
186
187         /* Find new StepSize index value */
188         state->step_idx += IndexAdjust[code];
189
190         if (state->step_idx < 0) {
191                 state->step_idx = 0;
192         } else if (state->step_idx > 88) {
193                 state->step_idx = 88;
194         }
195         return (state->pred_val);
196 }
197
198 static void adpcm_decode(const snd_pcm_channel_area_t *src_areas,
199                          snd_pcm_uframes_t src_offset,
200                          const snd_pcm_channel_area_t *dst_areas,
201                          snd_pcm_uframes_t dst_offset,
202                          unsigned int channels, snd_pcm_uframes_t frames, int putidx,
203                          adpcm_state_t *states)
204 {
205 #define PUT16_LABELS
206 #include "plugin_ops.h"
207 #undef PUT16_LABELS
208         void *put = put16_labels[putidx];
209         unsigned int channel;
210         for (channel = 0; channel < channels; ++channel, ++states) {
211                 char *src;
212                 int srcbit;
213                 char *dst;
214                 int src_step, srcbit_step, dst_step;
215                 snd_pcm_uframes_t frames1;
216                 const snd_pcm_channel_area_t *src_area = &src_areas[channel];
217                 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
218 #if 0
219                 if (!src_area->enabled) {
220                         if (dst_area->wanted)
221                                 snd_pcm_area_silence(dst_area, dst_offset, frames, dst_sfmt);
222                         dst_area->enabled = 0;
223                         continue;
224                 }
225                 dst_area->enabled = 1;
226 #endif
227                 srcbit = src_area->first + src_area->step * src_offset;
228                 src = src_area->addr + srcbit / 8;
229                 srcbit %= 8;
230                 src_step = src_area->step / 8;
231                 srcbit_step = src_area->step % 8;
232                 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
233                 dst_step = snd_pcm_channel_area_step(dst_area);
234                 frames1 = frames;
235                 while (frames1-- > 0) {
236                         int16_t sample;
237                         int v;
238                         if (srcbit)
239                                 v = *src & 0x0f;
240                         else
241                                 v = (*src >> 4) & 0x0f;
242                         sample = adpcm_decoder(v, states);
243                         goto *put;
244 #define PUT16_END after
245 #include "plugin_ops.h"
246 #undef PUT16_END
247                 after:
248                         src += src_step;
249                         srcbit += srcbit_step;
250                         if (srcbit == 8) {
251                                 src++;
252                                 srcbit = 0;
253                         }
254                         dst += dst_step;
255                 }
256         }
257 }
258
259 static void adpcm_encode(const snd_pcm_channel_area_t *src_areas,
260                          snd_pcm_uframes_t src_offset,
261                          const snd_pcm_channel_area_t *dst_areas,
262                          snd_pcm_uframes_t dst_offset,
263                          unsigned int channels, snd_pcm_uframes_t frames, int getidx,
264                          adpcm_state_t *states)
265 {
266 #define GET16_LABELS
267 #include "plugin_ops.h"
268 #undef GET16_LABELS
269         void *get = get16_labels[getidx];
270         unsigned int channel;
271         int16_t sample = 0;
272         for (channel = 0; channel < channels; ++channel, ++states) {
273                 char *src;
274                 char *dst;
275                 int dstbit;
276                 int src_step, dst_step, dstbit_step;
277                 snd_pcm_uframes_t frames1;
278                 const snd_pcm_channel_area_t *src_area = &src_areas[channel];
279                 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
280 #if 0
281                 if (!src_area->enabled) {
282                         if (dst_area->wanted)
283                                 snd_pcm_area_silence(dst_area, dst_offset, frames, dst_sfmt);
284                         dst_area->enabled = 0;
285                         continue;
286                 }
287                 dst_area->enabled = 1;
288 #endif
289                 src = snd_pcm_channel_area_addr(src_area, src_offset);
290                 src_step = snd_pcm_channel_area_step(src_area);
291                 dstbit = dst_area->first + dst_area->step * dst_offset;
292                 dst = dst_area->addr + dstbit / 8;
293                 dstbit %= 8;
294                 dst_step = dst_area->step / 8;
295                 dstbit_step = dst_area->step % 8;
296                 frames1 = frames;
297                 while (frames1-- > 0) {
298                         int v;
299                         goto *get;
300 #define GET16_END after
301 #include "plugin_ops.h"
302 #undef GET16_END
303                 after:
304                         v = adpcm_encoder(sample, states);
305                         if (dstbit)
306                                 *dst = (*dst & 0xf0) | v;
307                         else
308                                 *dst = (*dst & 0x0f) | (v << 4);
309                         src += src_step;
310                         dst += dst_step;
311                         dstbit += dstbit_step;
312                         if (dstbit == 8) {
313                                 dst++;
314                                 dstbit = 0;
315                         }
316                 }
317         }
318 }
319
320 static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
321 {
322         snd_pcm_adpcm_t *adpcm = pcm->private;
323         int err = 0;
324         if (adpcm->plug.close_slave)
325                 err = snd_pcm_close(adpcm->plug.slave);
326         if (adpcm->states)
327                 free(adpcm->states);
328         free(adpcm);
329         return 0;
330 }
331
332 static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
333 {
334         snd_pcm_adpcm_t *adpcm = pcm->private;
335         snd_pcm_t *slave = adpcm->plug.slave;
336         int err;
337         unsigned int cmask, lcmask;
338         snd_pcm_hw_params_t sparams;
339         mask_t *access_mask = alloca(mask_sizeof());
340         mask_t *saccess_mask = alloca(mask_sizeof());
341         mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
342         mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
343         cmask = params->cmask;
344         params->cmask = 0;
345         err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
346                                       access_mask);
347         if (err < 0)
348                 return err;
349         if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
350                 mask_t *format_mask = alloca(mask_sizeof());
351                 mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
352                 err = _snd_pcm_hw_param_mask(params,
353                                               SND_PCM_HW_PARAM_FORMAT,
354                                               format_mask);
355                 if (err < 0)
356                         return err;
357         } else {
358                 err = _snd_pcm_hw_param_set(params,
359                                             SND_PCM_HW_PARAM_FORMAT,
360                                             SND_PCM_FORMAT_IMA_ADPCM, 0);
361                 if (err < 0)
362                         return err;
363         }
364         err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
365                                      SND_PCM_SUBFORMAT_STD, 0);
366         if (err < 0)
367                 return err;
368         lcmask = params->cmask;
369         params->cmask |= cmask;
370
371         _snd_pcm_hw_params_any(&sparams);
372         _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
373                                 saccess_mask);
374         _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
375                               adpcm->sformat, 0);
376         _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
377                                SND_PCM_SUBFORMAT_STD, 0);
378         err = snd_pcm_hw_refine2(params, &sparams,
379                                  snd_pcm_generic_hw_link, slave,
380                                  SND_PCM_HW_PARBIT_CHANNELS |
381                                  SND_PCM_HW_PARBIT_RATE |
382                                  SND_PCM_HW_PARBIT_PERIOD_SIZE |
383                                  SND_PCM_HW_PARBIT_BUFFER_SIZE |
384                                  SND_PCM_HW_PARBIT_PERIODS |
385                                  SND_PCM_HW_PARBIT_PERIOD_TIME |
386                                  SND_PCM_HW_PARBIT_BUFFER_TIME |
387                                  SND_PCM_HW_PARBIT_TICK_TIME);
388         params->cmask |= lcmask;
389         if (err < 0)
390                 return err;
391         params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
392         return 0;
393 }
394
395 static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
396 {
397         snd_pcm_adpcm_t *adpcm = pcm->private;
398         snd_pcm_t *slave = adpcm->plug.slave;
399         int err;
400         snd_pcm_hw_params_t sparams;
401         unsigned int links;
402         mask_t *saccess_mask = alloca(mask_sizeof());
403         mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
404
405         _snd_pcm_hw_params_any(&sparams);
406         _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
407                                 saccess_mask);
408         _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
409                               adpcm->sformat, 0);
410         _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
411                               SND_PCM_SUBFORMAT_STD, 0);
412         links = SND_PCM_HW_PARBIT_CHANNELS |
413                 SND_PCM_HW_PARBIT_RATE |
414                 SND_PCM_HW_PARBIT_PERIOD_SIZE |
415                 SND_PCM_HW_PARBIT_BUFFER_SIZE |
416                 SND_PCM_HW_PARBIT_PERIODS |
417                 SND_PCM_HW_PARBIT_PERIOD_TIME |
418                 SND_PCM_HW_PARBIT_BUFFER_TIME |
419                 SND_PCM_HW_PARBIT_TICK_TIME;
420         err = snd_pcm_hw_params_refine(&sparams, links, params);
421         assert(err >= 0);
422         err = snd_pcm_hw_params(slave, &sparams);
423         params->cmask = 0;
424         sparams.cmask = ~0U;
425         snd_pcm_hw_params_refine(params, links, &sparams);
426         if (err < 0)
427                 return err;
428         params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
429         if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
430                 if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
431                         adpcm->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);
432                         adpcm->func = adpcm_encode;
433                 } else {
434                         adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, adpcm->sformat);
435                         adpcm->func = adpcm_decode;
436                 }
437         } else {
438                 if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
439                         adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0));
440                         adpcm->func = adpcm_decode;
441                 } else {
442                         adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_FORMAT_S16);
443                         adpcm->func = adpcm_encode;
444                 }
445         }
446         if (adpcm->states)
447                 free(adpcm->states);
448         adpcm->states = malloc(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_CHANNELS, 0) * sizeof(*adpcm->states));
449         return 0;
450 }
451
452 static int snd_pcm_adpcm_init(snd_pcm_t *pcm)
453 {
454         snd_pcm_adpcm_t *adpcm = pcm->private;
455         unsigned int k;
456         for (k = 0; k < pcm->channels; ++k) {
457                 adpcm->states[k].pred_val = 0;
458                 adpcm->states[k].step_idx = 0;
459         }
460         return 0;
461 }
462
463 static snd_pcm_sframes_t snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
464                                          const snd_pcm_channel_area_t *areas,
465                                          snd_pcm_uframes_t offset,
466                                          snd_pcm_uframes_t size,
467                                          snd_pcm_uframes_t *slave_sizep)
468 {
469         snd_pcm_adpcm_t *adpcm = pcm->private;
470         snd_pcm_t *slave = adpcm->plug.slave;
471         snd_pcm_uframes_t xfer = 0;
472         snd_pcm_sframes_t err = 0;
473         if (slave_sizep && *slave_sizep < size)
474                 size = *slave_sizep;
475         assert(size > 0);
476         while (xfer < size) {
477                 snd_pcm_uframes_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
478                 adpcm->func(areas, offset, 
479                             snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
480                             pcm->channels, frames,
481                             adpcm->getput_idx, adpcm->states);
482                 err = snd_pcm_mmap_forward(slave, frames);
483                 if (err < 0)
484                         break;
485                 assert((snd_pcm_uframes_t)err == frames);
486                 offset += err;
487                 xfer += err;
488                 snd_pcm_mmap_hw_forward(pcm, err);
489         }
490         if (xfer > 0) {
491                 if (slave_sizep)
492                         *slave_sizep = xfer;
493                 return xfer;
494         }
495         return err;
496 }
497
498 static snd_pcm_sframes_t snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
499                                         const snd_pcm_channel_area_t *areas,
500                                         snd_pcm_uframes_t offset,
501                                         snd_pcm_uframes_t size,
502                                         snd_pcm_uframes_t *slave_sizep)
503 {
504         snd_pcm_adpcm_t *adpcm = pcm->private;
505         snd_pcm_t *slave = adpcm->plug.slave;
506         snd_pcm_uframes_t xfer = 0;
507         snd_pcm_sframes_t err = 0;
508         if (slave_sizep && *slave_sizep < size)
509                 size = *slave_sizep;
510         assert(size > 0);
511         while (xfer < size) {
512                 snd_pcm_uframes_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
513                 adpcm->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
514                             areas, offset, 
515                             pcm->channels, frames,
516                             adpcm->getput_idx, adpcm->states);
517                 err = snd_pcm_mmap_forward(slave, frames);
518                 if (err < 0)
519                         break;
520                 assert((snd_pcm_uframes_t)err == frames);
521                 offset += err;
522                 xfer += err;
523                 snd_pcm_mmap_hw_forward(pcm, err);
524         }
525         if (xfer > 0) {
526                 if (slave_sizep)
527                         *slave_sizep = xfer;
528                 return xfer;
529         }
530         return err;
531 }
532
533 static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, snd_output_t *out)
534 {
535         snd_pcm_adpcm_t *adpcm = pcm->private;
536         snd_output_printf(out, "Ima-ADPCM conversion PCM (%s)\n", 
537                 snd_pcm_format_name(adpcm->sformat));
538         if (pcm->setup) {
539                 snd_output_printf(out, "Its setup is:\n");
540                 snd_pcm_dump_setup(pcm, out);
541         }
542         snd_output_printf(out, "Slave: ");
543         snd_pcm_dump(adpcm->plug.slave, out);
544 }
545
546 snd_pcm_ops_t snd_pcm_adpcm_ops = {
547         close: snd_pcm_adpcm_close,
548         card: snd_pcm_plugin_card,
549         info: snd_pcm_plugin_info,
550         hw_refine: snd_pcm_adpcm_hw_refine,
551         hw_params: snd_pcm_adpcm_hw_params,
552         sw_params: snd_pcm_plugin_sw_params,
553         channel_info: snd_pcm_plugin_channel_info,
554         dump: snd_pcm_adpcm_dump,
555         nonblock: snd_pcm_plugin_nonblock,
556         async: snd_pcm_plugin_async,
557         mmap: snd_pcm_plugin_mmap,
558         munmap: snd_pcm_plugin_munmap,
559 };
560
561 int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
562 {
563         snd_pcm_t *pcm;
564         snd_pcm_adpcm_t *adpcm;
565         assert(pcmp && slave);
566         if (snd_pcm_format_linear(sformat) != 1 &&
567             sformat != SND_PCM_FORMAT_IMA_ADPCM)
568                 return -EINVAL;
569         adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
570         if (!adpcm) {
571                 return -ENOMEM;
572         }
573         adpcm->sformat = sformat;
574         adpcm->plug.read = snd_pcm_adpcm_read_areas;
575         adpcm->plug.write = snd_pcm_adpcm_write_areas;
576         adpcm->plug.init = snd_pcm_adpcm_init;
577         adpcm->plug.slave = slave;
578         adpcm->plug.close_slave = close_slave;
579
580         pcm = calloc(1, sizeof(snd_pcm_t));
581         if (!pcm) {
582                 free(adpcm);
583                 return -ENOMEM;
584         }
585         if (name)
586                 pcm->name = strdup(name);
587         pcm->type = SND_PCM_TYPE_ADPCM;
588         pcm->stream = slave->stream;
589         pcm->mode = slave->mode;
590         pcm->ops = &snd_pcm_adpcm_ops;
591         pcm->op_arg = pcm;
592         pcm->fast_ops = &snd_pcm_plugin_fast_ops;
593         pcm->fast_op_arg = pcm;
594         pcm->private = adpcm;
595         pcm->poll_fd = slave->poll_fd;
596         pcm->hw_ptr = &adpcm->plug.hw_ptr;
597         pcm->appl_ptr = &adpcm->plug.appl_ptr;
598         *pcmp = pcm;
599
600         return 0;
601 }
602
603 int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name,
604                          snd_config_t *conf, 
605                          int stream, int mode)
606 {
607         snd_config_iterator_t i;
608         char *sname = NULL;
609         int err;
610         snd_pcm_t *spcm;
611         int sformat = -1;
612         snd_config_foreach(i, conf) {
613                 snd_config_t *n = snd_config_entry(i);
614                 if (strcmp(n->id, "comment") == 0)
615                         continue;
616                 if (strcmp(n->id, "type") == 0)
617                         continue;
618                 if (strcmp(n->id, "stream") == 0)
619                         continue;
620                 if (strcmp(n->id, "sname") == 0) {
621                         err = snd_config_string_get(n, &sname);
622                         if (err < 0) {
623                                 ERR("Invalid type for %s", n->id);
624                                 return -EINVAL;
625                         }
626                         continue;
627                 }
628                 if (strcmp(n->id, "sformat") == 0) {
629                         char *f;
630                         err = snd_config_string_get(n, &f);
631                         if (err < 0) {
632                                 ERR("Invalid type for %s", n->id);
633                                 return -EINVAL;
634                         }
635                         sformat = snd_pcm_format_value(f);
636                         if (sformat < 0) {
637                                 ERR("Unknown sformat");
638                                 return -EINVAL;
639                         }
640                         if (snd_pcm_format_linear(sformat) != 1 &&
641                             sformat != SND_PCM_FORMAT_IMA_ADPCM) {
642                                 ERR("Invalid sformat");
643                                 return -EINVAL;
644                         }
645                         continue;
646                 }
647                 ERR("Unknown field %s", n->id);
648                 return -EINVAL;
649         }
650         if (!sname) {
651                 ERR("sname is not defined");
652                 return -EINVAL;
653         }
654         if (sformat < 0) {
655                 ERR("sformat is not defined");
656                 return -EINVAL;
657         }
658         /* This is needed cause snd_config_update may destroy config */
659         sname = strdup(sname);
660         if (!sname)
661                 return  -ENOMEM;
662         err = snd_pcm_open(&spcm, sname, stream, mode);
663         free(sname);
664         if (err < 0)
665                 return err;
666         err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1);
667         if (err < 0)
668                 snd_pcm_close(spcm);
669         return err;
670 }
671                                 
672