2 * \file pcm/pcm_lfloat.c
4 * \brief PCM Linear<->Float Conversion Plugin Interface
5 * \author Jaroslav Kysela <perex@perex.cz>
9 * PCM - Linear Integer <-> Linear Float conversion
10 * Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
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
30 #include "pcm_local.h"
31 #include "pcm_plugin.h"
33 #include "plugin_ops.h"
37 typedef float float_t;
38 typedef double double_t;
40 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 91)
45 /* entry for static linking */
46 const char *_snd_module_pcm_lfloat = "";
50 /* This field need to be the first */
51 snd_pcm_plugin_t plug;
52 unsigned int int32_idx;
53 unsigned int float32_idx;
54 snd_pcm_format_t sformat;
55 void (*func)(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
56 const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
57 unsigned int channels, snd_pcm_uframes_t frames,
58 unsigned int get32idx, unsigned int put32floatidx);
61 int snd_pcm_lfloat_get_s32_index(snd_pcm_format_t format)
66 case SND_PCM_FORMAT_FLOAT_LE:
67 case SND_PCM_FORMAT_FLOAT_BE:
70 case SND_PCM_FORMAT_FLOAT64_LE:
71 case SND_PCM_FORMAT_FLOAT64_BE:
77 #ifdef SND_LITTLE_ENDIAN
78 endian = snd_pcm_format_big_endian(format);
80 endian = snd_pcm_format_little_endian(format);
82 return ((width / 32)-1) * 2 + endian;
85 int snd_pcm_lfloat_put_s32_index(snd_pcm_format_t format)
87 return snd_pcm_lfloat_get_s32_index(format);
90 #endif /* DOC_HIDDEN */
96 void snd_pcm_lfloat_convert_integer_float(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
97 const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
98 unsigned int channels, snd_pcm_uframes_t frames,
99 unsigned int get32idx, unsigned int put32floatidx)
102 #define PUT32F_LABELS
103 #include "plugin_ops.h"
106 void *get32 = get32_labels[get32idx];
107 void *put32float = put32float_labels[put32floatidx];
108 unsigned int channel;
109 for (channel = 0; channel < channels; ++channel) {
112 int src_step, dst_step;
113 snd_pcm_uframes_t frames1;
115 snd_tmp_float_t tmp_float;
116 snd_tmp_double_t tmp_double;
117 const snd_pcm_channel_area_t *src_area = &src_areas[channel];
118 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
119 src = snd_pcm_channel_area_addr(src_area, src_offset);
120 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
121 src_step = snd_pcm_channel_area_step(src_area);
122 dst_step = snd_pcm_channel_area_step(dst_area);
124 while (frames1-- > 0) {
126 #define GET32_END sample_loaded
127 #include "plugin_ops.h"
131 #define PUT32F_END sample_put
132 #include "plugin_ops.h"
141 void snd_pcm_lfloat_convert_float_integer(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
142 const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
143 unsigned int channels, snd_pcm_uframes_t frames,
144 unsigned int put32idx, unsigned int get32floatidx)
147 #define GET32F_LABELS
148 #include "plugin_ops.h"
151 void *put32 = put32_labels[put32idx];
152 void *get32float = get32float_labels[get32floatidx];
153 unsigned int channel;
154 for (channel = 0; channel < channels; ++channel) {
157 int src_step, dst_step;
158 snd_pcm_uframes_t frames1;
160 snd_tmp_float_t tmp_float;
161 snd_tmp_double_t tmp_double;
162 const snd_pcm_channel_area_t *src_area = &src_areas[channel];
163 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
164 src = snd_pcm_channel_area_addr(src_area, src_offset);
165 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
166 src_step = snd_pcm_channel_area_step(src_area);
167 dst_step = snd_pcm_channel_area_step(dst_area);
169 while (frames1-- > 0) {
171 #define GET32F_END sample_loaded
172 #include "plugin_ops.h"
176 #define PUT32_END sample_put
177 #include "plugin_ops.h"
186 #endif /* DOC_HIDDEN */
188 static int snd_pcm_lfloat_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
190 snd_pcm_lfloat_t *lfloat = pcm->private_data;
192 snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
193 snd_pcm_format_mask_t lformat_mask = { SND_PCM_FMTBIT_LINEAR };
194 snd_pcm_format_mask_t fformat_mask = { SND_PCM_FMTBIT_FLOAT };
195 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
199 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
200 snd_pcm_format_linear(lfloat->sformat) ?
201 &fformat_mask : &lformat_mask);
204 err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
207 params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
211 static int snd_pcm_lfloat_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
213 snd_pcm_lfloat_t *lfloat = pcm->private_data;
214 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
215 _snd_pcm_hw_params_any(sparams);
216 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
218 _snd_pcm_hw_params_set_format(sparams, lfloat->sformat);
219 _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
223 static int snd_pcm_lfloat_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
224 snd_pcm_hw_params_t *sparams)
227 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
228 SND_PCM_HW_PARBIT_RATE |
229 SND_PCM_HW_PARBIT_PERIOD_SIZE |
230 SND_PCM_HW_PARBIT_BUFFER_SIZE |
231 SND_PCM_HW_PARBIT_PERIODS |
232 SND_PCM_HW_PARBIT_PERIOD_TIME |
233 SND_PCM_HW_PARBIT_BUFFER_TIME |
234 SND_PCM_HW_PARBIT_TICK_TIME);
235 err = _snd_pcm_hw_params_refine(sparams, links, params);
241 static int snd_pcm_lfloat_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
242 snd_pcm_hw_params_t *sparams)
245 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
246 SND_PCM_HW_PARBIT_RATE |
247 SND_PCM_HW_PARBIT_PERIOD_SIZE |
248 SND_PCM_HW_PARBIT_BUFFER_SIZE |
249 SND_PCM_HW_PARBIT_PERIODS |
250 SND_PCM_HW_PARBIT_PERIOD_TIME |
251 SND_PCM_HW_PARBIT_BUFFER_TIME |
252 SND_PCM_HW_PARBIT_TICK_TIME);
253 err = _snd_pcm_hw_params_refine(params, links, sparams);
259 static int snd_pcm_lfloat_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
261 return snd_pcm_hw_refine_slave(pcm, params,
262 snd_pcm_lfloat_hw_refine_cprepare,
263 snd_pcm_lfloat_hw_refine_cchange,
264 snd_pcm_lfloat_hw_refine_sprepare,
265 snd_pcm_lfloat_hw_refine_schange,
266 snd_pcm_generic_hw_refine);
269 static int snd_pcm_lfloat_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
271 snd_pcm_lfloat_t *lfloat = pcm->private_data;
272 snd_pcm_t *slave = lfloat->plug.gen.slave;
273 snd_pcm_format_t src_format, dst_format;
274 int err = snd_pcm_hw_params_slave(pcm, params,
275 snd_pcm_lfloat_hw_refine_cchange,
276 snd_pcm_lfloat_hw_refine_sprepare,
277 snd_pcm_lfloat_hw_refine_schange,
278 snd_pcm_generic_hw_params);
281 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
282 err = INTERNAL(snd_pcm_hw_params_get_format)(params, &src_format);
283 dst_format = slave->format;
285 src_format = slave->format;
286 err = INTERNAL(snd_pcm_hw_params_get_format)(params, &dst_format);
288 if (snd_pcm_format_linear(src_format)) {
289 lfloat->int32_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32);
290 lfloat->float32_idx = snd_pcm_lfloat_put_s32_index(dst_format);
291 lfloat->func = snd_pcm_lfloat_convert_integer_float;
293 lfloat->int32_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
294 lfloat->float32_idx = snd_pcm_lfloat_get_s32_index(src_format);
295 lfloat->func = snd_pcm_lfloat_convert_float_integer;
300 static snd_pcm_uframes_t
301 snd_pcm_lfloat_write_areas(snd_pcm_t *pcm,
302 const snd_pcm_channel_area_t *areas,
303 snd_pcm_uframes_t offset,
304 snd_pcm_uframes_t size,
305 const snd_pcm_channel_area_t *slave_areas,
306 snd_pcm_uframes_t slave_offset,
307 snd_pcm_uframes_t *slave_sizep)
309 snd_pcm_lfloat_t *lfloat = pcm->private_data;
310 if (size > *slave_sizep)
312 lfloat->func(slave_areas, slave_offset,
315 lfloat->int32_idx, lfloat->float32_idx);
320 static snd_pcm_uframes_t
321 snd_pcm_lfloat_read_areas(snd_pcm_t *pcm,
322 const snd_pcm_channel_area_t *areas,
323 snd_pcm_uframes_t offset,
324 snd_pcm_uframes_t size,
325 const snd_pcm_channel_area_t *slave_areas,
326 snd_pcm_uframes_t slave_offset,
327 snd_pcm_uframes_t *slave_sizep)
329 snd_pcm_lfloat_t *lfloat = pcm->private_data;
330 if (size > *slave_sizep)
332 lfloat->func(areas, offset,
333 slave_areas, slave_offset,
335 lfloat->int32_idx, lfloat->float32_idx);
340 static void snd_pcm_lfloat_dump(snd_pcm_t *pcm, snd_output_t *out)
342 snd_pcm_lfloat_t *lfloat = pcm->private_data;
343 snd_output_printf(out, "Linear Integer <-> Linear Float conversion PCM (%s)\n",
344 snd_pcm_format_name(lfloat->sformat));
346 snd_output_printf(out, "Its setup is:\n");
347 snd_pcm_dump_setup(pcm, out);
349 snd_output_printf(out, "Slave: ");
350 snd_pcm_dump(lfloat->plug.gen.slave, out);
353 static snd_pcm_ops_t snd_pcm_lfloat_ops = {
354 .close = snd_pcm_generic_close,
355 .info = snd_pcm_generic_info,
356 .hw_refine = snd_pcm_lfloat_hw_refine,
357 .hw_params = snd_pcm_lfloat_hw_params,
358 .hw_free = snd_pcm_generic_hw_free,
359 .sw_params = snd_pcm_generic_sw_params,
360 .channel_info = snd_pcm_generic_channel_info,
361 .dump = snd_pcm_lfloat_dump,
362 .nonblock = snd_pcm_generic_nonblock,
363 .async = snd_pcm_generic_async,
364 .mmap = snd_pcm_generic_mmap,
365 .munmap = snd_pcm_generic_munmap,
369 * \brief Creates a new linear conversion PCM
370 * \param pcmp Returns created PCM handle
371 * \param name Name of PCM
372 * \param sformat Slave (destination) format
373 * \param slave Slave PCM handle
374 * \param close_slave When set, the slave PCM handle is closed with copy PCM
375 * \retval zero on success otherwise a negative error code
376 * \warning Using of this function might be dangerous in the sense
377 * of compatibility reasons. The prototype might be freely
380 int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave)
383 snd_pcm_lfloat_t *lfloat;
385 assert(pcmp && slave);
386 if (snd_pcm_format_linear(sformat) != 1 &&
387 snd_pcm_format_float(sformat) != 1)
389 lfloat = calloc(1, sizeof(snd_pcm_lfloat_t));
393 snd_pcm_plugin_init(&lfloat->plug);
394 lfloat->sformat = sformat;
395 lfloat->plug.read = snd_pcm_lfloat_read_areas;
396 lfloat->plug.write = snd_pcm_lfloat_write_areas;
397 lfloat->plug.undo_read = snd_pcm_plugin_undo_read_generic;
398 lfloat->plug.undo_write = snd_pcm_plugin_undo_write_generic;
399 lfloat->plug.gen.slave = slave;
400 lfloat->plug.gen.close_slave = close_slave;
402 err = snd_pcm_new(&pcm, SND_PCM_TYPE_LINEAR_FLOAT, name, slave->stream, slave->mode);
407 pcm->ops = &snd_pcm_lfloat_ops;
408 pcm->fast_ops = &snd_pcm_plugin_fast_ops;
409 pcm->private_data = lfloat;
410 pcm->poll_fd = slave->poll_fd;
411 pcm->poll_events = slave->poll_events;
412 snd_pcm_set_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0);
413 snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0);
419 /*! \page pcm_plugins
421 \section pcm_plugins_lfloat Plugin: linear<->float
423 This plugin converts linear to float samples and float to linear samples from master
424 linear<->float conversion PCM to given slave PCM. The channel count, format and rate must
425 match for both of them.
429 type lfloat # Linear<->Float conversion PCM
430 slave STR # Slave name
432 slave { # Slave definition
433 pcm STR # Slave PCM name
435 pcm { } # Slave PCM definition
436 format STR # Slave format
441 \subsection pcm_plugins_lfloat_funcref Function reference
444 <LI>snd_pcm_lfloat_open()
445 <LI>_snd_pcm_lfloat_open()
451 * \brief Creates a new linear<->float conversion PCM
452 * \param pcmp Returns created PCM handle
453 * \param name Name of PCM
454 * \param root Root configuration node
455 * \param conf Configuration node with copy PCM description
456 * \param stream Stream type
457 * \param mode Stream mode
458 * \retval zero on success otherwise a negative error code
459 * \warning Using of this function might be dangerous in the sense
460 * of compatibility reasons. The prototype might be freely
463 int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name,
464 snd_config_t *root, snd_config_t *conf,
465 snd_pcm_stream_t stream, int mode)
467 snd_config_iterator_t i, next;
470 snd_config_t *slave = NULL, *sconf;
471 snd_pcm_format_t sformat;
472 snd_config_for_each(i, next, conf) {
473 snd_config_t *n = snd_config_iterator_entry(i);
475 if (snd_config_get_id(n, &id) < 0)
477 if (snd_pcm_conf_generic_id(id))
479 if (strcmp(id, "slave") == 0) {
483 SNDERR("Unknown field %s", id);
487 SNDERR("slave is not defined");
490 err = snd_pcm_slave_conf(root, slave, &sconf, 1,
491 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
494 if (snd_pcm_format_linear(sformat) != 1 &&
495 snd_pcm_format_float(sformat) != 1) {
496 snd_config_delete(sconf);
497 SNDERR("slave format is not linear integer or linear float");
500 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
501 snd_config_delete(sconf);
504 err = snd_pcm_lfloat_open(pcmp, name, sformat, spcm, 1);
510 SND_DLSYM_BUILD_VERSION(_snd_pcm_lfloat_open, SND_PCM_DLSYM_VERSION);
513 #else /* BUGGY_GCC */
515 int snd_pcm_lfloat_open(snd_pcm_t **pcmp ATTRIBUTE_UNUSED,
516 const char *name ATTRIBUTE_UNUSED,
517 snd_pcm_format_t sformat ATTRIBUTE_UNUSED,
518 snd_pcm_t *slave ATTRIBUTE_UNUSED,
519 int close_slave ATTRIBUTE_UNUSED)
521 SNDERR("please, upgrade your GCC to use lfloat plugin");
525 int _snd_pcm_lfloat_open(snd_pcm_t **pcmp ATTRIBUTE_UNUSED,
526 const char *name ATTRIBUTE_UNUSED,
527 snd_config_t *root ATTRIBUTE_UNUSED,
528 snd_config_t *conf ATTRIBUTE_UNUSED,
529 snd_pcm_stream_t stream ATTRIBUTE_UNUSED,
530 int mode ATTRIBUTE_UNUSED)
532 SNDERR("please, upgrade your GCC to use lfloat plugin");
536 #endif /* BUGGY_GCC */