aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Rümelin <vr_qemu@t-online.de>2025-05-15 07:44:29 +0200
committerMarc-André Lureau <marcandre.lureau@redhat.com>2025-05-25 11:28:28 +0200
commit5d978c5da7f7d85d3a74b7d4dbe9ba5c5584d560 (patch)
tree472e1b3621572c13e025084ea9344005887d64ce
parent9ddb7c85c965636f7abf91382dc40175ce121aa3 (diff)
downloadqemu-5d978c5da7f7d85d3a74b7d4dbe9ba5c5584d560.zip
qemu-5d978c5da7f7d85d3a74b7d4dbe9ba5c5584d560.tar.gz
qemu-5d978c5da7f7d85d3a74b7d4dbe9ba5c5584d560.tar.bz2
audio: add float sample endianness converters
Commit ed2a4a7941 ("audio: proper support for float samples in mixeng") added support for float audio samples. As there were no audio frontend devices with float support at that time, the code was limited to native endian float samples. When nobody was paying attention, an audio device that supports floating point samples crept in with commit eb9ad377bb ("virtio-sound: handle control messages and streams"). Add code for the audio subsystem to convert float samples to the correct endianness. The type punning code was taken from the PipeWire project. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de> Message-Id: <20250515054429.7385-7-vr_qemu@t-online.de>
-rw-r--r--audio/audio.c3
-rw-r--r--audio/audio_template.h12
-rw-r--r--audio/mixeng.c75
-rw-r--r--audio/mixeng.h6
4 files changed, 82 insertions, 14 deletions
diff --git a/audio/audio.c b/audio/audio.c
index 3f5baf0..b58ad74 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1892,7 +1892,8 @@ CaptureVoiceOut *AUD_add_capture(
cap->buf = g_malloc0_n(hw->mix_buf.size, hw->info.bytes_per_frame);
if (hw->info.is_float) {
- hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
+ hw->clip = mixeng_clip_float[hw->info.nchannels == 2]
+ [hw->info.swap_endianness];
} else {
hw->clip = mixeng_clip
[hw->info.nchannels == 2]
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 7ccfec0..c29d79c 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -174,9 +174,11 @@ static int glue (audio_pcm_sw_init_, TYPE) (
if (sw->info.is_float) {
#ifdef DAC
- sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
+ sw->conv = mixeng_conv_float[sw->info.nchannels == 2]
+ [sw->info.swap_endianness];
#else
- sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
+ sw->clip = mixeng_clip_float[sw->info.nchannels == 2]
+ [sw->info.swap_endianness];
#endif
} else {
#ifdef DAC
@@ -303,9 +305,11 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
if (hw->info.is_float) {
#ifdef DAC
- hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
+ hw->clip = mixeng_clip_float[hw->info.nchannels == 2]
+ [hw->info.swap_endianness];
#else
- hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
+ hw->conv = mixeng_conv_float[hw->info.nchannels == 2]
+ [hw->info.swap_endianness];
#endif
} else {
#ifdef DAC
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 13e1ff9..703ee54 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -283,6 +283,11 @@ static const float float_scale_reciprocal = 1.f / ((int64_t)INT32_MAX + 1);
#endif
#endif
+#define F32_TO_F32S(v) \
+ bswap32((union { uint32_t i; float f; }){ .f = (v) }.i)
+#define F32S_TO_F32(v) \
+ ((union { uint32_t i; float f; }){ .i = bswap32(v) }.f)
+
static void conv_natural_float_to_mono(struct st_sample *dst, const void *src,
int samples)
{
@@ -294,6 +299,17 @@ static void conv_natural_float_to_mono(struct st_sample *dst, const void *src,
}
}
+static void conv_swap_float_to_mono(struct st_sample *dst, const void *src,
+ int samples)
+{
+ const uint32_t *in_f32s = src;
+
+ while (samples--) {
+ dst->r = dst->l = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++));
+ dst++;
+ }
+}
+
static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src,
int samples)
{
@@ -306,9 +322,27 @@ static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src,
}
}
-t_sample *mixeng_conv_float[2] = {
- conv_natural_float_to_mono,
- conv_natural_float_to_stereo,
+static void conv_swap_float_to_stereo(struct st_sample *dst, const void *src,
+ int samples)
+{
+ const uint32_t *in_f32s = src;
+
+ while (samples--) {
+ dst->l = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++));
+ dst->r = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++));
+ dst++;
+ }
+}
+
+t_sample *mixeng_conv_float[2][2] = {
+ {
+ conv_natural_float_to_mono,
+ conv_swap_float_to_mono,
+ },
+ {
+ conv_natural_float_to_stereo,
+ conv_swap_float_to_stereo,
+ }
};
static void clip_natural_float_from_mono(void *dst, const struct st_sample *src,
@@ -322,6 +356,17 @@ static void clip_natural_float_from_mono(void *dst, const struct st_sample *src,
}
}
+static void clip_swap_float_from_mono(void *dst, const struct st_sample *src,
+ int samples)
+{
+ uint32_t *out_f32s = dst;
+
+ while (samples--) {
+ *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->l + src->r));
+ src++;
+ }
+}
+
static void clip_natural_float_from_stereo(
void *dst, const struct st_sample *src, int samples)
{
@@ -334,9 +379,27 @@ static void clip_natural_float_from_stereo(
}
}
-f_sample *mixeng_clip_float[2] = {
- clip_natural_float_from_mono,
- clip_natural_float_from_stereo,
+static void clip_swap_float_from_stereo(
+ void *dst, const struct st_sample *src, int samples)
+{
+ uint32_t *out_f32s = dst;
+
+ while (samples--) {
+ *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->l));
+ *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->r));
+ src++;
+ }
+}
+
+f_sample *mixeng_clip_float[2][2] = {
+ {
+ clip_natural_float_from_mono,
+ clip_swap_float_from_mono,
+ },
+ {
+ clip_natural_float_from_stereo,
+ clip_swap_float_from_stereo,
+ }
};
void audio_sample_to_uint64(const void *samples, int pos,
diff --git a/audio/mixeng.h b/audio/mixeng.h
index a5f56d2..ead93ac 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -42,9 +42,9 @@ typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
extern t_sample *mixeng_conv[2][2][2][3];
extern f_sample *mixeng_clip[2][2][2][3];
-/* indices: [stereo] */
-extern t_sample *mixeng_conv_float[2];
-extern f_sample *mixeng_clip_float[2];
+/* indices: [stereo][swap endianness] */
+extern t_sample *mixeng_conv_float[2][2];
+extern f_sample *mixeng_clip_float[2][2];
void *st_rate_start (int inrate, int outrate);
void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,