Commit ed2a4a79 authored by Kővágó, Zoltán's avatar Kővágó, Zoltán Committed by Gerd Hoffmann
Browse files

audio: proper support for float samples in mixeng



This adds proper support for float samples in mixeng by adding a new
audio format for it.

Limitations: only native endianness is supported.  None of the virtual
sound cards support float samples (it looks like most of them only
support 8 and 16 bit, only hda supports 32 bit), it is only used for the
audio backends (i.e. host side).

Signed-off-by: default avatarKővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Acked-by: default avatarMarkus Armbruster <armbru@redhat.com>
Message-id: 8a8b0b5698401b78d3c4c8ec90aef83b95babb06.1580672076.git.DirtY.iCE.hu@gmail.com
Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent 180b044f
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -307,6 +307,13 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
            return SND_PCM_FORMAT_U32_LE;
        }

    case AUDIO_FORMAT_F32:
        if (endianness) {
            return SND_PCM_FORMAT_FLOAT_BE;
        } else {
            return SND_PCM_FORMAT_FLOAT_LE;
        }

    default:
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
@@ -370,6 +377,16 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
        *fmt = AUDIO_FORMAT_U32;
        break;

    case SND_PCM_FORMAT_FLOAT_LE:
        *endianness = 0;
        *fmt = AUDIO_FORMAT_F32;
        break;

    case SND_PCM_FORMAT_FLOAT_BE:
        *endianness = 1;
        *fmt = AUDIO_FORMAT_F32;
        break;

    default:
        dolog ("Unrecognized audio format %d\n", alsafmt);
        return -1;
+38 −18
Original line number Diff line number Diff line
@@ -218,6 +218,9 @@ static void audio_print_settings (struct audsettings *as)
    case AUDIO_FORMAT_U32:
        AUD_log (NULL, "U32");
        break;
    case AUDIO_FORMAT_F32:
        AUD_log (NULL, "F32");
        break;
    default:
        AUD_log (NULL, "invalid(%d)", as->fmt);
        break;
@@ -252,6 +255,7 @@ static int audio_validate_settings (struct audsettings *as)
    case AUDIO_FORMAT_U16:
    case AUDIO_FORMAT_S32:
    case AUDIO_FORMAT_U32:
    case AUDIO_FORMAT_F32:
        break;
    default:
        invalid = 1;
@@ -264,24 +268,28 @@ static int audio_validate_settings (struct audsettings *as)

static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
{
    int bits = 8, sign = 0;
    int bits = 8;
    bool is_signed = false, is_float = false;

    switch (as->fmt) {
    case AUDIO_FORMAT_S8:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U8:
        break;

    case AUDIO_FORMAT_S16:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U16:
        bits = 16;
        break;

    case AUDIO_FORMAT_F32:
        is_float = true;
        /* fall through */
    case AUDIO_FORMAT_S32:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U32:
        bits = 32;
@@ -292,33 +300,38 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
    }
    return info->freq == as->freq
        && info->nchannels == as->nchannels
        && info->sign == sign
        && info->is_signed == is_signed
        && info->is_float == is_float
        && info->bits == bits
        && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
}

void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
{
    int bits = 8, sign = 0, mul;
    int bits = 8, mul;
    bool is_signed = false, is_float = false;

    switch (as->fmt) {
    case AUDIO_FORMAT_S8:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U8:
        mul = 1;
        break;

    case AUDIO_FORMAT_S16:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U16:
        bits = 16;
        mul = 2;
        break;

    case AUDIO_FORMAT_F32:
        is_float = true;
        /* fall through */
    case AUDIO_FORMAT_S32:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U32:
        bits = 32;
@@ -331,7 +344,8 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)

    info->freq = as->freq;
    info->bits = bits;
    info->sign = sign;
    info->is_signed = is_signed;
    info->is_float = is_float;
    info->nchannels = as->nchannels;
    info->bytes_per_frame = as->nchannels * mul;
    info->bytes_per_second = info->freq * info->bytes_per_frame;
@@ -344,7 +358,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
        return;
    }

    if (info->sign) {
    if (info->is_signed || info->is_float) {
        memset(buf, 0x00, len * info->bytes_per_frame);
    }
    else {
@@ -770,8 +784,9 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
#ifdef DEBUG_AUDIO
static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
{
    dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
           cap, info->bits, info->sign, info->freq, info->nchannels);
    dolog("%s: bits %d, sign %d, float %d, freq %d, nchan %d\n",
          cap, info->bits, info->is_signed, info->is_float, info->freq,
          info->nchannels);
}
#endif

@@ -1832,11 +1847,15 @@ 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];
        } else {
            hw->clip = mixeng_clip
                [hw->info.nchannels == 2]
            [hw->info.sign]
                [hw->info.is_signed]
                [hw->info.swap_endianness]
                [audio_bits_to_index(hw->info.bits)];
        }

        QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
        QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
@@ -2075,6 +2094,7 @@ int audioformat_bytes_per_sample(AudioFormat fmt)

    case AUDIO_FORMAT_U32:
    case AUDIO_FORMAT_S32:
    case AUDIO_FORMAT_F32:
        return 4;

    case AUDIO_FORMAT__MAX:
+2 −1
Original line number Diff line number Diff line
@@ -40,7 +40,8 @@ struct audio_callback {

struct audio_pcm_info {
    int bits;
    int sign;
    bool is_signed;
    bool is_float;
    int freq;
    int nchannels;
    int bytes_per_frame;
+25 −16
Original line number Diff line number Diff line
@@ -153,15 +153,23 @@ static int glue (audio_pcm_sw_init_, TYPE) (
    sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
#endif

    if (sw->info.is_float) {
#ifdef DAC
        sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
#else
        sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
#endif
    } else {
#ifdef DAC
        sw->conv = mixeng_conv
#else
        sw->clip = mixeng_clip
#endif
            [sw->info.nchannels == 2]
        [sw->info.sign]
            [sw->info.is_signed]
            [sw->info.swap_endianness]
            [audio_bits_to_index(sw->info.bits)];
    }

    sw->name = g_strdup (name);
    err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
@@ -276,22 +284,23 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
        goto err1;
    }

    if (s->dev->driver == AUDIODEV_DRIVER_COREAUDIO) {
    if (hw->info.is_float) {
#ifdef DAC
        hw->clip = clip_natural_float_from_stereo;
        hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
#else
        hw->conv = conv_natural_float_to_stereo;
        hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
#endif
    } else
    } else {
#ifdef DAC
        hw->clip = mixeng_clip
#else
        hw->conv = mixeng_conv
#endif
            [hw->info.nchannels == 2]
        [hw->info.sign]
            [hw->info.is_signed]
            [hw->info.swap_endianness]
            [audio_bits_to_index(hw->info.bits)];
    }

    glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);

+1 −6
Original line number Diff line number Diff line
@@ -491,14 +491,9 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
        return -1;
    }

    /*
     * The canonical audio format for CoreAudio on macOS is float. Currently
     * there is no generic code for AUDIO_FORMAT_F32 in qemu. Here we select
     * AUDIO_FORMAT_S32 instead because only the sample size has to match.
     */
    fake_as = *as;
    as = &fake_as;
    as->fmt = AUDIO_FORMAT_S32;
    as->fmt = AUDIO_FORMAT_F32;
    audio_pcm_init_info (&hw->info, as);

    status = coreaudio_get_voice(&core->outputDeviceID);
Loading