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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "pcm_local.h" 60#include "pcm_plugin.h" 61#include "plugin_ops.h" 62#include "bswap.h" 63 64#ifndef PIC 65/* entry for static linking */ 66const char *_snd_module_pcm_adpcm = ""; 67#endif 68 69#ifndef DOC_HIDDEN 70 71typedef void (*adpcm_f)(const snd_pcm_channel_area_t *dst_areas, 72 snd_pcm_uframes_t dst_offset, 73 const snd_pcm_channel_area_t *src_areas, 74 snd_pcm_uframes_t src_offset, 75 unsigned int channels, snd_pcm_uframes_t frames, 76 unsigned int getputidx, 77 snd_pcm_adpcm_state_t *states); 78 79typedef struct { 80 /* This field need to be the first */ 81 snd_pcm_plugin_t plug; 82 unsigned int getput_idx; 83 adpcm_f func; 84 snd_pcm_format_t sformat; 85 snd_pcm_adpcm_state_t *states; 86} snd_pcm_adpcm_t; 87 88#endif 89 90/* First table lookup for Ima-ADPCM quantizer */ 91static const char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; 92 93/* Second table lookup for Ima-ADPCM quantizer */ 94static const short StepSize[89] = { 95 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 96 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 97 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 98 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 99 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 100 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 101 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 102 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 103 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 104}; 105 106static char adpcm_encoder(int sl, snd_pcm_adpcm_state_t * state) 107{ 108 short diff; /* Difference between sl and predicted sample */ 109 short pred_diff; /* Predicted difference to next sample */ 110 111 unsigned char sign; /* sign of diff */ 112 short step; /* holds previous StepSize value */ 113 unsigned char adjust_idx; /* Index to IndexAdjust lookup table */ 114 115 int i; 116 117 /* Compute difference to previous predicted value */ 118 diff = sl - state->pred_val; 119 sign = (diff < 0) ? 0x8 : 0x0; 120 if (sign) { 121 diff = -diff; 122 } 123 124 /* 125 * This code *approximately* computes: 126 * adjust_idx = diff * 4 / step; 127 * pred_diff = (adjust_idx + 0.5) * step / 4; 128 * 129 * But in shift step bits are dropped. The net result of this is 130 * that even if you have fast mul/div hardware you cannot put it to 131 * good use since the fix-up would be too expensive. 132 */ 133 134 step = StepSize[state->step_idx]; 135 136 /* Divide and clamp */ 137 pred_diff = step >> 3; 138 for (adjust_idx = 0, i = 0x4; i; i >>= 1, step >>= 1) { 139 if (diff >= step) { 140 adjust_idx |= i; 141 diff -= step; 142 pred_diff += step; 143 } 144 } 145 146 /* Update and clamp previous predicted value */ 147 state->pred_val += sign ? -pred_diff : pred_diff; 148 149 if (state->pred_val > 32767) { 150 state->pred_val = 32767; 151 } else if (state->pred_val < -32768) { 152 state->pred_val = -32768; 153 } 154 155 /* Update and clamp StepSize lookup table index */ 156 state->step_idx += IndexAdjust[adjust_idx]; 157 158 if (state->step_idx < 0) { 159 state->step_idx = 0; 160 } else if (state->step_idx > 88) { 161 state->step_idx = 88; 162 } 163 return (sign | adjust_idx); 164} 165 166 167static int adpcm_decoder(unsigned char code, snd_pcm_adpcm_state_t * state) 168{ 169 short pred_diff; /* Predicted difference to next sample */ 170 short step; /* holds previous StepSize value */ 171 char sign; 172 173 int i; 174 175 /* Separate sign and magnitude */ 176 sign = code & 0x8; 177 code &= 0x7; 178 179 /* 180 * Computes pred_diff = (code + 0.5) * step / 4, 181 * but see comment in adpcm_coder. 182 */ 183 184 step = StepSize[state->step_idx]; 185 186 /* Compute difference and new predicted value */ 187 pred_diff = step >> 3; 188 for (i = 0x4; i; i >>= 1, step >>= 1) { 189 if (code & i) { 190 pred_diff += step; 191 } 192 } 193 state->pred_val += (sign) ? -pred_diff : pred_diff; 194 195 /* Clamp output value */ 196 if (state->pred_val > 32767) { 197 state->pred_val = 32767; 198 } else if (state->pred_val < -32768) { 199 state->pred_val = -32768; 200 } 201 202 /* Find new StepSize index value */ 203 state->step_idx += IndexAdjust[code]; 204 205 if (state->step_idx < 0) { 206 state->step_idx = 0; 207 } else if (state->step_idx > 88) { 208 state->step_idx = 88; 209 } 210 return (state->pred_val); 211} 212 213#ifndef DOC_HIDDEN 214 215void snd_pcm_adpcm_decode(const snd_pcm_channel_area_t *dst_areas, 216 snd_pcm_uframes_t dst_offset, 217 const snd_pcm_channel_area_t *src_areas, 218 snd_pcm_uframes_t src_offset, 219 unsigned int channels, snd_pcm_uframes_t frames, 220 unsigned int putidx, 221 snd_pcm_adpcm_state_t *states) 222{ 223#define PUT16_LABELS 224#include "plugin_ops.h" 225#undef PUT16_LABELS 226 void *put = put16_labels[putidx]; 227 unsigned int channel; 228 for (channel = 0; channel < channels; ++channel, ++states) { 229 const char *src; 230 int srcbit; 231 char *dst; 232 int src_step, srcbit_step, dst_step; 233 snd_pcm_uframes_t frames1; 234 const snd_pcm_channel_area_t *src_area = &src_areas[channel]; 235 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; 236 srcbit = src_area->first + src_area->step * src_offset; 237 src = (const char *) src_area->addr + srcbit / 8; 238 srcbit %= 8; 239 src_step = src_area->step / 8; 240 srcbit_step = src_area->step % 8; 241 dst = snd_pcm_channel_area_addr(dst_area, dst_offset); 242 dst_step = snd_pcm_channel_area_step(dst_area); 243 frames1 = frames; 244 while (frames1-- > 0) { 245 int16_t sample; 246 unsigned char v; 247 if (srcbit) 248 v = *src & 0x0f; 249 else 250 v = (*src >> 4) & 0x0f; 251 sample = adpcm_decoder(v, states); 252 goto *put; 253#define PUT16_END after 254#include "plugin_ops.h" 255#undef PUT16_END 256 after: 257 src += src_step; 258 srcbit += srcbit_step; 259 if (srcbit == 8) { 260 src++; 261 srcbit = 0; 262 } 263 dst += dst_step; 264 } 265 } 266} 267 268void snd_pcm_adpcm_encode(const snd_pcm_channel_area_t *dst_areas, 269 snd_pcm_uframes_t dst_offset, 270 const snd_pcm_channel_area_t *src_areas, 271 snd_pcm_uframes_t src_offset, 272 unsigned int channels, snd_pcm_uframes_t frames, 273 unsigned int getidx, 274 snd_pcm_adpcm_state_t *states) 275{ 276#define GET16_LABELS 277#include "plugin_ops.h" 278#undef GET16_LABELS 279 void *get = get16_labels[getidx]; 280 unsigned int channel; 281 int16_t sample = 0; 282 for (channel = 0; channel < channels; ++channel, ++states) { 283 const char *src; 284 char *dst; 285 int dstbit; 286 int src_step, dst_step, dstbit_step; 287 snd_pcm_uframes_t frames1; 288 const snd_pcm_channel_area_t *src_area = &src_areas[channel]; 289 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; 290 src = snd_pcm_channel_area_addr(src_area, src_offset); 291 src_step = snd_pcm_channel_area_step(src_area); 292 dstbit = dst_area->first + dst_area->step * dst_offset; 293 dst = (char *) dst_area->addr + dstbit / 8; 294 dstbit %= 8; 295 dst_step = dst_area->step / 8; 296 dstbit_step = dst_area->step % 8; 297 frames1 = frames; 298 while (frames1-- > 0) { 299 int v; 300 goto *get; 301#define GET16_END after 302#include "plugin_ops.h" 303#undef GET16_END 304 after: 305 v = adpcm_encoder(sample, states); 306 if (dstbit) 307 *dst = (*dst & 0xf0) | v; 308 else 309 *dst = (*dst & 0x0f) | (v << 4); 310 src += src_step; 311 dst += dst_step; 312 dstbit += dstbit_step; 313 if (dstbit == 8) { 314 dst++; 315 dstbit = 0; 316 } 317 } 318 } 319} 320 321#endif 322 323static int snd_pcm_adpcm_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 324{ 325 snd_pcm_adpcm_t *adpcm = pcm->private_data; 326 int err; 327 snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; 328 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 329 &access_mask); 330 if (err < 0) 331 return err; 332 if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { 333 snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; 334 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, 335 &format_mask); 336 } else { 337 err = _snd_pcm_hw_params_set_format(params, 338 SND_PCM_FORMAT_IMA_ADPCM); 339 } 340 if (err < 0) 341 return err; 342 err = _snd_pcm_hw_params_set_subformat(params, 343 SND_PCM_SUBFORMAT_STD); 344 if (err < 0) 345 return err; 346 params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); 347 return 0; 348} 349 350static int snd_pcm_adpcm_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) 351{ 352 snd_pcm_adpcm_t *adpcm = pcm->private_data; 353 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 354 _snd_pcm_hw_params_any(sparams); 355 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 356 &saccess_mask); 357 _snd_pcm_hw_params_set_format(sparams, adpcm->sformat); 358 _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); 359 return 0; 360} 361 362static int snd_pcm_adpcm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, 363 snd_pcm_hw_params_t *sparams) 364{ 365 int err; 366 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | 367 SND_PCM_HW_PARBIT_RATE | 368 SND_PCM_HW_PARBIT_PERIOD_SIZE | 369 SND_PCM_HW_PARBIT_BUFFER_SIZE | 370 SND_PCM_HW_PARBIT_PERIODS | 371 SND_PCM_HW_PARBIT_PERIOD_TIME | 372 SND_PCM_HW_PARBIT_BUFFER_TIME | 373 SND_PCM_HW_PARBIT_TICK_TIME); 374 err = _snd_pcm_hw_params_refine(sparams, links, params); 375 if (err < 0) 376 return err; 377 return 0; 378} 379 380static int snd_pcm_adpcm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, 381 snd_pcm_hw_params_t *sparams) 382{ 383 int err; 384 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | 385 SND_PCM_HW_PARBIT_RATE | 386 SND_PCM_HW_PARBIT_PERIOD_SIZE | 387 SND_PCM_HW_PARBIT_BUFFER_SIZE | 388 SND_PCM_HW_PARBIT_PERIODS | 389 SND_PCM_HW_PARBIT_PERIOD_TIME | 390 SND_PCM_HW_PARBIT_BUFFER_TIME | 391 SND_PCM_HW_PARBIT_TICK_TIME); 392 err = _snd_pcm_hw_params_refine(params, links, sparams); 393 if (err < 0) 394 return err; 395 return 0; 396} 397 398static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 399{ 400 return snd_pcm_hw_refine_slave(pcm, params, 401 snd_pcm_adpcm_hw_refine_cprepare, 402 snd_pcm_adpcm_hw_refine_cchange, 403 snd_pcm_adpcm_hw_refine_sprepare, 404 snd_pcm_adpcm_hw_refine_schange, 405 snd_pcm_generic_hw_refine); 406} 407 408static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) 409{ 410 snd_pcm_adpcm_t *adpcm = pcm->private_data; 411 snd_pcm_format_t format; 412 int err = snd_pcm_hw_params_slave(pcm, params, 413 snd_pcm_adpcm_hw_refine_cchange, 414 snd_pcm_adpcm_hw_refine_sprepare, 415 snd_pcm_adpcm_hw_refine_schange, 416 snd_pcm_generic_hw_params); 417 if (err < 0) 418 return err; 419 420 err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format); 421 if (err < 0) 422 return err; 423 424 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 425 if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { 426 adpcm->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S16); 427 adpcm->func = snd_pcm_adpcm_encode; 428 } else { 429 adpcm->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, adpcm->sformat); 430 adpcm->func = snd_pcm_adpcm_decode; 431 } 432 } else { 433 if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { 434 adpcm->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, format); 435 adpcm->func = snd_pcm_adpcm_decode; 436 } else { 437 adpcm->getput_idx = snd_pcm_linear_get_index(adpcm->sformat, SND_PCM_FORMAT_S16); 438 adpcm->func = snd_pcm_adpcm_encode; 439 } 440 } 441 assert(!adpcm->states); 442 adpcm->states = malloc(adpcm->plug.gen.slave->channels * sizeof(*adpcm->states)); 443 if (adpcm->states == NULL) 444 return -ENOMEM; 445 return 0; 446} 447 448static int snd_pcm_adpcm_hw_free(snd_pcm_t *pcm) 449{ 450 snd_pcm_adpcm_t *adpcm = pcm->private_data; 451 free(adpcm->states); 452 adpcm->states = NULL; 453 return snd_pcm_hw_free(adpcm->plug.gen.slave); 454} 455 456static int snd_pcm_adpcm_init(snd_pcm_t *pcm) 457{ 458 snd_pcm_adpcm_t *adpcm = pcm->private_data; 459 unsigned int k; 460 for (k = 0; k < pcm->channels; ++k) { 461 adpcm->states[k].pred_val = 0; 462 adpcm->states[k].step_idx = 0; 463 } 464 return 0; 465} 466 467static snd_pcm_uframes_t 468snd_pcm_adpcm_write_areas(snd_pcm_t *pcm, 469 const snd_pcm_channel_area_t *areas, 470 snd_pcm_uframes_t offset, 471 snd_pcm_uframes_t size, 472 const snd_pcm_channel_area_t *slave_areas, 473 snd_pcm_uframes_t slave_offset, 474 snd_pcm_uframes_t *slave_sizep) 475{ 476 snd_pcm_adpcm_t *adpcm = pcm->private_data; 477 if (size > *slave_sizep) 478 size = *slave_sizep; 479 adpcm->func(slave_areas, slave_offset, 480 areas, offset, 481 pcm->channels, size, 482 adpcm->getput_idx, adpcm->states); 483 *slave_sizep = size; 484 return size; 485} 486 487static snd_pcm_uframes_t 488snd_pcm_adpcm_read_areas(snd_pcm_t *pcm, 489 const snd_pcm_channel_area_t *areas, 490 snd_pcm_uframes_t offset, 491 snd_pcm_uframes_t size, 492 const snd_pcm_channel_area_t *slave_areas, 493 snd_pcm_uframes_t slave_offset, 494 snd_pcm_uframes_t *slave_sizep) 495{ 496 snd_pcm_adpcm_t *adpcm = pcm->private_data; 497 if (size > *slave_sizep) 498 size = *slave_sizep; 499 adpcm->func(areas, offset, 500 slave_areas, slave_offset, 501 pcm->channels, size, 502 adpcm->getput_idx, adpcm->states); 503 *slave_sizep = size; 504 return size; 505} 506 507static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, snd_output_t *out) 508{ 509 snd_pcm_adpcm_t *adpcm = pcm->private_data; 510 snd_output_printf(out, "Ima-ADPCM conversion PCM (%s)\n", 511 snd_pcm_format_name(adpcm->sformat)); 512 if (pcm->setup) { 513 snd_output_printf(out, "Its setup is:\n"); 514 snd_pcm_dump_setup(pcm, out); 515 } 516 snd_output_printf(out, "Slave: "); 517 snd_pcm_dump(adpcm->plug.gen.slave, out); 518} 519 520static const snd_pcm_ops_t snd_pcm_adpcm_ops = { 521 .close = snd_pcm_generic_close, 522 .info = snd_pcm_generic_info, 523 .hw_refine = snd_pcm_adpcm_hw_refine, 524 .hw_params = snd_pcm_adpcm_hw_params, 525 .hw_free = snd_pcm_adpcm_hw_free, 526 .sw_params = snd_pcm_generic_sw_params, 527 .channel_info = snd_pcm_generic_channel_info, 528 .dump = snd_pcm_adpcm_dump, 529 .nonblock = snd_pcm_generic_nonblock, 530 .async = snd_pcm_generic_async, 531 .mmap = snd_pcm_generic_mmap, 532 .munmap = snd_pcm_generic_munmap, 533 .query_chmaps = snd_pcm_generic_query_chmaps, 534 .get_chmap = snd_pcm_generic_get_chmap, 535 .set_chmap = snd_pcm_generic_set_chmap, 536}; 537 538/** 539 * \brief Creates a new Ima-ADPCM conversion PCM 540 * \param pcmp Returns created PCM handle 541 * \param name Name of PCM 542 * \param sformat Slave (destination) format 543 * \param slave Slave PCM handle 544 * \param close_slave When set, the slave PCM handle is closed with copy PCM 545 * \retval zero on success otherwise a negative error code 546 * \warning Using of this function might be dangerous in the sense 547 * of compatibility reasons. The prototype might be freely 548 * changed in future. 549 */ 550int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave) 551{ 552 snd_pcm_t *pcm; 553 snd_pcm_adpcm_t *adpcm; 554 int err; 555 assert(pcmp && slave); 556 if (snd_pcm_format_linear(sformat) != 1 && 557 sformat != SND_PCM_FORMAT_IMA_ADPCM) 558 return -EINVAL; 559 adpcm = calloc(1, sizeof(snd_pcm_adpcm_t)); 560 if (!adpcm) { 561 return -ENOMEM; 562 } 563 adpcm->sformat = sformat; 564 snd_pcm_plugin_init(&adpcm->plug); 565 adpcm->plug.read = snd_pcm_adpcm_read_areas; 566 adpcm->plug.write = snd_pcm_adpcm_write_areas; 567 adpcm->plug.init = snd_pcm_adpcm_init; 568 adpcm->plug.gen.slave = slave; 569 adpcm->plug.gen.close_slave = close_slave; 570 571 err = snd_pcm_new(&pcm, SND_PCM_TYPE_ADPCM, name, slave->stream, slave->mode); 572 if (err < 0) { 573 free(adpcm); 574 return err; 575 } 576 pcm->ops = &snd_pcm_adpcm_ops; 577 pcm->fast_ops = &snd_pcm_plugin_fast_ops; 578 pcm->private_data = adpcm; 579 pcm->poll_fd = slave->poll_fd; 580 pcm->poll_events = slave->poll_events; 581 pcm->tstamp_type = slave->tstamp_type; 582 snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0); 583 snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0); 584 *pcmp = pcm; 585 586 return 0; 587} 588 589/*! \page pcm_plugins 590 591\section pcm_plugins_adpcm Plugin: Ima-ADPCM 592 593This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples 594from master Ima-ADPCM conversion PCM to given slave PCM. The channel count, 595format and rate must match for both of them. 596 597\code 598pcm.name { 599 type adpcm # Ima-ADPCM conversion PCM 600 slave STR # Slave name 601 # or 602 slave { # Slave definition 603 pcm STR # Slave PCM name 604 # or 605 pcm { } # Slave PCM definition 606 format STR # Slave format 607 } 608} 609\endcode 610 611\subsection pcm_plugins_adpcm_funcref Function reference 612 613<UL> 614 <LI>snd_pcm_adpcm_open() 615 <LI>_snd_pcm_adpcm_open() 616</UL> 617 618*/ 619 620/** 621 * \brief Creates a new Ima-ADPCM conversion PCM 622 * \param pcmp Returns created PCM handle 623 * \param name Name of PCM 624 * \param root Root configuration node 625 * \param conf Configuration node with copy PCM description 626 * \param stream Stream type 627 * \param mode Stream mode 628 * \retval zero on success otherwise a negative error code 629 * \warning Using of this function might be dangerous in the sense 630 * of compatibility reasons. The prototype might be freely 631 * changed in future. 632 */ 633int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, 634 snd_config_t *root, snd_config_t *conf, 635 snd_pcm_stream_t stream, int mode) 636{ 637 snd_config_iterator_t i, next; 638 int err; 639 snd_pcm_t *spcm; 640 snd_config_t *slave = NULL, *sconf; 641 snd_pcm_format_t sformat; 642 snd_config_for_each(i, next, conf) { 643 snd_config_t *n = snd_config_iterator_entry(i); 644 const char *id; 645 if (snd_config_get_id(n, &id) < 0) 646 continue; 647 if (snd_pcm_conf_generic_id(id)) 648 continue; 649 if (strcmp(id, "slave") == 0) { 650 slave = n; 651 continue; 652 } 653 SNDERR("Unknown field %s", id); 654 return -EINVAL; 655 } 656 if (!slave) { 657 SNDERR("slave is not defined"); 658 return -EINVAL; 659 } 660 err = snd_pcm_slave_conf(root, slave, &sconf, 1, 661 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); 662 if (err < 0) 663 return err; 664 if (snd_pcm_format_linear(sformat) != 1 && 665 sformat != SND_PCM_FORMAT_IMA_ADPCM) { 666 snd_config_delete(sconf); 667 SNDERR("invalid slave format"); 668 return -EINVAL; 669 } 670 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 671 snd_config_delete(sconf); 672 if (err < 0) 673 return err; 674 err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1); 675 if (err < 0) 676 snd_pcm_close(spcm); 677 return err; 678} 679#ifndef DOC_HIDDEN 680SND_DLSYM_BUILD_VERSION(_snd_pcm_adpcm_open, SND_PCM_DLSYM_VERSION); 681#endif 682