audio: float fixes

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCgAGBQJeb2M4AAoJEEy22O7T6HE42NgP/21LTlqMMB4LUzstard87IQV
 ch8KVEcnEYaJVZcnzQrhY6SL7bu5JqVk5xcV9GOzbxT8l5Q6pUFJnrqvmHu9Q5B5
 itQj48EBSdNb1iwFYhuOCBHc9I1n4fa2VwTcERprcx9uXArmflS4tsgnrUR+05zd
 96hGzo+/Q4KVlX/pj9k5kSUwvZyQZRjX6ruvpGnLJMAq4yf9XFVt9ifsVFLyYO6i
 LQ1xaFH0mpPmlbnDMlMRx6nDQeUQfMABp4FU6hqDSGCjbCSI28RrhiACo1A9RFqJ
 O9F+i1XRFmCEEtpJ4OuoRWo3Nlx3txZtHkj+bK7z6c0kpseUWYGL4z2he0wKPMwD
 Qw0iFuOUNS6Yv7iQBvTtG5vJjwqJpOjdPvwjxq8gggoCvRK+bFfBUoh/luJX9rAz
 3kr/BFO24so31+fhcRtte8FP23I3yevWWSbowOsaYVTfUwEGy4n5P4dGr4yiGdI5
 f35VjlSiV2kMlFgZOCH8M32Sf5G+UgzwjhgboxMlntopG04u7Ex2YItwH8tNady1
 S1OxSbTE5I8aUtYAfTtaynqySZZn6x8Kmq0LRBT1Xw/5uzaY7UpCa48Vjz9oFn47
 Yl49GbytwfXd9FtDrFexrDbBOkCtU6cJtRTjxmckK7TFsu0Vbzoy8sy6EJSZiCjY
 8G7n6g5qRBhrzeLuboIG
 =yV4v
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/audio-20200316-pull-request' into staging

audio: float fixes

# gpg: Signature made Mon 16 Mar 2020 11:30:00 GMT
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/audio-20200316-pull-request:
  audio: add audiodev format=f32 option documentation
  audio: fix saturation nonlinearity in clip_* functions
  audio: change mixing engine float range to [-1.f, 1.f]
  audio: consistency changes
  audio: change naming scheme of FLOAT_CONV macros
  qapi/audio: add documentation for AudioFormat

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-03-16 13:06:14 +00:00
commit 509f61798b
4 changed files with 39 additions and 27 deletions

View File

@ -268,17 +268,17 @@ f_sample *mixeng_clip[2][2][2][3] = {
}; };
#ifdef FLOAT_MIXENG #ifdef FLOAT_MIXENG
#define FLOAT_CONV_TO(x) (x) #define CONV_NATURAL_FLOAT(x) (x)
#define FLOAT_CONV_FROM(x) (x) #define CLIP_NATURAL_FLOAT(x) (x)
#else #else
static const float float_scale = UINT_MAX; static const float float_scale = UINT_MAX / 2.f;
#define FLOAT_CONV_TO(x) ((x) * float_scale) #define CONV_NATURAL_FLOAT(x) ((x) * float_scale)
#ifdef RECIPROCAL #ifdef RECIPROCAL
static const float float_scale_reciprocal = 1.f / UINT_MAX; static const float float_scale_reciprocal = 2.f / UINT_MAX;
#define FLOAT_CONV_FROM(x) ((x) * float_scale_reciprocal) #define CLIP_NATURAL_FLOAT(x) ((x) * float_scale_reciprocal)
#else #else
#define FLOAT_CONV_FROM(x) ((x) / float_scale) #define CLIP_NATURAL_FLOAT(x) ((x) / float_scale)
#endif #endif
#endif #endif
@ -288,7 +288,7 @@ static void conv_natural_float_to_mono(struct st_sample *dst, const void *src,
float *in = (float *)src; float *in = (float *)src;
while (samples--) { while (samples--) {
dst->r = dst->l = FLOAT_CONV_TO(*in++); dst->r = dst->l = CONV_NATURAL_FLOAT(*in++);
dst++; dst++;
} }
} }
@ -299,8 +299,8 @@ static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src,
float *in = (float *)src; float *in = (float *)src;
while (samples--) { while (samples--) {
dst->l = FLOAT_CONV_TO(*in++); dst->l = CONV_NATURAL_FLOAT(*in++);
dst->r = FLOAT_CONV_TO(*in++); dst->r = CONV_NATURAL_FLOAT(*in++);
dst++; dst++;
} }
} }
@ -316,7 +316,7 @@ static void clip_natural_float_from_mono(void *dst, const struct st_sample *src,
float *out = (float *)dst; float *out = (float *)dst;
while (samples--) { while (samples--) {
*out++ = FLOAT_CONV_FROM(src->l) + FLOAT_CONV_FROM(src->r); *out++ = CLIP_NATURAL_FLOAT(src->l + src->r);
src++; src++;
} }
} }
@ -327,8 +327,8 @@ static void clip_natural_float_from_stereo(
float *out = (float *)dst; float *out = (float *)dst;
while (samples--) { while (samples--) {
*out++ = FLOAT_CONV_FROM(src->l); *out++ = CLIP_NATURAL_FLOAT(src->l);
*out++ = FLOAT_CONV_FROM(src->r); *out++ = CLIP_NATURAL_FLOAT(src->r);
src++; src++;
} }
} }

View File

@ -41,32 +41,31 @@ static inline mixeng_real glue (conv_, ET) (IN_T v)
#ifdef RECIPROCAL #ifdef RECIPROCAL
#ifdef SIGNED #ifdef SIGNED
return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN)); return nv * (2.f / ((mixeng_real)IN_MAX - IN_MIN));
#else #else
return (nv - HALF) * (1.f / (mixeng_real) IN_MAX); return (nv - HALF) * (2.f / (mixeng_real)IN_MAX);
#endif #endif
#else /* !RECIPROCAL */ #else /* !RECIPROCAL */
#ifdef SIGNED #ifdef SIGNED
return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN); return nv / (((mixeng_real)IN_MAX - IN_MIN) / 2.f);
#else #else
return (nv - HALF) / (mixeng_real) IN_MAX; return (nv - HALF) / ((mixeng_real)IN_MAX / 2.f);
#endif #endif
#endif #endif
} }
static inline IN_T glue (clip_, ET) (mixeng_real v) static inline IN_T glue (clip_, ET) (mixeng_real v)
{ {
if (v >= 0.5) { if (v >= 1.f) {
return IN_MAX; return IN_MAX;
} } else if (v < -1.f) {
else if (v < -0.5) {
return IN_MIN; return IN_MIN;
} }
#ifdef SIGNED #ifdef SIGNED
return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real) IN_MAX - IN_MIN))); return ENDIAN_CONVERT((IN_T)(v * (((mixeng_real)IN_MAX - IN_MIN) / 2.f)));
#else #else
return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF)); return ENDIAN_CONVERT((IN_T)((v * ((mixeng_real)IN_MAX / 2.f)) + HALF));
#endif #endif
} }
@ -84,10 +83,9 @@ static inline int64_t glue (conv_, ET) (IN_T v)
static inline IN_T glue (clip_, ET) (int64_t v) static inline IN_T glue (clip_, ET) (int64_t v)
{ {
if (v >= 0x7f000000) { if (v >= 0x7fffffffLL) {
return IN_MAX; return IN_MAX;
} } else if (v < -2147483648LL) {
else if (v < -2147483648LL) {
return IN_MIN; return IN_MIN;
} }

View File

@ -273,6 +273,20 @@
# #
# An enumeration of possible audio formats. # An enumeration of possible audio formats.
# #
# @u8: unsigned 8 bit integer
#
# @s8: signed 8 bit integer
#
# @u16: unsigned 16 bit integer
#
# @s16: signed 16 bit integer
#
# @u32: unsigned 32 bit integer
#
# @s32: signed 32 bit integer
#
# @f32: single precision floating-point (since 5.0)
#
# Since: 4.0 # Since: 4.0
## ##
{ 'enum': 'AudioFormat', { 'enum': 'AudioFormat',

View File

@ -551,7 +551,7 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
" in|out.frequency= frequency to use with fixed settings\n" " in|out.frequency= frequency to use with fixed settings\n"
" in|out.channels= number of channels to use with fixed settings\n" " in|out.channels= number of channels to use with fixed settings\n"
" in|out.format= sample format to use with fixed settings\n" " in|out.format= sample format to use with fixed settings\n"
" valid values: s8, s16, s32, u8, u16, u32\n" " valid values: s8, s16, s32, u8, u16, u32, f32\n"
" in|out.voices= number of voices to use\n" " in|out.voices= number of voices to use\n"
" in|out.buffer-length= length of buffer in microseconds\n" " in|out.buffer-length= length of buffer in microseconds\n"
"-audiodev none,id=id,[,prop[=value][,...]]\n" "-audiodev none,id=id,[,prop[=value][,...]]\n"
@ -647,7 +647,7 @@ SRST
``in|out.format=format`` ``in|out.format=format``
Specify the sample format to use when using fixed-settings. Specify the sample format to use when using fixed-settings.
Valid values are: ``s8``, ``s16``, ``s32``, ``u8``, ``u16``, Valid values are: ``s8``, ``s16``, ``s32``, ``u8``, ``u16``,
``u32``. Default is ``s16``. ``u32``, ``f32``. Default is ``s16``.
``in|out.voices=voices`` ``in|out.voices=voices``
Specify the number of voices to use. Default is 1. Specify the number of voices to use. Default is 1.