• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/iserver/alsa-lib-1.0.26/src/pcm/

Lines Matching defs:*

2  * \file pcm/pcm_alaw.c
3 * \ingroup PCM_Plugins
4 * \brief PCM A-Law Conversion Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \date 2000-2001
9 * PCM - A-Law conversion
10 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <byteswap.h>
30 #include "pcm_local.h"
31 #include "pcm_plugin.h"
33 #include "plugin_ops.h"
35 #ifndef PIC
36 /* entry for static linking */
37 const char *_snd_module_pcm_alaw = "";
38 #endif
40 #ifndef DOC_HIDDEN
42 typedef void (*alaw_f)(const snd_pcm_channel_area_t *dst_areas,
43 snd_pcm_uframes_t dst_offset,
44 const snd_pcm_channel_area_t *src_areas,
45 snd_pcm_uframes_t src_offset,
46 unsigned int channels, snd_pcm_uframes_t frames,
47 unsigned int getputidx);
49 typedef struct {
50 /* This field need to be the first */
51 snd_pcm_plugin_t plug;
52 unsigned int getput_idx;
53 alaw_f func;
54 snd_pcm_format_t sformat;
55 } snd_pcm_alaw_t;
57 #endif
59 static inline int val_seg(int val)
61 int r = 1;
62 val >>= 8;
63 if (val & 0xf0) {
64 val >>= 4;
65 r += 4;
67 if (val & 0x0c) {
68 val >>= 2;
69 r += 2;
71 if (val & 0x02)
72 r += 1;
73 return r;
77 * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
79 * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
81 * Linear Input Code Compressed Code
82 * ------------------------ ---------------
83 * 0000000wxyza 000wxyz
84 * 0000001wxyza 001wxyz
85 * 000001wxyzab 010wxyz
86 * 00001wxyzabc 011wxyz
87 * 0001wxyzabcd 100wxyz
88 * 001wxyzabcde 101wxyz
89 * 01wxyzabcdef 110wxyz
90 * 1wxyzabcdefg 111wxyz
92 * For further information see John C. Bellamy's Digital Telephony, 1982,
93 * John Wiley & Sons, pps 98-111 and 472-476.
96 static unsigned char s16_to_alaw(int pcm_val)
98 int mask;
99 int seg;
100 unsigned char aval;
102 if (pcm_val >= 0) {
103 mask = 0xD5;
104 } else {
105 mask = 0x55;
106 pcm_val = -pcm_val;
107 if (pcm_val > 0x7fff)
108 pcm_val = 0x7fff;
111 if (pcm_val < 256)
112 aval = pcm_val >> 4;
113 else {
114 /* Convert the scaled magnitude to segment number. */
115 seg = val_seg(pcm_val);
116 aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
118 return aval ^ mask;
122 * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
125 static int alaw_to_s16(unsigned char a_val)
127 int t;
128 int seg;
130 a_val ^= 0x55;
131 t = a_val & 0x7f;
132 if (t < 16)
133 t = (t << 4) + 8;
134 else {
135 seg = (t >> 4) & 0x07;
136 t = ((t & 0x0f) << 4) + 0x108;
137 t <<= seg -1;
139 return ((a_val & 0x80) ? t : -t);
142 #ifndef DOC_HIDDEN
144 void snd_pcm_alaw_decode(const snd_pcm_channel_area_t *dst_areas,
145 snd_pcm_uframes_t dst_offset,
146 const snd_pcm_channel_area_t *src_areas,
147 snd_pcm_uframes_t src_offset,
148 unsigned int channels, snd_pcm_uframes_t frames,
149 unsigned int putidx)
151 #define PUT16_LABELS
152 #include "plugin_ops.h"
153 #undef PUT16_LABELS
154 void *put = put16_labels[putidx];
155 unsigned int channel;
156 for (channel = 0; channel < channels; ++channel) {
157 const unsigned char *src;
158 char *dst;
159 int src_step, dst_step;
160 snd_pcm_uframes_t frames1;
161 const snd_pcm_channel_area_t *src_area = &src_areas[channel];
162 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
163 src = snd_pcm_channel_area_addr(src_area, src_offset);
164 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
165 src_step = snd_pcm_channel_area_step(src_area);
166 dst_step = snd_pcm_channel_area_step(dst_area);
167 frames1 = frames;
168 while (frames1-- > 0) {
169 int16_t sample = alaw_to_s16(*src);
170 goto *put;
171 #define PUT16_END after
172 #include "plugin_ops.h"
173 #undef PUT16_END
174 after:
175 src += src_step;
176 dst += dst_step;
181 void snd_pcm_alaw_encode(const snd_pcm_channel_area_t *dst_areas,
182 snd_pcm_uframes_t dst_offset,
183 const snd_pcm_channel_area_t *src_areas,
184 snd_pcm_uframes_t src_offset,
185 unsigned int channels, snd_pcm_uframes_t frames,
186 unsigned int getidx)
188 #define GET16_LABELS
189 #include "plugin_ops.h"
190 #undef GET16_LABELS
191 void *get = get16_labels[getidx];
192 unsigned int channel;
193 int16_t sample = 0;
194 for (channel = 0; channel < channels; ++channel) {
195 const char *src;
196 char *dst;
197 int src_step, dst_step;
198 snd_pcm_uframes_t frames1;
199 const snd_pcm_channel_area_t *src_area = &src_areas[channel];
200 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
201 src = snd_pcm_channel_area_addr(src_area, src_offset);
202 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
203 src_step = snd_pcm_channel_area_step(src_area);
204 dst_step = snd_pcm_channel_area_step(dst_area);
205 frames1 = frames;
206 while (frames1-- > 0) {
207 goto *get;
208 #define GET16_END after
209 #include "plugin_ops.h"
210 #undef GET16_END
211 after:
212 *dst = s16_to_alaw(sample);
213 src += src_step;
214 dst += dst_step;
219 #endif /* DOC_HIDDEN */
221 static int snd_pcm_alaw_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
223 snd_pcm_alaw_t *alaw = pcm->private_data;
224 int err;
225 snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
226 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
227 &access_mask);
228 if (err < 0)
229 return err;
230 if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
231 snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR };
232 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
233 &format_mask);
234 } else {
235 err = _snd_pcm_hw_params_set_format(params,
236 SND_PCM_FORMAT_A_LAW);
238 if (err < 0)
239 return err;
240 err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
241 if (err < 0)
242 return err;
243 params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
244 return 0;
247 static int snd_pcm_alaw_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
249 snd_pcm_alaw_t *alaw = pcm->private_data;
250 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
251 _snd_pcm_hw_params_any(sparams);
252 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
253 &saccess_mask);
254 _snd_pcm_hw_params_set_format(sparams, alaw->sformat);
255 _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
256 return 0;
259 static int snd_pcm_alaw_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
260 snd_pcm_hw_params_t *sparams)
262 int err;
263 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
264 SND_PCM_HW_PARBIT_RATE |
265 SND_PCM_HW_PARBIT_PERIOD_SIZE |
266 SND_PCM_HW_PARBIT_BUFFER_SIZE |
267 SND_PCM_HW_PARBIT_PERIODS |
268 SND_PCM_HW_PARBIT_PERIOD_TIME |
269 SND_PCM_HW_PARBIT_BUFFER_TIME |
270 SND_PCM_HW_PARBIT_TICK_TIME);
271 err = _snd_pcm_hw_params_refine(sparams, links, params);
272 if (err < 0)
273 return err;
274 return 0;
277 static int snd_pcm_alaw_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
278 snd_pcm_hw_params_t *sparams)
280 int err;
281 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
282 SND_PCM_HW_PARBIT_RATE |
283 SND_PCM_HW_PARBIT_PERIOD_SIZE |
284 SND_PCM_HW_PARBIT_BUFFER_SIZE |
285 SND_PCM_HW_PARBIT_PERIODS |
286 SND_PCM_HW_PARBIT_PERIOD_TIME |
287 SND_PCM_HW_PARBIT_BUFFER_TIME |
288 SND_PCM_HW_PARBIT_TICK_TIME);
289 err = _snd_pcm_hw_params_refine(params, links, sparams);
290 if (err < 0)
291 return err;
292 return 0;
295 static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
297 return snd_pcm_hw_refine_slave(pcm, params,
298 snd_pcm_alaw_hw_refine_cprepare,
299 snd_pcm_alaw_hw_refine_cchange,
300 snd_pcm_alaw_hw_refine_sprepare,
301 snd_pcm_alaw_hw_refine_schange,
302 snd_pcm_generic_hw_refine);
305 static int snd_pcm_alaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
307 snd_pcm_alaw_t *alaw = pcm->private_data;
308 snd_pcm_format_t format;
309 int err = snd_pcm_hw_params_slave(pcm, params,
310 snd_pcm_alaw_hw_refine_cchange,
311 snd_pcm_alaw_hw_refine_sprepare,
312 snd_pcm_alaw_hw_refine_schange,
313 snd_pcm_generic_hw_params);
314 if (err < 0)
315 return err;
317 err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format);
318 if (err < 0)
319 return err;
321 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
322 if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
323 alaw->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S16);
324 alaw->func = snd_pcm_alaw_encode;
325 } else {
326 alaw->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, alaw->sformat);
327 alaw->func = snd_pcm_alaw_decode;
329 } else {
330 if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
331 alaw->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, format);
332 alaw->func = snd_pcm_alaw_decode;
333 } else {
334 alaw->getput_idx = snd_pcm_linear_get_index(alaw->sformat, SND_PCM_FORMAT_S16);
335 alaw->func = snd_pcm_alaw_encode;
338 return 0;
341 static snd_pcm_uframes_t
342 snd_pcm_alaw_write_areas(snd_pcm_t *pcm,
343 const snd_pcm_channel_area_t *areas,
344 snd_pcm_uframes_t offset,
345 snd_pcm_uframes_t size,
346 const snd_pcm_channel_area_t *slave_areas,
347 snd_pcm_uframes_t slave_offset,
348 snd_pcm_uframes_t *slave_sizep)
350 snd_pcm_alaw_t *alaw = pcm->private_data;
351 if (size > *slave_sizep)
352 size = *slave_sizep;
353 alaw->func(slave_areas, slave_offset,
354 areas, offset,
355 pcm->channels, size,
356 alaw->getput_idx);
357 *slave_sizep = size;
358 return size;
361 static snd_pcm_uframes_t
362 snd_pcm_alaw_read_areas(snd_pcm_t *pcm,
363 const snd_pcm_channel_area_t *areas,
364 snd_pcm_uframes_t offset,
365 snd_pcm_uframes_t size,
366 const snd_pcm_channel_area_t *slave_areas,
367 snd_pcm_uframes_t slave_offset,
368 snd_pcm_uframes_t *slave_sizep)
370 snd_pcm_alaw_t *alaw = pcm->private_data;
371 if (size > *slave_sizep)
372 size = *slave_sizep;
373 alaw->func(areas, offset,
374 slave_areas, slave_offset,
375 pcm->channels, size,
376 alaw->getput_idx);
377 *slave_sizep = size;
378 return size;
381 static void snd_pcm_alaw_dump(snd_pcm_t *pcm, snd_output_t *out)
383 snd_pcm_alaw_t *alaw = pcm->private_data;
384 snd_output_printf(out, "A-Law conversion PCM (%s)\n",
385 snd_pcm_format_name(alaw->sformat));
386 if (pcm->setup) {
387 snd_output_printf(out, "Its setup is:\n");
388 snd_pcm_dump_setup(pcm, out);
390 snd_output_printf(out, "Slave: ");
391 snd_pcm_dump(alaw->plug.gen.slave, out);
394 static const snd_pcm_ops_t snd_pcm_alaw_ops = {
395 .close = snd_pcm_generic_close,
396 .info = snd_pcm_generic_info,
397 .hw_refine = snd_pcm_alaw_hw_refine,
398 .hw_params = snd_pcm_alaw_hw_params,
399 .hw_free = snd_pcm_generic_hw_free,
400 .sw_params = snd_pcm_generic_sw_params,
401 .channel_info = snd_pcm_generic_channel_info,
402 .dump = snd_pcm_alaw_dump,
403 .nonblock = snd_pcm_generic_nonblock,
404 .async = snd_pcm_generic_async,
405 .mmap = snd_pcm_generic_mmap,
406 .munmap = snd_pcm_generic_munmap,
410 * \brief Creates a new A-Law conversion PCM
411 * \param pcmp Returns created PCM handle
412 * \param name Name of PCM
413 * \param sformat Slave (destination) format
414 * \param slave Slave PCM handle
415 * \param close_slave When set, the slave PCM handle is closed with copy PCM
416 * \retval zero on success otherwise a negative error code
417 * \warning Using of this function might be dangerous in the sense
418 * of compatibility reasons. The prototype might be freely
419 * changed in future.
421 int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave)
423 snd_pcm_t *pcm;
424 snd_pcm_alaw_t *alaw;
425 int err;
426 assert(pcmp && slave);
427 if (snd_pcm_format_linear(sformat) != 1 &&
428 sformat != SND_PCM_FORMAT_A_LAW)
429 return -EINVAL;
430 alaw = calloc(1, sizeof(snd_pcm_alaw_t));
431 if (!alaw) {
432 return -ENOMEM;
434 snd_pcm_plugin_init(&alaw->plug);
435 alaw->sformat = sformat;
436 alaw->plug.read = snd_pcm_alaw_read_areas;
437 alaw->plug.write = snd_pcm_alaw_write_areas;
438 alaw->plug.undo_read = snd_pcm_plugin_undo_read_generic;
439 alaw->plug.undo_write = snd_pcm_plugin_undo_write_generic;
440 alaw->plug.gen.slave = slave;
441 alaw->plug.gen.close_slave = close_slave;
443 err = snd_pcm_new(&pcm, SND_PCM_TYPE_ALAW, name, slave->stream, slave->mode);
444 if (err < 0) {
445 free(alaw);
446 return err;
448 pcm->ops = &snd_pcm_alaw_ops;
449 pcm->fast_ops = &snd_pcm_plugin_fast_ops;
450 pcm->private_data = alaw;
451 pcm->poll_fd = slave->poll_fd;
452 pcm->poll_events = slave->poll_events;
453 pcm->monotonic = slave->monotonic;
454 snd_pcm_set_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0);
455 snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0);
456 *pcmp = pcm;
458 return 0;
461 /*! \page pcm_plugins
463 \section pcm_plugins_alaw Plugin: A-Law
465 This plugin converts A-Law samples to linear or linear to A-Law samples
466 from master A-Law conversion PCM to given slave PCM. The channel count,
467 format and rate must match for both of them.
469 \code
470 pcm.name {
471 type alaw # A-Law conversion PCM
472 slave STR # Slave name
473 # or
474 slave { # Slave definition
475 pcm STR # Slave PCM name
476 # or
477 pcm { } # Slave PCM definition
478 format STR # Slave format
481 \endcode
483 \subsection pcm_plugins_alaw_funcref Function reference
485 <UL>
486 <LI>snd_pcm_alaw_open()
487 <LI>_snd_pcm_alaw_open()
488 </UL>
493 * \brief Creates a new A-Law conversion PCM
494 * \param pcmp Returns created PCM handle
495 * \param name Name of PCM
496 * \param root Root configuration node
497 * \param conf Configuration node with copy PCM description
498 * \param stream Stream type
499 * \param mode Stream mode
500 * \retval zero on success otherwise a negative error code
501 * \warning Using of this function might be dangerous in the sense
502 * of compatibility reasons. The prototype might be freely
503 * changed in future.
505 int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name,
506 snd_config_t *root, snd_config_t *conf,
507 snd_pcm_stream_t stream, int mode)
509 snd_config_iterator_t i, next;
510 int err;
511 snd_pcm_t *spcm;
512 snd_config_t *slave = NULL, *sconf;
513 snd_pcm_format_t sformat;
514 snd_config_for_each(i, next, conf) {
515 snd_config_t *n = snd_config_iterator_entry(i);
516 const char *id;
517 if (snd_config_get_id(n, &id) < 0)
518 continue;
519 if (snd_pcm_conf_generic_id(id))
520 continue;
521 if (strcmp(id, "slave") == 0) {
522 slave = n;
523 continue;
525 SNDERR("Unknown field %s", id);
526 return -EINVAL;
528 if (!slave) {
529 SNDERR("slave is not defined");
530 return -EINVAL;
532 err = snd_pcm_slave_conf(root, slave, &sconf, 1,
533 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
534 if (err < 0)
535 return err;
536 if (snd_pcm_format_linear(sformat) != 1 &&
537 sformat != SND_PCM_FORMAT_A_LAW) {
538 snd_config_delete(sconf);
539 SNDERR("invalid slave format");
540 return -EINVAL;
542 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
543 snd_config_delete(sconf);
544 if (err < 0)
545 return err;
546 err = snd_pcm_alaw_open(pcmp, name, sformat, spcm, 1);
547 if (err < 0)
548 snd_pcm_close(spcm);
549 return err;
551 #ifndef DOC_HIDDEN
552 SND_DLSYM_BUILD_VERSION(_snd_pcm_alaw_open, SND_PCM_DLSYM_VERSION);
553 #endif