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/* 37These routines convert 16 bit linear PCM samples to 4 bit ADPCM code 38and vice versa. The ADPCM code used is the Intel/DVI ADPCM code which 39is being recommended by the IMA Digital Audio Technical Working Group. 40 41The algorithm for this coder was taken from: 42Proposal for Standardized Audio Interstreamge Formats, 43IMA 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 */ 67const char *_snd_module_pcm_adpcm = ""; 68#endif 69 70#ifndef DOC_HIDDEN 71 72typedef 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 80typedef 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 */ 92static const char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; 93 94/* Second table lookup for Ima-ADPCM quantizer */ 95static const 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 107static 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 168static 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 216void 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 269void 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 324static 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 351static 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 363static 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 381static 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 399static 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 409static 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 449static 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 457static 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 468static snd_pcm_uframes_t 469snd_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 488static snd_pcm_uframes_t 489snd_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 508static 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 521static const 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 */ 548int 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 pcm->monotonic = slave->monotonic; 580 snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0); 581 snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0); 582 *pcmp = pcm; 583 584 return 0; 585} 586 587/*! \page pcm_plugins 588 589\section pcm_plugins_adpcm Plugin: Ima-ADPCM 590 591This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples 592from master Ima-ADPCM conversion PCM to given slave PCM. The channel count, 593format and rate must match for both of them. 594 595\code 596pcm.name { 597 type adpcm # Ima-ADPCM conversion PCM 598 slave STR # Slave name 599 # or 600 slave { # Slave definition 601 pcm STR # Slave PCM name 602 # or 603 pcm { } # Slave PCM definition 604 format STR # Slave format 605 } 606} 607\endcode 608 609\subsection pcm_plugins_adpcm_funcref Function reference 610 611<UL> 612 <LI>snd_pcm_adpcm_open() 613 <LI>_snd_pcm_adpcm_open() 614</UL> 615 616*/ 617 618/** 619 * \brief Creates a new Ima-ADPCM conversion PCM 620 * \param pcmp Returns created PCM handle 621 * \param name Name of PCM 622 * \param root Root configuration node 623 * \param conf Configuration node with copy PCM description 624 * \param stream Stream type 625 * \param mode Stream mode 626 * \retval zero on success otherwise a negative error code 627 * \warning Using of this function might be dangerous in the sense 628 * of compatibility reasons. The prototype might be freely 629 * changed in future. 630 */ 631int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, 632 snd_config_t *root, snd_config_t *conf, 633 snd_pcm_stream_t stream, int mode) 634{ 635 snd_config_iterator_t i, next; 636 int err; 637 snd_pcm_t *spcm; 638 snd_config_t *slave = NULL, *sconf; 639 snd_pcm_format_t sformat; 640 snd_config_for_each(i, next, conf) { 641 snd_config_t *n = snd_config_iterator_entry(i); 642 const char *id; 643 if (snd_config_get_id(n, &id) < 0) 644 continue; 645 if (snd_pcm_conf_generic_id(id)) 646 continue; 647 if (strcmp(id, "slave") == 0) { 648 slave = n; 649 continue; 650 } 651 SNDERR("Unknown field %s", id); 652 return -EINVAL; 653 } 654 if (!slave) { 655 SNDERR("slave is not defined"); 656 return -EINVAL; 657 } 658 err = snd_pcm_slave_conf(root, slave, &sconf, 1, 659 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); 660 if (err < 0) 661 return err; 662 if (snd_pcm_format_linear(sformat) != 1 && 663 sformat != SND_PCM_FORMAT_IMA_ADPCM) { 664 snd_config_delete(sconf); 665 SNDERR("invalid slave format"); 666 return -EINVAL; 667 } 668 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 669 snd_config_delete(sconf); 670 if (err < 0) 671 return err; 672 err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1); 673 if (err < 0) 674 snd_pcm_close(spcm); 675 return err; 676} 677#ifndef DOC_HIDDEN 678SND_DLSYM_BUILD_VERSION(_snd_pcm_adpcm_open, SND_PCM_DLSYM_VERSION); 679#endif 680