OSDN Git Service

4c916ab3f0644177c5177fab288e1ae658abe3f6
[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)(snd_pcm_channel_area_t *src_areas,
60                         size_t src_offset,
61                         snd_pcm_channel_area_t *dst_areas,
62                         size_t dst_offset,
63                         size_t frames, size_t channels, 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         int cformat;
73         int cxfer_mode, cmmap_shape;
74         adpcm_state_t *states;
75 } snd_pcm_adpcm_t;
76
77 /* First table lookup for Ima-ADPCM quantizer */
78 static char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
79
80 /* Second table lookup for Ima-ADPCM quantizer */
81 static short StepSize[89] = {
82         7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
83         19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
84         50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
85         130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
86         337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
87         876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
88         2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
89         5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
90         15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
91 };
92
93 static char adpcm_encoder(int sl, adpcm_state_t * state)
94 {
95         short diff;             /* Difference between sl and predicted sample */
96         short pred_diff;        /* Predicted difference to next sample */
97
98         unsigned char sign;     /* sign of diff */
99         short step;             /* holds previous StepSize value */
100         unsigned char adjust_idx;       /* Index to IndexAdjust lookup table */
101
102         int i;
103
104         /* Compute difference to previous predicted value */
105         diff = sl - state->pred_val;
106         sign = (diff < 0) ? 0x8 : 0x0;
107         if (sign) {
108                 diff = -diff;
109         }
110
111         /*
112          * This code *approximately* computes:
113          *    adjust_idx = diff * 4 / step;
114          *    pred_diff = (adjust_idx + 0.5) * step / 4;
115          *
116          * But in shift step bits are dropped. The net result of this is
117          * that even if you have fast mul/div hardware you cannot put it to
118          * good use since the fixup would be too expensive.
119          */
120
121         step = StepSize[state->step_idx];
122
123         /* Divide and clamp */
124         pred_diff = step >> 3;
125         for (adjust_idx = 0, i = 0x4; i; i >>= 1, step >>= 1) {
126                 if (diff >= step) {
127                         adjust_idx |= i;
128                         diff -= step;
129                         pred_diff += step;
130                 }
131         }
132
133         /* Update and clamp previous predicted value */
134         state->pred_val += sign ? -pred_diff : pred_diff;
135
136         if (state->pred_val > 32767) {
137                 state->pred_val = 32767;
138         } else if (state->pred_val < -32768) {
139                 state->pred_val = -32768;
140         }
141
142         /* Update and clamp StepSize lookup table index */
143         state->step_idx += IndexAdjust[adjust_idx];
144
145         if (state->step_idx < 0) {
146                 state->step_idx = 0;
147         } else if (state->step_idx > 88) {
148                 state->step_idx = 88;
149         }
150         return (sign | adjust_idx);
151 }
152
153
154 static int adpcm_decoder(unsigned char code, adpcm_state_t * state)
155 {
156         short pred_diff;        /* Predicted difference to next sample */
157         short step;             /* holds previous StepSize value */
158         char sign;
159
160         int i;
161
162         /* Separate sign and magnitude */
163         sign = code & 0x8;
164         code &= 0x7;
165
166         /*
167          * Computes pred_diff = (code + 0.5) * step / 4,
168          * but see comment in adpcm_coder.
169          */
170
171         step = StepSize[state->step_idx];
172
173         /* Compute difference and new predicted value */
174         pred_diff = step >> 3;
175         for (i = 0x4; i; i >>= 1, step >>= 1) {
176                 if (code & i) {
177                         pred_diff += step;
178                 }
179         }
180         state->pred_val += (sign) ? -pred_diff : pred_diff;
181
182         /* Clamp output value */
183         if (state->pred_val > 32767) {
184                 state->pred_val = 32767;
185         } else if (state->pred_val < -32768) {
186                 state->pred_val = -32768;
187         }
188
189         /* Find new StepSize index value */
190         state->step_idx += IndexAdjust[code];
191
192         if (state->step_idx < 0) {
193                 state->step_idx = 0;
194         } else if (state->step_idx > 88) {
195                 state->step_idx = 88;
196         }
197         return (state->pred_val);
198 }
199
200 static void adpcm_decode(snd_pcm_channel_area_t *src_areas,
201                          size_t src_offset,
202                          snd_pcm_channel_area_t *dst_areas,
203                          size_t dst_offset,
204                          size_t frames, size_t channels, int putidx,
205                          adpcm_state_t *states)
206 {
207 #define PUT_S16_LABELS
208 #include "plugin_ops.h"
209 #undef PUT_S16_LABELS
210         void *put = put_s16_labels[putidx];
211         size_t channel;
212         for (channel = 0; channel < channels; ++channel, ++states) {
213                 char *src;
214                 int srcbit;
215                 char *dst;
216                 int src_step, srcbit_step, dst_step;
217                 size_t frames1;
218                 snd_pcm_channel_area_t *src_area = &src_areas[channel];
219                 snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
220 #if 0
221                 if (!src_area->enabled) {
222                         if (dst_area->wanted)
223                                 snd_pcm_area_silence(dst_area, dst_offset, frames, dst_sfmt);
224                         dst_area->enabled = 0;
225                         continue;
226                 }
227                 dst_area->enabled = 1;
228 #endif
229                 srcbit = src_area->first + src_area->step * src_offset;
230                 src = src_area->addr + srcbit / 8;
231                 srcbit %= 8;
232                 src_step = src_area->step / 8;
233                 srcbit_step = src_area->step % 8;
234                 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
235                 dst_step = snd_pcm_channel_area_step(dst_area);
236                 frames1 = frames;
237                 while (frames1-- > 0) {
238                         int16_t sample;
239                         int v;
240                         if (srcbit)
241                                 v = *src & 0x0f;
242                         else
243                                 v = (*src >> 4) & 0x0f;
244                         sample = adpcm_decoder(v, states);
245                         goto *put;
246 #define PUT_S16_END after
247 #include "plugin_ops.h"
248 #undef PUT_S16_END
249                 after:
250                         src += src_step;
251                         srcbit += srcbit_step;
252                         if (srcbit == 8) {
253                                 src++;
254                                 srcbit = 0;
255                         }
256                         dst += dst_step;
257                 }
258         }
259 }
260
261 static void adpcm_encode(snd_pcm_channel_area_t *src_areas,
262                          size_t src_offset,
263                          snd_pcm_channel_area_t *dst_areas,
264                          size_t dst_offset,
265                          size_t frames, size_t channels, int getidx,
266                          adpcm_state_t *states)
267 {
268 #define GET_S16_LABELS
269 #include "plugin_ops.h"
270 #undef GET_S16_LABELS
271         void *get = get_s16_labels[getidx];
272         size_t channel;
273         int16_t sample = 0;
274         for (channel = 0; channel < channels; ++channel, ++states) {
275                 char *src;
276                 char *dst;
277                 int dstbit;
278                 int src_step, dst_step, dstbit_step;
279                 size_t frames1;
280                 snd_pcm_channel_area_t *src_area = &src_areas[channel];
281                 snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
282 #if 0
283                 if (!src_area->enabled) {
284                         if (dst_area->wanted)
285                                 snd_pcm_area_silence(dst_area, dst_offset, frames, dst_sfmt);
286                         dst_area->enabled = 0;
287                         continue;
288                 }
289                 dst_area->enabled = 1;
290 #endif
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 = 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 GET_S16_END after
303 #include "plugin_ops.h"
304 #undef GET_S16_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 static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
323 {
324         snd_pcm_adpcm_t *adpcm = pcm->private;
325         int err = 0;
326         if (adpcm->plug.close_slave)
327                 err = snd_pcm_close(adpcm->plug.slave);
328         if (adpcm->states)
329                 free(adpcm->states);
330         free(adpcm);
331         return 0;
332 }
333
334 static int snd_pcm_adpcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
335 {
336         snd_pcm_adpcm_t *adpcm = pcm->private;
337         unsigned int req_mask = info->req_mask;
338         unsigned int sfmt = info->req.format.sfmt;
339         int err;
340         if (req_mask & SND_PCM_PARAMS_SFMT) {
341                 if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
342                     !snd_pcm_format_linear(sfmt) :
343                     sfmt != SND_PCM_SFMT_IMA_ADPCM) {
344                         info->req.fail_mask = SND_PCM_PARAMS_SFMT;
345                         info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
346                         return -EINVAL;
347                 }
348         }
349         info->req_mask |= SND_PCM_PARAMS_SFMT;
350         info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE | 
351                             SND_PCM_PARAMS_XFER_MODE);
352         info->req.format.sfmt = adpcm->sformat;
353         err = snd_pcm_params_info(adpcm->plug.slave, info);
354         info->req_mask = req_mask;
355         info->req.format.sfmt = sfmt;
356         if (err < 0)
357                 return err;
358         if (req_mask & SND_PCM_PARAMS_SFMT)
359                 info->formats = 1 << sfmt;
360         else
361                 info->formats = adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
362                         SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_IMA_ADPCM;
363         info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
364         info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
365         return err;
366 }
367
368 static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
369 {
370         snd_pcm_adpcm_t *adpcm = pcm->private;
371         snd_pcm_t *slave = adpcm->plug.slave;
372         int err;
373         if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
374             !snd_pcm_format_linear(params->format.sfmt) :
375             params->format.sfmt != SND_PCM_SFMT_IMA_ADPCM) {
376                 params->fail_mask = SND_PCM_PARAMS_SFMT;
377                 params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
378                 return -EINVAL;
379         }
380         if (slave->mmap_data) {
381                 err = snd_pcm_munmap_data(slave);
382                 if (err < 0)
383                         return err;
384         }
385         adpcm->cformat = params->format.sfmt;
386         adpcm->cxfer_mode = params->xfer_mode;
387         adpcm->cmmap_shape = params->mmap_shape;
388         params->format.sfmt = adpcm->sformat;
389         params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
390         params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
391         err = snd_pcm_params(slave, params);
392         params->format.sfmt = adpcm->cformat;
393         params->xfer_mode = adpcm->cxfer_mode;
394         params->mmap_shape = adpcm->cmmap_shape;
395         if (slave->valid_setup) {
396                 int r = snd_pcm_mmap_data(slave, NULL);
397                 assert(r >= 0);
398         }
399         return err;
400 }
401
402 static int snd_pcm_adpcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
403 {
404         snd_pcm_adpcm_t *adpcm = pcm->private;
405         int err = snd_pcm_setup(adpcm->plug.slave, setup);
406         if (err < 0)
407                 return err;
408         assert(adpcm->sformat == setup->format.sfmt);
409         if (adpcm->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
410                 setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
411         else
412                 setup->xfer_mode = adpcm->cxfer_mode;
413         if (adpcm->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
414                 setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
415         else
416                 setup->mmap_shape = adpcm->cmmap_shape;
417         setup->format.sfmt = adpcm->cformat;
418         setup->mmap_bytes = 0;
419         if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
420                 if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
421                         adpcm->getput_idx = getput_index(adpcm->cformat);
422                         adpcm->func = adpcm_encode;
423                 } else {
424                         adpcm->getput_idx = getput_index(adpcm->sformat);
425                         adpcm->func = adpcm_decode;
426                 }
427         } else {
428                 if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
429                         adpcm->getput_idx = getput_index(adpcm->cformat);
430                         adpcm->func = adpcm_decode;
431                 } else {
432                         adpcm->getput_idx = getput_index(adpcm->sformat);
433                         adpcm->func = adpcm_encode;
434                 }
435         }
436         if (adpcm->states)
437                 free(adpcm->states);
438         adpcm->states = malloc(setup->format.channels * sizeof(*adpcm->states));
439         return 0;
440 }
441
442 static int snd_pcm_adpcm_init(snd_pcm_t *pcm)
443 {
444         snd_pcm_adpcm_t *adpcm = pcm->private;
445         unsigned int k;
446         for (k = 0; k < pcm->setup.format.channels; ++k) {
447                 adpcm->states[k].pred_val = 0;
448                 adpcm->states[k].step_idx = 0;
449         }
450         return 0;
451 }
452
453 static ssize_t snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
454                                          snd_pcm_channel_area_t *areas,
455                                          size_t offset,
456                                          size_t size,
457                                          size_t *slave_sizep)
458 {
459         snd_pcm_adpcm_t *adpcm = pcm->private;
460         snd_pcm_t *slave = adpcm->plug.slave;
461         size_t xfer = 0;
462         ssize_t err = 0;
463         if (slave_sizep && *slave_sizep < size)
464                 size = *slave_sizep;
465         assert(size > 0);
466         while (xfer < size) {
467                 size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
468                 adpcm->func(areas, offset, 
469                             snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
470                             frames, pcm->setup.format.channels,
471                             adpcm->getput_idx, adpcm->states);
472                 err = snd_pcm_mmap_forward(slave, frames);
473                 if (err < 0)
474                         break;
475                 assert((size_t)err == frames);
476                 offset += err;
477                 xfer += err;
478                 snd_pcm_mmap_hw_forward(pcm, err);
479         }
480         if (xfer > 0) {
481                 if (slave_sizep)
482                         *slave_sizep = xfer;
483                 return xfer;
484         }
485         return err;
486 }
487
488 static ssize_t snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
489                                         snd_pcm_channel_area_t *areas,
490                                         size_t offset,
491                                         size_t size,
492                                         size_t *slave_sizep)
493 {
494         snd_pcm_adpcm_t *adpcm = pcm->private;
495         snd_pcm_t *slave = adpcm->plug.slave;
496         size_t xfer = 0;
497         ssize_t err = 0;
498         if (slave_sizep && *slave_sizep < size)
499                 size = *slave_sizep;
500         assert(size > 0);
501         while (xfer < size) {
502                 size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
503                 adpcm->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
504                             areas, offset, 
505                             frames, pcm->setup.format.channels,
506                             adpcm->getput_idx, adpcm->states);
507                 err = snd_pcm_mmap_forward(slave, frames);
508                 if (err < 0)
509                         break;
510                 assert((size_t)err == frames);
511                 offset += err;
512                 xfer += err;
513                 snd_pcm_mmap_hw_forward(pcm, err);
514         }
515         if (xfer > 0) {
516                 if (slave_sizep)
517                         *slave_sizep = xfer;
518                 return xfer;
519         }
520         return err;
521 }
522
523 static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
524 {
525         snd_pcm_adpcm_t *adpcm = pcm->private;
526         fprintf(fp, "Ima-ADPCM conversion PCM (%s)\n", 
527                 snd_pcm_format_name(adpcm->sformat));
528         if (pcm->valid_setup) {
529                 fprintf(fp, "Its setup is:\n");
530                 snd_pcm_dump_setup(pcm, fp);
531         }
532         fprintf(fp, "Slave: ");
533         snd_pcm_dump(adpcm->plug.slave, fp);
534 }
535
536 struct snd_pcm_ops snd_pcm_adpcm_ops = {
537         close: snd_pcm_adpcm_close,
538         info: snd_pcm_plugin_info,
539         params_info: snd_pcm_adpcm_params_info,
540         params: snd_pcm_adpcm_params,
541         setup: snd_pcm_adpcm_setup,
542         channel_info: snd_pcm_plugin_channel_info,
543         channel_params: snd_pcm_plugin_channel_params,
544         channel_setup: snd_pcm_plugin_channel_setup,
545         dump: snd_pcm_adpcm_dump,
546         nonblock: snd_pcm_plugin_nonblock,
547         mmap_status: snd_pcm_plugin_mmap_status,
548         mmap_control: snd_pcm_plugin_mmap_control,
549         mmap_data: snd_pcm_plugin_mmap_data,
550         munmap_status: snd_pcm_plugin_munmap_status,
551         munmap_control: snd_pcm_plugin_munmap_control,
552         munmap_data: snd_pcm_plugin_munmap_data,
553 };
554
555 int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
556 {
557         snd_pcm_t *handle;
558         snd_pcm_adpcm_t *adpcm;
559         int err;
560         assert(handlep && slave);
561         if (snd_pcm_format_linear(sformat) != 1 &&
562             sformat != SND_PCM_SFMT_IMA_ADPCM)
563                 return -EINVAL;
564         adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
565         if (!adpcm) {
566                 return -ENOMEM;
567         }
568         adpcm->sformat = sformat;
569         adpcm->plug.read = snd_pcm_adpcm_read_areas;
570         adpcm->plug.write = snd_pcm_adpcm_write_areas;
571         adpcm->plug.init = snd_pcm_adpcm_init;
572         adpcm->plug.slave = slave;
573         adpcm->plug.close_slave = close_slave;
574
575         handle = calloc(1, sizeof(snd_pcm_t));
576         if (!handle) {
577                 free(adpcm);
578                 return -ENOMEM;
579         }
580         if (name)
581                 handle->name = strdup(name);
582         handle->type = SND_PCM_TYPE_ADPCM;
583         handle->stream = slave->stream;
584         handle->ops = &snd_pcm_adpcm_ops;
585         handle->op_arg = handle;
586         handle->fast_ops = &snd_pcm_plugin_fast_ops;
587         handle->fast_op_arg = handle;
588         handle->mode = slave->mode;
589         handle->private = adpcm;
590         err = snd_pcm_init(handle);
591         if (err < 0) {
592                 snd_pcm_close(handle);
593                 return err;
594         }
595         *handlep = handle;
596
597         return 0;
598 }
599
600 int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name,
601                          snd_config_t *conf, 
602                          int stream, int mode)
603 {
604         snd_config_iterator_t i;
605         char *sname = NULL;
606         int err;
607         snd_pcm_t *spcm;
608         int sformat = -1;
609         snd_config_foreach(i, conf) {
610                 snd_config_t *n = snd_config_entry(i);
611                 if (strcmp(n->id, "comment") == 0)
612                         continue;
613                 if (strcmp(n->id, "type") == 0)
614                         continue;
615                 if (strcmp(n->id, "stream") == 0)
616                         continue;
617                 if (strcmp(n->id, "sname") == 0) {
618                         err = snd_config_string_get(n, &sname);
619                         if (err < 0)
620                                 return -EINVAL;
621                         continue;
622                 }
623                 if (strcmp(n->id, "sformat") == 0) {
624                         char *f;
625                         err = snd_config_string_get(n, &f);
626                         if (err < 0)
627                                 return -EINVAL;
628                         sformat = snd_pcm_format_value(f);
629                         if (sformat < 0)
630                                 return -EINVAL;
631                         if (snd_pcm_format_linear(sformat) != 1 &&
632                             sformat != SND_PCM_SFMT_IMA_ADPCM)
633                                 return -EINVAL;
634                         continue;
635                 }
636                 return -EINVAL;
637         }
638         if (!sname || !sformat)
639                 return -EINVAL;
640         /* This is needed cause snd_config_update may destroy config */
641         sname = strdup(sname);
642         if (!sname)
643                 return  -ENOMEM;
644         err = snd_pcm_open(&spcm, sname, stream, mode);
645         free(sname);
646         if (err < 0)
647                 return err;
648         err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1);
649         if (err < 0)
650                 snd_pcm_close(spcm);
651         return err;
652 }
653                                 
654