185571bc7Sbellard /*
285571bc7Sbellard * QEMU Mixing engine
385571bc7Sbellard *
41d14ffa9Sbellard * Copyright (c) 2004-2005 Vassili Karpov (malc)
585571bc7Sbellard * Copyright (c) 1998 Fabrice Bellard
685571bc7Sbellard *
785571bc7Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy
885571bc7Sbellard * of this software and associated documentation files (the "Software"), to deal
985571bc7Sbellard * in the Software without restriction, including without limitation the rights
1085571bc7Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1185571bc7Sbellard * copies of the Software, and to permit persons to whom the Software is
1285571bc7Sbellard * furnished to do so, subject to the following conditions:
1385571bc7Sbellard *
1485571bc7Sbellard * The above copyright notice and this permission notice shall be included in
1585571bc7Sbellard * all copies or substantial portions of the Software.
1685571bc7Sbellard *
1785571bc7Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1885571bc7Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1985571bc7Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2085571bc7Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2185571bc7Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2285571bc7Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2385571bc7Sbellard * THE SOFTWARE.
2485571bc7Sbellard */
256086a565SPeter Maydell #include "qemu/osdep.h"
2658369e22SPaolo Bonzini #include "qemu/bswap.h"
273d4d16f4SPavel Dovgalyuk #include "qemu/error-report.h"
2887ecb68bSpbrook #include "audio.h"
2985571bc7Sbellard
301d14ffa9Sbellard #define AUDIO_CAP "mixeng"
311d14ffa9Sbellard #include "audio_int.h"
321d14ffa9Sbellard
331d14ffa9Sbellard /* 8 bit */
341d14ffa9Sbellard #define ENDIAN_CONVERSION natural
351d14ffa9Sbellard #define ENDIAN_CONVERT(v) (v)
361d14ffa9Sbellard
371d14ffa9Sbellard /* Signed 8 bit */
38a2885387SRoger Pau Monne #define BSIZE 8
39a2885387SRoger Pau Monne #define ITYPE int
401d14ffa9Sbellard #define IN_MIN SCHAR_MIN
411d14ffa9Sbellard #define IN_MAX SCHAR_MAX
4285571bc7Sbellard #define SIGNED
431d14ffa9Sbellard #define SHIFT 8
4485571bc7Sbellard #include "mixeng_template.h"
4585571bc7Sbellard #undef SIGNED
4685571bc7Sbellard #undef IN_MAX
4785571bc7Sbellard #undef IN_MIN
48a2885387SRoger Pau Monne #undef BSIZE
49a2885387SRoger Pau Monne #undef ITYPE
501d14ffa9Sbellard #undef SHIFT
5185571bc7Sbellard
521d14ffa9Sbellard /* Unsigned 8 bit */
53a2885387SRoger Pau Monne #define BSIZE 8
54a2885387SRoger Pau Monne #define ITYPE uint
5585571bc7Sbellard #define IN_MIN 0
5685571bc7Sbellard #define IN_MAX UCHAR_MAX
571d14ffa9Sbellard #define SHIFT 8
5885571bc7Sbellard #include "mixeng_template.h"
5985571bc7Sbellard #undef IN_MAX
6085571bc7Sbellard #undef IN_MIN
61a2885387SRoger Pau Monne #undef BSIZE
62a2885387SRoger Pau Monne #undef ITYPE
631d14ffa9Sbellard #undef SHIFT
6485571bc7Sbellard
651d14ffa9Sbellard #undef ENDIAN_CONVERT
661d14ffa9Sbellard #undef ENDIAN_CONVERSION
671d14ffa9Sbellard
681d14ffa9Sbellard /* Signed 16 bit */
69a2885387SRoger Pau Monne #define BSIZE 16
70a2885387SRoger Pau Monne #define ITYPE int
7185571bc7Sbellard #define IN_MIN SHRT_MIN
7285571bc7Sbellard #define IN_MAX SHRT_MAX
7385571bc7Sbellard #define SIGNED
741d14ffa9Sbellard #define SHIFT 16
751d14ffa9Sbellard #define ENDIAN_CONVERSION natural
761d14ffa9Sbellard #define ENDIAN_CONVERT(v) (v)
7785571bc7Sbellard #include "mixeng_template.h"
781d14ffa9Sbellard #undef ENDIAN_CONVERT
791d14ffa9Sbellard #undef ENDIAN_CONVERSION
801d14ffa9Sbellard #define ENDIAN_CONVERSION swap
811d14ffa9Sbellard #define ENDIAN_CONVERT(v) bswap16 (v)
821d14ffa9Sbellard #include "mixeng_template.h"
831d14ffa9Sbellard #undef ENDIAN_CONVERT
841d14ffa9Sbellard #undef ENDIAN_CONVERSION
8585571bc7Sbellard #undef SIGNED
8685571bc7Sbellard #undef IN_MAX
8785571bc7Sbellard #undef IN_MIN
88a2885387SRoger Pau Monne #undef BSIZE
89a2885387SRoger Pau Monne #undef ITYPE
901d14ffa9Sbellard #undef SHIFT
9185571bc7Sbellard
92f941aa25Sths /* Unsigned 16 bit */
93a2885387SRoger Pau Monne #define BSIZE 16
94a2885387SRoger Pau Monne #define ITYPE uint
9585571bc7Sbellard #define IN_MIN 0
9685571bc7Sbellard #define IN_MAX USHRT_MAX
971d14ffa9Sbellard #define SHIFT 16
981d14ffa9Sbellard #define ENDIAN_CONVERSION natural
991d14ffa9Sbellard #define ENDIAN_CONVERT(v) (v)
10085571bc7Sbellard #include "mixeng_template.h"
1011d14ffa9Sbellard #undef ENDIAN_CONVERT
1021d14ffa9Sbellard #undef ENDIAN_CONVERSION
1031d14ffa9Sbellard #define ENDIAN_CONVERSION swap
1041d14ffa9Sbellard #define ENDIAN_CONVERT(v) bswap16 (v)
1051d14ffa9Sbellard #include "mixeng_template.h"
1061d14ffa9Sbellard #undef ENDIAN_CONVERT
1071d14ffa9Sbellard #undef ENDIAN_CONVERSION
10885571bc7Sbellard #undef IN_MAX
10985571bc7Sbellard #undef IN_MIN
110a2885387SRoger Pau Monne #undef BSIZE
111a2885387SRoger Pau Monne #undef ITYPE
1121d14ffa9Sbellard #undef SHIFT
11385571bc7Sbellard
114f941aa25Sths /* Signed 32 bit */
115a2885387SRoger Pau Monne #define BSIZE 32
116a2885387SRoger Pau Monne #define ITYPE int
117f941aa25Sths #define IN_MIN INT32_MIN
118f941aa25Sths #define IN_MAX INT32_MAX
119f941aa25Sths #define SIGNED
120f941aa25Sths #define SHIFT 32
121f941aa25Sths #define ENDIAN_CONVERSION natural
122f941aa25Sths #define ENDIAN_CONVERT(v) (v)
123f941aa25Sths #include "mixeng_template.h"
124f941aa25Sths #undef ENDIAN_CONVERT
125f941aa25Sths #undef ENDIAN_CONVERSION
126f941aa25Sths #define ENDIAN_CONVERSION swap
127f941aa25Sths #define ENDIAN_CONVERT(v) bswap32 (v)
128f941aa25Sths #include "mixeng_template.h"
129f941aa25Sths #undef ENDIAN_CONVERT
130f941aa25Sths #undef ENDIAN_CONVERSION
131f941aa25Sths #undef SIGNED
132f941aa25Sths #undef IN_MAX
133f941aa25Sths #undef IN_MIN
134a2885387SRoger Pau Monne #undef BSIZE
135a2885387SRoger Pau Monne #undef ITYPE
136f941aa25Sths #undef SHIFT
137f941aa25Sths
138ad483a51Smalc /* Unsigned 32 bit */
139a2885387SRoger Pau Monne #define BSIZE 32
140a2885387SRoger Pau Monne #define ITYPE uint
141f941aa25Sths #define IN_MIN 0
142f941aa25Sths #define IN_MAX UINT32_MAX
143f941aa25Sths #define SHIFT 32
144f941aa25Sths #define ENDIAN_CONVERSION natural
145f941aa25Sths #define ENDIAN_CONVERT(v) (v)
146f941aa25Sths #include "mixeng_template.h"
147f941aa25Sths #undef ENDIAN_CONVERT
148f941aa25Sths #undef ENDIAN_CONVERSION
149f941aa25Sths #define ENDIAN_CONVERSION swap
150f941aa25Sths #define ENDIAN_CONVERT(v) bswap32 (v)
151f941aa25Sths #include "mixeng_template.h"
152f941aa25Sths #undef ENDIAN_CONVERT
153f941aa25Sths #undef ENDIAN_CONVERSION
154f941aa25Sths #undef IN_MAX
155f941aa25Sths #undef IN_MIN
156a2885387SRoger Pau Monne #undef BSIZE
157a2885387SRoger Pau Monne #undef ITYPE
158f941aa25Sths #undef SHIFT
159f941aa25Sths
160f941aa25Sths t_sample *mixeng_conv[2][2][2][3] = {
16185571bc7Sbellard {
16285571bc7Sbellard {
1631d14ffa9Sbellard {
1641d14ffa9Sbellard conv_natural_uint8_t_to_mono,
165f941aa25Sths conv_natural_uint16_t_to_mono,
166f941aa25Sths conv_natural_uint32_t_to_mono
16785571bc7Sbellard },
16885571bc7Sbellard {
1691d14ffa9Sbellard conv_natural_uint8_t_to_mono,
170f941aa25Sths conv_swap_uint16_t_to_mono,
171f941aa25Sths conv_swap_uint32_t_to_mono,
17285571bc7Sbellard }
17385571bc7Sbellard },
17485571bc7Sbellard {
17585571bc7Sbellard {
1761d14ffa9Sbellard conv_natural_int8_t_to_mono,
177f941aa25Sths conv_natural_int16_t_to_mono,
178f941aa25Sths conv_natural_int32_t_to_mono
17985571bc7Sbellard },
18085571bc7Sbellard {
1811d14ffa9Sbellard conv_natural_int8_t_to_mono,
182f941aa25Sths conv_swap_int16_t_to_mono,
183f941aa25Sths conv_swap_int32_t_to_mono
1841d14ffa9Sbellard }
1851d14ffa9Sbellard }
1861d14ffa9Sbellard },
1871d14ffa9Sbellard {
1881d14ffa9Sbellard {
1891d14ffa9Sbellard {
1901d14ffa9Sbellard conv_natural_uint8_t_to_stereo,
191f941aa25Sths conv_natural_uint16_t_to_stereo,
192f941aa25Sths conv_natural_uint32_t_to_stereo
1931d14ffa9Sbellard },
1941d14ffa9Sbellard {
1951d14ffa9Sbellard conv_natural_uint8_t_to_stereo,
196f941aa25Sths conv_swap_uint16_t_to_stereo,
197f941aa25Sths conv_swap_uint32_t_to_stereo
1981d14ffa9Sbellard }
1991d14ffa9Sbellard },
2001d14ffa9Sbellard {
2011d14ffa9Sbellard {
2021d14ffa9Sbellard conv_natural_int8_t_to_stereo,
203f941aa25Sths conv_natural_int16_t_to_stereo,
204f941aa25Sths conv_natural_int32_t_to_stereo
2051d14ffa9Sbellard },
2061d14ffa9Sbellard {
2071d14ffa9Sbellard conv_natural_int8_t_to_stereo,
208f941aa25Sths conv_swap_int16_t_to_stereo,
209f941aa25Sths conv_swap_int32_t_to_stereo,
2101d14ffa9Sbellard }
21185571bc7Sbellard }
21285571bc7Sbellard }
21385571bc7Sbellard };
21485571bc7Sbellard
215f941aa25Sths f_sample *mixeng_clip[2][2][2][3] = {
21685571bc7Sbellard {
21785571bc7Sbellard {
2181d14ffa9Sbellard {
2191d14ffa9Sbellard clip_natural_uint8_t_from_mono,
220f941aa25Sths clip_natural_uint16_t_from_mono,
221f941aa25Sths clip_natural_uint32_t_from_mono
22285571bc7Sbellard },
22385571bc7Sbellard {
2241d14ffa9Sbellard clip_natural_uint8_t_from_mono,
225f941aa25Sths clip_swap_uint16_t_from_mono,
226f941aa25Sths clip_swap_uint32_t_from_mono
22785571bc7Sbellard }
22885571bc7Sbellard },
22985571bc7Sbellard {
23085571bc7Sbellard {
2311d14ffa9Sbellard clip_natural_int8_t_from_mono,
232f941aa25Sths clip_natural_int16_t_from_mono,
233f941aa25Sths clip_natural_int32_t_from_mono
23485571bc7Sbellard },
23585571bc7Sbellard {
2361d14ffa9Sbellard clip_natural_int8_t_from_mono,
237f941aa25Sths clip_swap_int16_t_from_mono,
238f941aa25Sths clip_swap_int32_t_from_mono
2391d14ffa9Sbellard }
2401d14ffa9Sbellard }
2411d14ffa9Sbellard },
2421d14ffa9Sbellard {
2431d14ffa9Sbellard {
2441d14ffa9Sbellard {
2451d14ffa9Sbellard clip_natural_uint8_t_from_stereo,
246f941aa25Sths clip_natural_uint16_t_from_stereo,
247f941aa25Sths clip_natural_uint32_t_from_stereo
2481d14ffa9Sbellard },
2491d14ffa9Sbellard {
2501d14ffa9Sbellard clip_natural_uint8_t_from_stereo,
251f941aa25Sths clip_swap_uint16_t_from_stereo,
252f941aa25Sths clip_swap_uint32_t_from_stereo
2531d14ffa9Sbellard }
2541d14ffa9Sbellard },
2551d14ffa9Sbellard {
2561d14ffa9Sbellard {
2571d14ffa9Sbellard clip_natural_int8_t_from_stereo,
258f941aa25Sths clip_natural_int16_t_from_stereo,
259f941aa25Sths clip_natural_int32_t_from_stereo
2601d14ffa9Sbellard },
2611d14ffa9Sbellard {
2621d14ffa9Sbellard clip_natural_int8_t_from_stereo,
263f941aa25Sths clip_swap_int16_t_from_stereo,
264f941aa25Sths clip_swap_int32_t_from_stereo
2651d14ffa9Sbellard }
26685571bc7Sbellard }
26785571bc7Sbellard }
26885571bc7Sbellard };
26985571bc7Sbellard
270ed2a4a79SKővágó, Zoltán #ifdef FLOAT_MIXENG
271dd381319SVolker Rümelin #define CONV_NATURAL_FLOAT(x) (x)
272dd381319SVolker Rümelin #define CLIP_NATURAL_FLOAT(x) (x)
273ed2a4a79SKővágó, Zoltán #else
2749c61fcc8SVolker Rümelin /* macros to map [-1.f, 1.f] <-> [INT32_MIN, INT32_MAX + 1] */
2759c61fcc8SVolker Rümelin static const float float_scale = (int64_t)INT32_MAX + 1;
276dd381319SVolker Rümelin #define CONV_NATURAL_FLOAT(x) ((x) * float_scale)
277ed2a4a79SKővágó, Zoltán
278ed2a4a79SKővágó, Zoltán #ifdef RECIPROCAL
2799c61fcc8SVolker Rümelin static const float float_scale_reciprocal = 1.f / ((int64_t)INT32_MAX + 1);
280dd381319SVolker Rümelin #define CLIP_NATURAL_FLOAT(x) ((x) * float_scale_reciprocal)
281ed2a4a79SKővágó, Zoltán #else
282dd381319SVolker Rümelin #define CLIP_NATURAL_FLOAT(x) ((x) / float_scale)
283ed2a4a79SKővágó, Zoltán #endif
284ed2a4a79SKővágó, Zoltán #endif
285ed2a4a79SKővágó, Zoltán
286*5d978c5dSVolker Rümelin #define F32_TO_F32S(v) \
287*5d978c5dSVolker Rümelin bswap32((union { uint32_t i; float f; }){ .f = (v) }.i)
288*5d978c5dSVolker Rümelin #define F32S_TO_F32(v) \
289*5d978c5dSVolker Rümelin ((union { uint32_t i; float f; }){ .i = bswap32(v) }.f)
290*5d978c5dSVolker Rümelin
conv_natural_float_to_mono(struct st_sample * dst,const void * src,int samples)291ed2a4a79SKővágó, Zoltán static void conv_natural_float_to_mono(struct st_sample *dst, const void *src,
292180b044fSVolker Rümelin int samples)
293180b044fSVolker Rümelin {
2949ddb7c85SVolker Rümelin const float *in = src;
295180b044fSVolker Rümelin
296180b044fSVolker Rümelin while (samples--) {
297dd381319SVolker Rümelin dst->r = dst->l = CONV_NATURAL_FLOAT(*in++);
298180b044fSVolker Rümelin dst++;
299180b044fSVolker Rümelin }
300180b044fSVolker Rümelin }
301180b044fSVolker Rümelin
conv_swap_float_to_mono(struct st_sample * dst,const void * src,int samples)302*5d978c5dSVolker Rümelin static void conv_swap_float_to_mono(struct st_sample *dst, const void *src,
303*5d978c5dSVolker Rümelin int samples)
304*5d978c5dSVolker Rümelin {
305*5d978c5dSVolker Rümelin const uint32_t *in_f32s = src;
306*5d978c5dSVolker Rümelin
307*5d978c5dSVolker Rümelin while (samples--) {
308*5d978c5dSVolker Rümelin dst->r = dst->l = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++));
309*5d978c5dSVolker Rümelin dst++;
310*5d978c5dSVolker Rümelin }
311*5d978c5dSVolker Rümelin }
312*5d978c5dSVolker Rümelin
conv_natural_float_to_stereo(struct st_sample * dst,const void * src,int samples)313ed2a4a79SKővágó, Zoltán static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src,
314ed2a4a79SKővágó, Zoltán int samples)
315ed2a4a79SKővágó, Zoltán {
3169ddb7c85SVolker Rümelin const float *in = src;
317ed2a4a79SKővágó, Zoltán
318ed2a4a79SKővágó, Zoltán while (samples--) {
319dd381319SVolker Rümelin dst->l = CONV_NATURAL_FLOAT(*in++);
320dd381319SVolker Rümelin dst->r = CONV_NATURAL_FLOAT(*in++);
321ed2a4a79SKővágó, Zoltán dst++;
322ed2a4a79SKővágó, Zoltán }
323ed2a4a79SKővágó, Zoltán }
324ed2a4a79SKővágó, Zoltán
conv_swap_float_to_stereo(struct st_sample * dst,const void * src,int samples)325*5d978c5dSVolker Rümelin static void conv_swap_float_to_stereo(struct st_sample *dst, const void *src,
326*5d978c5dSVolker Rümelin int samples)
327*5d978c5dSVolker Rümelin {
328*5d978c5dSVolker Rümelin const uint32_t *in_f32s = src;
329*5d978c5dSVolker Rümelin
330*5d978c5dSVolker Rümelin while (samples--) {
331*5d978c5dSVolker Rümelin dst->l = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++));
332*5d978c5dSVolker Rümelin dst->r = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++));
333*5d978c5dSVolker Rümelin dst++;
334*5d978c5dSVolker Rümelin }
335*5d978c5dSVolker Rümelin }
336*5d978c5dSVolker Rümelin
337*5d978c5dSVolker Rümelin t_sample *mixeng_conv_float[2][2] = {
338*5d978c5dSVolker Rümelin {
339ed2a4a79SKővágó, Zoltán conv_natural_float_to_mono,
340*5d978c5dSVolker Rümelin conv_swap_float_to_mono,
341*5d978c5dSVolker Rümelin },
342*5d978c5dSVolker Rümelin {
343ed2a4a79SKővágó, Zoltán conv_natural_float_to_stereo,
344*5d978c5dSVolker Rümelin conv_swap_float_to_stereo,
345*5d978c5dSVolker Rümelin }
346ed2a4a79SKővágó, Zoltán };
347ed2a4a79SKővágó, Zoltán
clip_natural_float_from_mono(void * dst,const struct st_sample * src,int samples)348ed2a4a79SKővágó, Zoltán static void clip_natural_float_from_mono(void *dst, const struct st_sample *src,
349180b044fSVolker Rümelin int samples)
350180b044fSVolker Rümelin {
3519ddb7c85SVolker Rümelin float *out = dst;
352180b044fSVolker Rümelin
353180b044fSVolker Rümelin while (samples--) {
35433a93baeSVolker Rümelin *out++ = CLIP_NATURAL_FLOAT(src->l + src->r);
355180b044fSVolker Rümelin src++;
356180b044fSVolker Rümelin }
357180b044fSVolker Rümelin }
3583d4d16f4SPavel Dovgalyuk
clip_swap_float_from_mono(void * dst,const struct st_sample * src,int samples)359*5d978c5dSVolker Rümelin static void clip_swap_float_from_mono(void *dst, const struct st_sample *src,
360*5d978c5dSVolker Rümelin int samples)
361*5d978c5dSVolker Rümelin {
362*5d978c5dSVolker Rümelin uint32_t *out_f32s = dst;
363*5d978c5dSVolker Rümelin
364*5d978c5dSVolker Rümelin while (samples--) {
365*5d978c5dSVolker Rümelin *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->l + src->r));
366*5d978c5dSVolker Rümelin src++;
367*5d978c5dSVolker Rümelin }
368*5d978c5dSVolker Rümelin }
369*5d978c5dSVolker Rümelin
clip_natural_float_from_stereo(void * dst,const struct st_sample * src,int samples)370ed2a4a79SKővágó, Zoltán static void clip_natural_float_from_stereo(
371ed2a4a79SKővágó, Zoltán void *dst, const struct st_sample *src, int samples)
372ed2a4a79SKővágó, Zoltán {
3739ddb7c85SVolker Rümelin float *out = dst;
374ed2a4a79SKővágó, Zoltán
375ed2a4a79SKővágó, Zoltán while (samples--) {
376dd381319SVolker Rümelin *out++ = CLIP_NATURAL_FLOAT(src->l);
377dd381319SVolker Rümelin *out++ = CLIP_NATURAL_FLOAT(src->r);
378ed2a4a79SKővágó, Zoltán src++;
379ed2a4a79SKővágó, Zoltán }
380ed2a4a79SKővágó, Zoltán }
381ed2a4a79SKővágó, Zoltán
clip_swap_float_from_stereo(void * dst,const struct st_sample * src,int samples)382*5d978c5dSVolker Rümelin static void clip_swap_float_from_stereo(
383*5d978c5dSVolker Rümelin void *dst, const struct st_sample *src, int samples)
384*5d978c5dSVolker Rümelin {
385*5d978c5dSVolker Rümelin uint32_t *out_f32s = dst;
386*5d978c5dSVolker Rümelin
387*5d978c5dSVolker Rümelin while (samples--) {
388*5d978c5dSVolker Rümelin *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->l));
389*5d978c5dSVolker Rümelin *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->r));
390*5d978c5dSVolker Rümelin src++;
391*5d978c5dSVolker Rümelin }
392*5d978c5dSVolker Rümelin }
393*5d978c5dSVolker Rümelin
394*5d978c5dSVolker Rümelin f_sample *mixeng_clip_float[2][2] = {
395*5d978c5dSVolker Rümelin {
396ed2a4a79SKővágó, Zoltán clip_natural_float_from_mono,
397*5d978c5dSVolker Rümelin clip_swap_float_from_mono,
398*5d978c5dSVolker Rümelin },
399*5d978c5dSVolker Rümelin {
400ed2a4a79SKővágó, Zoltán clip_natural_float_from_stereo,
401*5d978c5dSVolker Rümelin clip_swap_float_from_stereo,
402*5d978c5dSVolker Rümelin }
403ed2a4a79SKővágó, Zoltán };
404ed2a4a79SKővágó, Zoltán
audio_sample_to_uint64(const void * samples,int pos,uint64_t * left,uint64_t * right)405e709d2acSPhilippe Mathieu-Daudé void audio_sample_to_uint64(const void *samples, int pos,
4063d4d16f4SPavel Dovgalyuk uint64_t *left, uint64_t *right)
4073d4d16f4SPavel Dovgalyuk {
4083d4d16f4SPavel Dovgalyuk #ifdef FLOAT_MIXENG
4093d4d16f4SPavel Dovgalyuk error_report(
4103d4d16f4SPavel Dovgalyuk "Coreaudio and floating point samples are not supported by replay yet");
4113d4d16f4SPavel Dovgalyuk abort();
4123d4d16f4SPavel Dovgalyuk #else
413832061a2SAkihiko Odaki const struct st_sample *sample = samples;
414832061a2SAkihiko Odaki sample += pos;
4153d4d16f4SPavel Dovgalyuk *left = sample->l;
4163d4d16f4SPavel Dovgalyuk *right = sample->r;
4173d4d16f4SPavel Dovgalyuk #endif
4183d4d16f4SPavel Dovgalyuk }
4193d4d16f4SPavel Dovgalyuk
audio_sample_from_uint64(void * samples,int pos,uint64_t left,uint64_t right)4203d4d16f4SPavel Dovgalyuk void audio_sample_from_uint64(void *samples, int pos,
4213d4d16f4SPavel Dovgalyuk uint64_t left, uint64_t right)
4223d4d16f4SPavel Dovgalyuk {
4233d4d16f4SPavel Dovgalyuk #ifdef FLOAT_MIXENG
4243d4d16f4SPavel Dovgalyuk error_report(
4253d4d16f4SPavel Dovgalyuk "Coreaudio and floating point samples are not supported by replay yet");
4263d4d16f4SPavel Dovgalyuk abort();
4273d4d16f4SPavel Dovgalyuk #else
428832061a2SAkihiko Odaki struct st_sample *sample = samples;
429832061a2SAkihiko Odaki sample += pos;
4303d4d16f4SPavel Dovgalyuk sample->l = left;
4313d4d16f4SPavel Dovgalyuk sample->r = right;
4323d4d16f4SPavel Dovgalyuk #endif
4333d4d16f4SPavel Dovgalyuk }
4343d4d16f4SPavel Dovgalyuk
43585571bc7Sbellard /*
43685571bc7Sbellard * August 21, 1998
43785571bc7Sbellard * Copyright 1998 Fabrice Bellard.
43885571bc7Sbellard *
439cb8d4c8fSStefan Weil * [Rewrote completely the code of Lance Norskog And Sundry
44085571bc7Sbellard * Contributors with a more efficient algorithm.]
44185571bc7Sbellard *
44285571bc7Sbellard * This source code is freely redistributable and may be used for
44385571bc7Sbellard * any purpose. This copyright notice must be maintained.
44485571bc7Sbellard * Lance Norskog And Sundry Contributors are not responsible for
44585571bc7Sbellard * the consequences of using this software.
44685571bc7Sbellard */
44785571bc7Sbellard
44885571bc7Sbellard /*
44985571bc7Sbellard * Sound Tools rate change effect file.
45085571bc7Sbellard */
45185571bc7Sbellard /*
45285571bc7Sbellard * Linear Interpolation.
45385571bc7Sbellard *
45485571bc7Sbellard * The use of fractional increment allows us to use no buffer. It
45585571bc7Sbellard * avoid the problems at the end of the buffer we had with the old
45685571bc7Sbellard * method which stored a possibly big buffer of size
45785571bc7Sbellard * lcm(in_rate,out_rate).
45885571bc7Sbellard *
45985571bc7Sbellard * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If
46085571bc7Sbellard * the input & output frequencies are equal, a delay of one sample is
46185571bc7Sbellard * introduced. Limited to processing 32-bit count worth of samples.
46285571bc7Sbellard *
46385571bc7Sbellard * 1 << FRAC_BITS evaluating to zero in several places. Changed with
46485571bc7Sbellard * an (unsigned long) cast to make it safe. MarkMLl 2/1/99
46585571bc7Sbellard */
46685571bc7Sbellard
46785571bc7Sbellard /* Private data */
468c0fe3827Sbellard struct rate {
46985571bc7Sbellard uint64_t opos;
47085571bc7Sbellard uint64_t opos_inc;
47185571bc7Sbellard uint32_t ipos; /* position in the input stream (integer) */
4721ea879e5Smalc struct st_sample ilast; /* last sample in the input stream */
473c0fe3827Sbellard };
47485571bc7Sbellard
47585571bc7Sbellard /*
47685571bc7Sbellard * Prepare processing.
47785571bc7Sbellard */
st_rate_start(int inrate,int outrate)47885571bc7Sbellard void *st_rate_start (int inrate, int outrate)
47985571bc7Sbellard {
48025bf0c2dSVolker Rümelin struct rate *rate = g_new0(struct rate, 1);
48185571bc7Sbellard
48285571bc7Sbellard rate->opos = 0;
48385571bc7Sbellard
48485571bc7Sbellard /* increment */
4851d14ffa9Sbellard rate->opos_inc = ((uint64_t) inrate << 32) / outrate;
48685571bc7Sbellard
48785571bc7Sbellard rate->ipos = 0;
48885571bc7Sbellard rate->ilast.l = 0;
48985571bc7Sbellard rate->ilast.r = 0;
49085571bc7Sbellard return rate;
49185571bc7Sbellard }
49285571bc7Sbellard
4931d14ffa9Sbellard #define NAME st_rate_flow_mix
4941d14ffa9Sbellard #define OP(a, b) a += b
4951d14ffa9Sbellard #include "rate_template.h"
49685571bc7Sbellard
4971d14ffa9Sbellard #define NAME st_rate_flow
4981d14ffa9Sbellard #define OP(a, b) a = b
4991d14ffa9Sbellard #include "rate_template.h"
50085571bc7Sbellard
st_rate_stop(void * opaque)50185571bc7Sbellard void st_rate_stop (void *opaque)
50285571bc7Sbellard {
5037267c094SAnthony Liguori g_free (opaque);
50485571bc7Sbellard }
5051d14ffa9Sbellard
5061a01df3dSVolker Rümelin /**
507a9ea5678SVolker Rümelin * st_rate_frames_out() - returns the number of frames the resampling code
508a9ea5678SVolker Rümelin * generates from frames_in frames
509a9ea5678SVolker Rümelin *
510a9ea5678SVolker Rümelin * @opaque: pointer to struct rate
511a9ea5678SVolker Rümelin * @frames_in: number of frames
512a9ea5678SVolker Rümelin *
513a9ea5678SVolker Rümelin * When upsampling, there may be more than one correct result. In this case,
514a9ea5678SVolker Rümelin * the function returns the maximum number of output frames the resampling
515a9ea5678SVolker Rümelin * code can generate.
516a9ea5678SVolker Rümelin */
st_rate_frames_out(void * opaque,uint32_t frames_in)517a9ea5678SVolker Rümelin uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in)
518a9ea5678SVolker Rümelin {
519a9ea5678SVolker Rümelin struct rate *rate = opaque;
520a9ea5678SVolker Rümelin uint64_t opos_end, opos_delta;
521a9ea5678SVolker Rümelin uint32_t ipos_end;
522a9ea5678SVolker Rümelin uint32_t frames_out;
523a9ea5678SVolker Rümelin
524a9ea5678SVolker Rümelin if (rate->opos_inc == 1ULL << 32) {
525a9ea5678SVolker Rümelin return frames_in;
526a9ea5678SVolker Rümelin }
527a9ea5678SVolker Rümelin
528a9ea5678SVolker Rümelin /* no output frame without at least one input frame */
529a9ea5678SVolker Rümelin if (!frames_in) {
530a9ea5678SVolker Rümelin return 0;
531a9ea5678SVolker Rümelin }
532a9ea5678SVolker Rümelin
533a9ea5678SVolker Rümelin /* last frame read was at rate->ipos - 1 */
534a9ea5678SVolker Rümelin ipos_end = rate->ipos - 1 + frames_in;
535a9ea5678SVolker Rümelin opos_end = (uint64_t)ipos_end << 32;
536a9ea5678SVolker Rümelin
537a9ea5678SVolker Rümelin /* last frame written was at rate->opos - rate->opos_inc */
538a9ea5678SVolker Rümelin if (opos_end + rate->opos_inc <= rate->opos) {
539a9ea5678SVolker Rümelin return 0;
540a9ea5678SVolker Rümelin }
541a9ea5678SVolker Rümelin opos_delta = opos_end - rate->opos + rate->opos_inc;
542a9ea5678SVolker Rümelin frames_out = opos_delta / rate->opos_inc;
543a9ea5678SVolker Rümelin
544a9ea5678SVolker Rümelin return opos_delta % rate->opos_inc ? frames_out : frames_out - 1;
545a9ea5678SVolker Rümelin }
546a9ea5678SVolker Rümelin
547a9ea5678SVolker Rümelin /**
5481a01df3dSVolker Rümelin * st_rate_frames_in() - returns the number of frames needed to
5491a01df3dSVolker Rümelin * get frames_out frames after resampling
5501a01df3dSVolker Rümelin *
5511a01df3dSVolker Rümelin * @opaque: pointer to struct rate
5521a01df3dSVolker Rümelin * @frames_out: number of frames
5531a01df3dSVolker Rümelin *
5541a01df3dSVolker Rümelin * When downsampling, there may be more than one correct result. In this
5551a01df3dSVolker Rümelin * case, the function returns the maximum number of input frames needed.
5561a01df3dSVolker Rümelin */
st_rate_frames_in(void * opaque,uint32_t frames_out)5571a01df3dSVolker Rümelin uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out)
5581a01df3dSVolker Rümelin {
5591a01df3dSVolker Rümelin struct rate *rate = opaque;
5601a01df3dSVolker Rümelin uint64_t opos_start, opos_end;
5611a01df3dSVolker Rümelin uint32_t ipos_start, ipos_end;
5621a01df3dSVolker Rümelin
5631a01df3dSVolker Rümelin if (rate->opos_inc == 1ULL << 32) {
5641a01df3dSVolker Rümelin return frames_out;
5651a01df3dSVolker Rümelin }
5661a01df3dSVolker Rümelin
5671a01df3dSVolker Rümelin if (frames_out) {
5681a01df3dSVolker Rümelin opos_start = rate->opos;
5691a01df3dSVolker Rümelin ipos_start = rate->ipos;
5701a01df3dSVolker Rümelin } else {
5711a01df3dSVolker Rümelin uint64_t offset;
5721a01df3dSVolker Rümelin
5731a01df3dSVolker Rümelin /* add offset = ceil(opos_inc) to opos and ipos to avoid an underflow */
5741a01df3dSVolker Rümelin offset = (rate->opos_inc + (1ULL << 32) - 1) & ~((1ULL << 32) - 1);
5751a01df3dSVolker Rümelin opos_start = rate->opos + offset;
5761a01df3dSVolker Rümelin ipos_start = rate->ipos + (offset >> 32);
5771a01df3dSVolker Rümelin }
5781a01df3dSVolker Rümelin /* last frame written was at opos_start - rate->opos_inc */
5791a01df3dSVolker Rümelin opos_end = opos_start - rate->opos_inc + rate->opos_inc * frames_out;
5801a01df3dSVolker Rümelin ipos_end = (opos_end >> 32) + 1;
5811a01df3dSVolker Rümelin
5821a01df3dSVolker Rümelin /* last frame read was at ipos_start - 1 */
5831a01df3dSVolker Rümelin return ipos_end + 1 > ipos_start ? ipos_end + 1 - ipos_start : 0;
5841a01df3dSVolker Rümelin }
5851a01df3dSVolker Rümelin
mixeng_clear(struct st_sample * buf,int len)5861ea879e5Smalc void mixeng_clear (struct st_sample *buf, int len)
5871d14ffa9Sbellard {
5881ea879e5Smalc memset (buf, 0, len * sizeof (struct st_sample));
5891d14ffa9Sbellard }
59000e07679SMichael Walle
mixeng_volume(struct st_sample * buf,int len,struct mixeng_volume * vol)59100e07679SMichael Walle void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol)
59200e07679SMichael Walle {
59300e07679SMichael Walle if (vol->mute) {
59400e07679SMichael Walle mixeng_clear (buf, len);
59500e07679SMichael Walle return;
59600e07679SMichael Walle }
59700e07679SMichael Walle
59800e07679SMichael Walle while (len--) {
59900e07679SMichael Walle #ifdef FLOAT_MIXENG
60000e07679SMichael Walle buf->l = buf->l * vol->l;
60100e07679SMichael Walle buf->r = buf->r * vol->r;
60200e07679SMichael Walle #else
60300e07679SMichael Walle buf->l = (buf->l * vol->l) >> 32;
60400e07679SMichael Walle buf->r = (buf->r * vol->r) >> 32;
60500e07679SMichael Walle #endif
60600e07679SMichael Walle buf += 1;
60700e07679SMichael Walle }
60800e07679SMichael Walle }
609