xref: /qemu/audio/mixeng.c (revision 470bcabd8f56b950c8b9c7a0531d62d3b85978c0)
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"
2687ecb68bSpbrook #include "qemu-common.h"
2758369e22SPaolo Bonzini #include "qemu/bswap.h"
283d4d16f4SPavel Dovgalyuk #include "qemu/error-report.h"
2987ecb68bSpbrook #include "audio.h"
3085571bc7Sbellard 
311d14ffa9Sbellard #define AUDIO_CAP "mixeng"
321d14ffa9Sbellard #include "audio_int.h"
331d14ffa9Sbellard 
341d14ffa9Sbellard /* 8 bit */
351d14ffa9Sbellard #define ENDIAN_CONVERSION natural
361d14ffa9Sbellard #define ENDIAN_CONVERT(v) (v)
371d14ffa9Sbellard 
381d14ffa9Sbellard /* Signed 8 bit */
39a2885387SRoger Pau Monne #define BSIZE 8
40a2885387SRoger Pau Monne #define ITYPE int
411d14ffa9Sbellard #define IN_MIN SCHAR_MIN
421d14ffa9Sbellard #define IN_MAX SCHAR_MAX
4385571bc7Sbellard #define SIGNED
441d14ffa9Sbellard #define SHIFT 8
4585571bc7Sbellard #include "mixeng_template.h"
4685571bc7Sbellard #undef SIGNED
4785571bc7Sbellard #undef IN_MAX
4885571bc7Sbellard #undef IN_MIN
49a2885387SRoger Pau Monne #undef BSIZE
50a2885387SRoger Pau Monne #undef ITYPE
511d14ffa9Sbellard #undef SHIFT
5285571bc7Sbellard 
531d14ffa9Sbellard /* Unsigned 8 bit */
54a2885387SRoger Pau Monne #define BSIZE 8
55a2885387SRoger Pau Monne #define ITYPE uint
5685571bc7Sbellard #define IN_MIN 0
5785571bc7Sbellard #define IN_MAX UCHAR_MAX
581d14ffa9Sbellard #define SHIFT 8
5985571bc7Sbellard #include "mixeng_template.h"
6085571bc7Sbellard #undef IN_MAX
6185571bc7Sbellard #undef IN_MIN
62a2885387SRoger Pau Monne #undef BSIZE
63a2885387SRoger Pau Monne #undef ITYPE
641d14ffa9Sbellard #undef SHIFT
6585571bc7Sbellard 
661d14ffa9Sbellard #undef ENDIAN_CONVERT
671d14ffa9Sbellard #undef ENDIAN_CONVERSION
681d14ffa9Sbellard 
691d14ffa9Sbellard /* Signed 16 bit */
70a2885387SRoger Pau Monne #define BSIZE 16
71a2885387SRoger Pau Monne #define ITYPE int
7285571bc7Sbellard #define IN_MIN SHRT_MIN
7385571bc7Sbellard #define IN_MAX SHRT_MAX
7485571bc7Sbellard #define SIGNED
751d14ffa9Sbellard #define SHIFT 16
761d14ffa9Sbellard #define ENDIAN_CONVERSION natural
771d14ffa9Sbellard #define ENDIAN_CONVERT(v) (v)
7885571bc7Sbellard #include "mixeng_template.h"
791d14ffa9Sbellard #undef ENDIAN_CONVERT
801d14ffa9Sbellard #undef ENDIAN_CONVERSION
811d14ffa9Sbellard #define ENDIAN_CONVERSION swap
821d14ffa9Sbellard #define ENDIAN_CONVERT(v) bswap16 (v)
831d14ffa9Sbellard #include "mixeng_template.h"
841d14ffa9Sbellard #undef ENDIAN_CONVERT
851d14ffa9Sbellard #undef ENDIAN_CONVERSION
8685571bc7Sbellard #undef SIGNED
8785571bc7Sbellard #undef IN_MAX
8885571bc7Sbellard #undef IN_MIN
89a2885387SRoger Pau Monne #undef BSIZE
90a2885387SRoger Pau Monne #undef ITYPE
911d14ffa9Sbellard #undef SHIFT
9285571bc7Sbellard 
93f941aa25Sths /* Unsigned 16 bit */
94a2885387SRoger Pau Monne #define BSIZE 16
95a2885387SRoger Pau Monne #define ITYPE uint
9685571bc7Sbellard #define IN_MIN 0
9785571bc7Sbellard #define IN_MAX USHRT_MAX
981d14ffa9Sbellard #define SHIFT 16
991d14ffa9Sbellard #define ENDIAN_CONVERSION natural
1001d14ffa9Sbellard #define ENDIAN_CONVERT(v) (v)
10185571bc7Sbellard #include "mixeng_template.h"
1021d14ffa9Sbellard #undef ENDIAN_CONVERT
1031d14ffa9Sbellard #undef ENDIAN_CONVERSION
1041d14ffa9Sbellard #define ENDIAN_CONVERSION swap
1051d14ffa9Sbellard #define ENDIAN_CONVERT(v) bswap16 (v)
1061d14ffa9Sbellard #include "mixeng_template.h"
1071d14ffa9Sbellard #undef ENDIAN_CONVERT
1081d14ffa9Sbellard #undef ENDIAN_CONVERSION
10985571bc7Sbellard #undef IN_MAX
11085571bc7Sbellard #undef IN_MIN
111a2885387SRoger Pau Monne #undef BSIZE
112a2885387SRoger Pau Monne #undef ITYPE
1131d14ffa9Sbellard #undef SHIFT
11485571bc7Sbellard 
115f941aa25Sths /* Signed 32 bit */
116a2885387SRoger Pau Monne #define BSIZE 32
117a2885387SRoger Pau Monne #define ITYPE int
118f941aa25Sths #define IN_MIN INT32_MIN
119f941aa25Sths #define IN_MAX INT32_MAX
120f941aa25Sths #define SIGNED
121f941aa25Sths #define SHIFT 32
122f941aa25Sths #define ENDIAN_CONVERSION natural
123f941aa25Sths #define ENDIAN_CONVERT(v) (v)
124f941aa25Sths #include "mixeng_template.h"
125f941aa25Sths #undef ENDIAN_CONVERT
126f941aa25Sths #undef ENDIAN_CONVERSION
127f941aa25Sths #define ENDIAN_CONVERSION swap
128f941aa25Sths #define ENDIAN_CONVERT(v) bswap32 (v)
129f941aa25Sths #include "mixeng_template.h"
130f941aa25Sths #undef ENDIAN_CONVERT
131f941aa25Sths #undef ENDIAN_CONVERSION
132f941aa25Sths #undef SIGNED
133f941aa25Sths #undef IN_MAX
134f941aa25Sths #undef IN_MIN
135a2885387SRoger Pau Monne #undef BSIZE
136a2885387SRoger Pau Monne #undef ITYPE
137f941aa25Sths #undef SHIFT
138f941aa25Sths 
139ad483a51Smalc /* Unsigned 32 bit */
140a2885387SRoger Pau Monne #define BSIZE 32
141a2885387SRoger Pau Monne #define ITYPE uint
142f941aa25Sths #define IN_MIN 0
143f941aa25Sths #define IN_MAX UINT32_MAX
144f941aa25Sths #define SHIFT 32
145f941aa25Sths #define ENDIAN_CONVERSION natural
146f941aa25Sths #define ENDIAN_CONVERT(v) (v)
147f941aa25Sths #include "mixeng_template.h"
148f941aa25Sths #undef ENDIAN_CONVERT
149f941aa25Sths #undef ENDIAN_CONVERSION
150f941aa25Sths #define ENDIAN_CONVERSION swap
151f941aa25Sths #define ENDIAN_CONVERT(v) bswap32 (v)
152f941aa25Sths #include "mixeng_template.h"
153f941aa25Sths #undef ENDIAN_CONVERT
154f941aa25Sths #undef ENDIAN_CONVERSION
155f941aa25Sths #undef IN_MAX
156f941aa25Sths #undef IN_MIN
157a2885387SRoger Pau Monne #undef BSIZE
158a2885387SRoger Pau Monne #undef ITYPE
159f941aa25Sths #undef SHIFT
160f941aa25Sths 
161f941aa25Sths t_sample *mixeng_conv[2][2][2][3] = {
16285571bc7Sbellard     {
16385571bc7Sbellard         {
1641d14ffa9Sbellard             {
1651d14ffa9Sbellard                 conv_natural_uint8_t_to_mono,
166f941aa25Sths                 conv_natural_uint16_t_to_mono,
167f941aa25Sths                 conv_natural_uint32_t_to_mono
16885571bc7Sbellard             },
16985571bc7Sbellard             {
1701d14ffa9Sbellard                 conv_natural_uint8_t_to_mono,
171f941aa25Sths                 conv_swap_uint16_t_to_mono,
172f941aa25Sths                 conv_swap_uint32_t_to_mono,
17385571bc7Sbellard             }
17485571bc7Sbellard         },
17585571bc7Sbellard         {
17685571bc7Sbellard             {
1771d14ffa9Sbellard                 conv_natural_int8_t_to_mono,
178f941aa25Sths                 conv_natural_int16_t_to_mono,
179f941aa25Sths                 conv_natural_int32_t_to_mono
18085571bc7Sbellard             },
18185571bc7Sbellard             {
1821d14ffa9Sbellard                 conv_natural_int8_t_to_mono,
183f941aa25Sths                 conv_swap_int16_t_to_mono,
184f941aa25Sths                 conv_swap_int32_t_to_mono
1851d14ffa9Sbellard             }
1861d14ffa9Sbellard         }
1871d14ffa9Sbellard     },
1881d14ffa9Sbellard     {
1891d14ffa9Sbellard         {
1901d14ffa9Sbellard             {
1911d14ffa9Sbellard                 conv_natural_uint8_t_to_stereo,
192f941aa25Sths                 conv_natural_uint16_t_to_stereo,
193f941aa25Sths                 conv_natural_uint32_t_to_stereo
1941d14ffa9Sbellard             },
1951d14ffa9Sbellard             {
1961d14ffa9Sbellard                 conv_natural_uint8_t_to_stereo,
197f941aa25Sths                 conv_swap_uint16_t_to_stereo,
198f941aa25Sths                 conv_swap_uint32_t_to_stereo
1991d14ffa9Sbellard             }
2001d14ffa9Sbellard         },
2011d14ffa9Sbellard         {
2021d14ffa9Sbellard             {
2031d14ffa9Sbellard                 conv_natural_int8_t_to_stereo,
204f941aa25Sths                 conv_natural_int16_t_to_stereo,
205f941aa25Sths                 conv_natural_int32_t_to_stereo
2061d14ffa9Sbellard             },
2071d14ffa9Sbellard             {
2081d14ffa9Sbellard                 conv_natural_int8_t_to_stereo,
209f941aa25Sths                 conv_swap_int16_t_to_stereo,
210f941aa25Sths                 conv_swap_int32_t_to_stereo,
2111d14ffa9Sbellard             }
21285571bc7Sbellard         }
21385571bc7Sbellard     }
21485571bc7Sbellard };
21585571bc7Sbellard 
216f941aa25Sths f_sample *mixeng_clip[2][2][2][3] = {
21785571bc7Sbellard     {
21885571bc7Sbellard         {
2191d14ffa9Sbellard             {
2201d14ffa9Sbellard                 clip_natural_uint8_t_from_mono,
221f941aa25Sths                 clip_natural_uint16_t_from_mono,
222f941aa25Sths                 clip_natural_uint32_t_from_mono
22385571bc7Sbellard             },
22485571bc7Sbellard             {
2251d14ffa9Sbellard                 clip_natural_uint8_t_from_mono,
226f941aa25Sths                 clip_swap_uint16_t_from_mono,
227f941aa25Sths                 clip_swap_uint32_t_from_mono
22885571bc7Sbellard             }
22985571bc7Sbellard         },
23085571bc7Sbellard         {
23185571bc7Sbellard             {
2321d14ffa9Sbellard                 clip_natural_int8_t_from_mono,
233f941aa25Sths                 clip_natural_int16_t_from_mono,
234f941aa25Sths                 clip_natural_int32_t_from_mono
23585571bc7Sbellard             },
23685571bc7Sbellard             {
2371d14ffa9Sbellard                 clip_natural_int8_t_from_mono,
238f941aa25Sths                 clip_swap_int16_t_from_mono,
239f941aa25Sths                 clip_swap_int32_t_from_mono
2401d14ffa9Sbellard             }
2411d14ffa9Sbellard         }
2421d14ffa9Sbellard     },
2431d14ffa9Sbellard     {
2441d14ffa9Sbellard         {
2451d14ffa9Sbellard             {
2461d14ffa9Sbellard                 clip_natural_uint8_t_from_stereo,
247f941aa25Sths                 clip_natural_uint16_t_from_stereo,
248f941aa25Sths                 clip_natural_uint32_t_from_stereo
2491d14ffa9Sbellard             },
2501d14ffa9Sbellard             {
2511d14ffa9Sbellard                 clip_natural_uint8_t_from_stereo,
252f941aa25Sths                 clip_swap_uint16_t_from_stereo,
253f941aa25Sths                 clip_swap_uint32_t_from_stereo
2541d14ffa9Sbellard             }
2551d14ffa9Sbellard         },
2561d14ffa9Sbellard         {
2571d14ffa9Sbellard             {
2581d14ffa9Sbellard                 clip_natural_int8_t_from_stereo,
259f941aa25Sths                 clip_natural_int16_t_from_stereo,
260f941aa25Sths                 clip_natural_int32_t_from_stereo
2611d14ffa9Sbellard             },
2621d14ffa9Sbellard             {
2631d14ffa9Sbellard                 clip_natural_int8_t_from_stereo,
264f941aa25Sths                 clip_swap_int16_t_from_stereo,
265f941aa25Sths                 clip_swap_int32_t_from_stereo
2661d14ffa9Sbellard             }
26785571bc7Sbellard         }
26885571bc7Sbellard     }
26985571bc7Sbellard };
27085571bc7Sbellard 
2713d4d16f4SPavel Dovgalyuk 
2723d4d16f4SPavel Dovgalyuk void audio_sample_to_uint64(void *samples, int pos,
2733d4d16f4SPavel Dovgalyuk                             uint64_t *left, uint64_t *right)
2743d4d16f4SPavel Dovgalyuk {
2753d4d16f4SPavel Dovgalyuk     struct st_sample *sample = samples;
2763d4d16f4SPavel Dovgalyuk     sample += pos;
2773d4d16f4SPavel Dovgalyuk #ifdef FLOAT_MIXENG
2783d4d16f4SPavel Dovgalyuk     error_report(
2793d4d16f4SPavel Dovgalyuk         "Coreaudio and floating point samples are not supported by replay yet");
2803d4d16f4SPavel Dovgalyuk     abort();
2813d4d16f4SPavel Dovgalyuk #else
2823d4d16f4SPavel Dovgalyuk     *left = sample->l;
2833d4d16f4SPavel Dovgalyuk     *right = sample->r;
2843d4d16f4SPavel Dovgalyuk #endif
2853d4d16f4SPavel Dovgalyuk }
2863d4d16f4SPavel Dovgalyuk 
2873d4d16f4SPavel Dovgalyuk void audio_sample_from_uint64(void *samples, int pos,
2883d4d16f4SPavel Dovgalyuk                             uint64_t left, uint64_t right)
2893d4d16f4SPavel Dovgalyuk {
2903d4d16f4SPavel Dovgalyuk     struct st_sample *sample = samples;
2913d4d16f4SPavel Dovgalyuk     sample += pos;
2923d4d16f4SPavel Dovgalyuk #ifdef FLOAT_MIXENG
2933d4d16f4SPavel Dovgalyuk     error_report(
2943d4d16f4SPavel Dovgalyuk         "Coreaudio and floating point samples are not supported by replay yet");
2953d4d16f4SPavel Dovgalyuk     abort();
2963d4d16f4SPavel Dovgalyuk #else
2973d4d16f4SPavel Dovgalyuk     sample->l = left;
2983d4d16f4SPavel Dovgalyuk     sample->r = right;
2993d4d16f4SPavel Dovgalyuk #endif
3003d4d16f4SPavel Dovgalyuk }
3013d4d16f4SPavel Dovgalyuk 
30285571bc7Sbellard /*
30385571bc7Sbellard  * August 21, 1998
30485571bc7Sbellard  * Copyright 1998 Fabrice Bellard.
30585571bc7Sbellard  *
306cb8d4c8fSStefan Weil  * [Rewrote completely the code of Lance Norskog And Sundry
30785571bc7Sbellard  * Contributors with a more efficient algorithm.]
30885571bc7Sbellard  *
30985571bc7Sbellard  * This source code is freely redistributable and may be used for
31085571bc7Sbellard  * any purpose.  This copyright notice must be maintained.
31185571bc7Sbellard  * Lance Norskog And Sundry Contributors are not responsible for
31285571bc7Sbellard  * the consequences of using this software.
31385571bc7Sbellard  */
31485571bc7Sbellard 
31585571bc7Sbellard /*
31685571bc7Sbellard  * Sound Tools rate change effect file.
31785571bc7Sbellard  */
31885571bc7Sbellard /*
31985571bc7Sbellard  * Linear Interpolation.
32085571bc7Sbellard  *
32185571bc7Sbellard  * The use of fractional increment allows us to use no buffer. It
32285571bc7Sbellard  * avoid the problems at the end of the buffer we had with the old
32385571bc7Sbellard  * method which stored a possibly big buffer of size
32485571bc7Sbellard  * lcm(in_rate,out_rate).
32585571bc7Sbellard  *
32685571bc7Sbellard  * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If
32785571bc7Sbellard  * the input & output frequencies are equal, a delay of one sample is
32885571bc7Sbellard  * introduced.  Limited to processing 32-bit count worth of samples.
32985571bc7Sbellard  *
33085571bc7Sbellard  * 1 << FRAC_BITS evaluating to zero in several places.  Changed with
33185571bc7Sbellard  * an (unsigned long) cast to make it safe.  MarkMLl 2/1/99
33285571bc7Sbellard  */
33385571bc7Sbellard 
33485571bc7Sbellard /* Private data */
335c0fe3827Sbellard struct rate {
33685571bc7Sbellard     uint64_t opos;
33785571bc7Sbellard     uint64_t opos_inc;
33885571bc7Sbellard     uint32_t ipos;              /* position in the input stream (integer) */
3391ea879e5Smalc     struct st_sample ilast;          /* last sample in the input stream */
340c0fe3827Sbellard };
34185571bc7Sbellard 
34285571bc7Sbellard /*
34385571bc7Sbellard  * Prepare processing.
34485571bc7Sbellard  */
34585571bc7Sbellard void *st_rate_start (int inrate, int outrate)
34685571bc7Sbellard {
347*470bcabdSAlistair Francis     struct rate *rate = audio_calloc(__func__, 1, sizeof(*rate));
34885571bc7Sbellard 
34985571bc7Sbellard     if (!rate) {
350e7cad338Sbellard         dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
3511d14ffa9Sbellard         return NULL;
35285571bc7Sbellard     }
35385571bc7Sbellard 
35485571bc7Sbellard     rate->opos = 0;
35585571bc7Sbellard 
35685571bc7Sbellard     /* increment */
3571d14ffa9Sbellard     rate->opos_inc = ((uint64_t) inrate << 32) / outrate;
35885571bc7Sbellard 
35985571bc7Sbellard     rate->ipos = 0;
36085571bc7Sbellard     rate->ilast.l = 0;
36185571bc7Sbellard     rate->ilast.r = 0;
36285571bc7Sbellard     return rate;
36385571bc7Sbellard }
36485571bc7Sbellard 
3651d14ffa9Sbellard #define NAME st_rate_flow_mix
3661d14ffa9Sbellard #define OP(a, b) a += b
3671d14ffa9Sbellard #include "rate_template.h"
36885571bc7Sbellard 
3691d14ffa9Sbellard #define NAME st_rate_flow
3701d14ffa9Sbellard #define OP(a, b) a = b
3711d14ffa9Sbellard #include "rate_template.h"
37285571bc7Sbellard 
37385571bc7Sbellard void st_rate_stop (void *opaque)
37485571bc7Sbellard {
3757267c094SAnthony Liguori     g_free (opaque);
37685571bc7Sbellard }
3771d14ffa9Sbellard 
3781ea879e5Smalc void mixeng_clear (struct st_sample *buf, int len)
3791d14ffa9Sbellard {
3801ea879e5Smalc     memset (buf, 0, len * sizeof (struct st_sample));
3811d14ffa9Sbellard }
38200e07679SMichael Walle 
38300e07679SMichael Walle void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol)
38400e07679SMichael Walle {
38500e07679SMichael Walle     if (vol->mute) {
38600e07679SMichael Walle         mixeng_clear (buf, len);
38700e07679SMichael Walle         return;
38800e07679SMichael Walle     }
38900e07679SMichael Walle 
39000e07679SMichael Walle     while (len--) {
39100e07679SMichael Walle #ifdef FLOAT_MIXENG
39200e07679SMichael Walle         buf->l = buf->l * vol->l;
39300e07679SMichael Walle         buf->r = buf->r * vol->r;
39400e07679SMichael Walle #else
39500e07679SMichael Walle         buf->l = (buf->l * vol->l) >> 32;
39600e07679SMichael Walle         buf->r = (buf->r * vol->r) >> 32;
39700e07679SMichael Walle #endif
39800e07679SMichael Walle         buf += 1;
39900e07679SMichael Walle     }
40000e07679SMichael Walle }
401