From f941aa256f2254c3f35f00fcf5d7f20dba55a5b7 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Feb 2007 22:19:29 +0000 Subject: [PATCH] Qemu support for S32 and U32 alsa output, by Vassili Karpov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2427 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 26 ++++++++++ audio/audio.c | 112 ++++++++++++++++++++++++++++++++++------- audio/audio.h | 4 +- audio/audio_template.h | 4 +- audio/coreaudio.c | 5 -- audio/mixeng.c | 95 +++++++++++++++++++++++++++------- audio/mixeng.h | 4 +- audio/wavaudio.c | 8 ++- audio/wavcapture.c | 6 +-- 9 files changed, 215 insertions(+), 49 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 71e5235664..2e59dfa4c4 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -157,6 +157,12 @@ static int aud_to_alsafmt (audfmt_e fmt) case AUD_FMT_U16: return SND_PCM_FORMAT_U16_LE; + case AUD_FMT_S32: + return SND_PCM_FORMAT_S32_LE; + + case AUD_FMT_U32: + return SND_PCM_FORMAT_U32_LE; + default: dolog ("Internal logic error: Bad audio format %d\n", fmt); #ifdef DEBUG_AUDIO @@ -199,6 +205,26 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness) *fmt = AUD_FMT_U16; break; + case SND_PCM_FORMAT_S32_LE: + *endianness = 0; + *fmt = AUD_FMT_S32; + break; + + case SND_PCM_FORMAT_U32_LE: + *endianness = 0; + *fmt = AUD_FMT_U32; + break; + + case SND_PCM_FORMAT_S32_BE: + *endianness = 1; + *fmt = AUD_FMT_S32; + break; + + case SND_PCM_FORMAT_U32_BE: + *endianness = 1; + *fmt = AUD_FMT_U32; + break; + default: dolog ("Unrecognized audio format %d\n", alsafmt); return -1; diff --git a/audio/audio.c b/audio/audio.c index 556e6fdbcb..5d3c7f15f0 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -80,7 +80,8 @@ static struct { { 44100, /* freq */ 2, /* nchannels */ - AUD_FMT_S16 /* fmt */ + AUD_FMT_S16, /* fmt */ + AUDIO_HOST_ENDIANNESS } }, @@ -91,7 +92,8 @@ static struct { { 44100, /* freq */ 2, /* nchannels */ - AUD_FMT_S16 /* fmt */ + AUD_FMT_S16, /* fmt */ + AUDIO_HOST_ENDIANNESS } }, @@ -166,6 +168,25 @@ int audio_bug (const char *funcname, int cond) } #endif +static inline int audio_bits_to_index (int bits) +{ + switch (bits) { + case 8: + return 0; + + case 16: + return 1; + + case 32: + return 2; + + default: + audio_bug ("bits_to_index", 1); + AUD_log (NULL, "invalid bits %d\n", bits); + return 0; + } +} + void *audio_calloc (const char *funcname, int nmemb, size_t size) { int cond; @@ -227,6 +248,12 @@ const char *audio_audfmt_to_string (audfmt_e fmt) case AUD_FMT_S16: return "S16"; + + case AUD_FMT_U32: + return "U32"; + + case AUD_FMT_S32: + return "S32"; } dolog ("Bogus audfmt %d returning S16\n", fmt); @@ -243,6 +270,10 @@ audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp) *defaultp = 0; return AUD_FMT_U16; } + else if (!strcasecmp (s, "u32")) { + *defaultp = 0; + return AUD_FMT_U32; + } else if (!strcasecmp (s, "s8")) { *defaultp = 0; return AUD_FMT_S8; @@ -251,6 +282,10 @@ audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp) *defaultp = 0; return AUD_FMT_S16; } + else if (!strcasecmp (s, "s32")) { + *defaultp = 0; + return AUD_FMT_S32; + } else { dolog ("Bogus audio format `%s' using %s\n", s, audio_audfmt_to_string (defval)); @@ -538,6 +573,8 @@ static int audio_validate_settings (audsettings_t *as) case AUD_FMT_U8: case AUD_FMT_S16: case AUD_FMT_U16: + case AUD_FMT_S32: + case AUD_FMT_U32: break; default: invalid = 1; @@ -563,6 +600,12 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) case AUD_FMT_U16: bits = 16; break; + + case AUD_FMT_S32: + sign = 1; + case AUD_FMT_U32: + bits = 32; + break; } return info->freq == as->freq && info->nchannels == as->nchannels @@ -573,7 +616,7 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) { - int bits = 8, sign = 0; + int bits = 8, sign = 0, shift = 0; switch (as->fmt) { case AUD_FMT_S8: @@ -585,6 +628,14 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) sign = 1; case AUD_FMT_U16: bits = 16; + shift = 1; + break; + + case AUD_FMT_S32: + sign = 1; + case AUD_FMT_U32: + bits = 32; + shift = 2; break; } @@ -592,7 +643,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) info->bits = bits; info->sign = sign; info->nchannels = as->nchannels; - info->shift = (as->nchannels == 2) + (bits == 16); + info->shift = (as->nchannels == 2) + shift; info->align = (1 << info->shift) - 1; info->bytes_per_second = info->freq << info->shift; info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); @@ -608,22 +659,49 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) memset (buf, 0x00, len << info->shift); } else { - if (info->bits == 8) { + switch (info->bits) { + case 8: memset (buf, 0x80, len << info->shift); - } - else { - int i; - uint16_t *p = buf; - int shift = info->nchannels - 1; - short s = INT16_MAX; + break; - if (info->swap_endianness) { - s = bswap16 (s); - } + case 16: + { + int i; + uint16_t *p = buf; + int shift = info->nchannels - 1; + short s = INT16_MAX; - for (i = 0; i < len << shift; i++) { - p[i] = s; + if (info->swap_endianness) { + s = bswap16 (s); + } + + for (i = 0; i < len << shift; i++) { + p[i] = s; + } } + break; + + case 32: + { + int i; + uint32_t *p = buf; + int shift = info->nchannels - 1; + int32_t s = INT32_MAX; + + if (info->swap_endianness) { + s = bswap32 (s); + } + + for (i = 0; i < len << shift; i++) { + p[i] = s; + } + } + break; + + default: + AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n", + info->bits); + break; } } } @@ -1811,7 +1889,7 @@ CaptureVoiceOut *AUD_add_capture ( [hw->info.nchannels == 2] [hw->info.sign] [hw->info.swap_endianness] - [hw->info.bits == 16]; + [audio_bits_to_index (hw->info.bits)]; LIST_INSERT_HEAD (&s->cap_head, cap, entries); LIST_INSERT_HEAD (&cap->cb_head, cb, entries); diff --git a/audio/audio.h b/audio/audio.h index c097f391bb..287cc5c734 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -33,7 +33,9 @@ typedef enum { AUD_FMT_U8, AUD_FMT_S8, AUD_FMT_U16, - AUD_FMT_S16 + AUD_FMT_S16, + AUD_FMT_U32, + AUD_FMT_S32 } audfmt_e; #ifdef WORDS_BIGENDIAN diff --git a/audio/audio_template.h b/audio/audio_template.h index 13e1c3efbb..850e101d72 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -164,7 +164,7 @@ static int glue (audio_pcm_sw_init_, TYPE) ( [sw->info.nchannels == 2] [sw->info.sign] [sw->info.swap_endianness] - [sw->info.bits == 16]; + [audio_bits_to_index (sw->info.bits)]; sw->name = qemu_strdup (name); err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); @@ -288,7 +288,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) [hw->info.nchannels == 2] [hw->info.sign] [hw->info.swap_endianness] - [hw->info.bits == 16]; + [audio_bits_to_index (hw->info.bits)]; if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { goto err1; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 8512f122b0..74d432f91e 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -294,7 +294,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; UInt32 propertySize; int err; - int bits = 8; const char *typ = "playback"; AudioValueRange frameRange; @@ -305,10 +304,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) return -1; } - if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { - bits = 16; - } - audio_pcm_init_info (&hw->info, as); /* open default output device */ diff --git a/audio/mixeng.c b/audio/mixeng.c index 6308d41004..34cc1aeee4 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -82,6 +82,7 @@ #undef IN_T #undef SHIFT +/* Unsigned 16 bit */ #define IN_T uint16_t #define IN_MIN 0 #define IN_MAX USHRT_MAX @@ -101,26 +102,72 @@ #undef IN_T #undef SHIFT -t_sample *mixeng_conv[2][2][2][2] = { +/* Signed 32 bit */ +#define IN_T int32_t +#define IN_MIN INT32_MIN +#define IN_MAX INT32_MAX +#define SIGNED +#define SHIFT 32 +#define ENDIAN_CONVERSION natural +#define ENDIAN_CONVERT(v) (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#define ENDIAN_CONVERSION swap +#define ENDIAN_CONVERT(v) bswap32 (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#undef SIGNED +#undef IN_MAX +#undef IN_MIN +#undef IN_T +#undef SHIFT + +/* Unsigned 16 bit */ +#define IN_T uint32_t +#define IN_MIN 0 +#define IN_MAX UINT32_MAX +#define SHIFT 32 +#define ENDIAN_CONVERSION natural +#define ENDIAN_CONVERT(v) (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#define ENDIAN_CONVERSION swap +#define ENDIAN_CONVERT(v) bswap32 (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#undef IN_MAX +#undef IN_MIN +#undef IN_T +#undef SHIFT + +t_sample *mixeng_conv[2][2][2][3] = { { { { conv_natural_uint8_t_to_mono, - conv_natural_uint16_t_to_mono + conv_natural_uint16_t_to_mono, + conv_natural_uint32_t_to_mono }, { conv_natural_uint8_t_to_mono, - conv_swap_uint16_t_to_mono + conv_swap_uint16_t_to_mono, + conv_swap_uint32_t_to_mono, } }, { { conv_natural_int8_t_to_mono, - conv_natural_int16_t_to_mono + conv_natural_int16_t_to_mono, + conv_natural_int32_t_to_mono }, { conv_natural_int8_t_to_mono, - conv_swap_int16_t_to_mono + conv_swap_int16_t_to_mono, + conv_swap_int32_t_to_mono } } }, @@ -128,46 +175,54 @@ t_sample *mixeng_conv[2][2][2][2] = { { { conv_natural_uint8_t_to_stereo, - conv_natural_uint16_t_to_stereo + conv_natural_uint16_t_to_stereo, + conv_natural_uint32_t_to_stereo }, { conv_natural_uint8_t_to_stereo, - conv_swap_uint16_t_to_stereo + conv_swap_uint16_t_to_stereo, + conv_swap_uint32_t_to_stereo } }, { { conv_natural_int8_t_to_stereo, - conv_natural_int16_t_to_stereo + conv_natural_int16_t_to_stereo, + conv_natural_int32_t_to_stereo }, { conv_natural_int8_t_to_stereo, - conv_swap_int16_t_to_stereo + conv_swap_int16_t_to_stereo, + conv_swap_int32_t_to_stereo, } } } }; -f_sample *mixeng_clip[2][2][2][2] = { +f_sample *mixeng_clip[2][2][2][3] = { { { { clip_natural_uint8_t_from_mono, - clip_natural_uint16_t_from_mono + clip_natural_uint16_t_from_mono, + clip_natural_uint32_t_from_mono }, { clip_natural_uint8_t_from_mono, - clip_swap_uint16_t_from_mono + clip_swap_uint16_t_from_mono, + clip_swap_uint32_t_from_mono } }, { { clip_natural_int8_t_from_mono, - clip_natural_int16_t_from_mono + clip_natural_int16_t_from_mono, + clip_natural_int32_t_from_mono }, { clip_natural_int8_t_from_mono, - clip_swap_int16_t_from_mono + clip_swap_int16_t_from_mono, + clip_swap_int32_t_from_mono } } }, @@ -175,21 +230,25 @@ f_sample *mixeng_clip[2][2][2][2] = { { { clip_natural_uint8_t_from_stereo, - clip_natural_uint16_t_from_stereo + clip_natural_uint16_t_from_stereo, + clip_natural_uint32_t_from_stereo }, { clip_natural_uint8_t_from_stereo, - clip_swap_uint16_t_from_stereo + clip_swap_uint16_t_from_stereo, + clip_swap_uint32_t_from_stereo } }, { { clip_natural_int8_t_from_stereo, - clip_natural_int16_t_from_stereo + clip_natural_int16_t_from_stereo, + clip_natural_int32_t_from_stereo }, { clip_natural_int8_t_from_stereo, - clip_swap_int16_t_from_stereo + clip_swap_int16_t_from_stereo, + clip_swap_int32_t_from_stereo } } } diff --git a/audio/mixeng.h b/audio/mixeng.h index 9e3bac1744..95b68df6ac 100644 --- a/audio/mixeng.h +++ b/audio/mixeng.h @@ -37,8 +37,8 @@ typedef void (t_sample) (st_sample_t *dst, const void *src, int samples, volume_t *vol); typedef void (f_sample) (void *dst, const st_sample_t *src, int samples); -extern t_sample *mixeng_conv[2][2][2][2]; -extern f_sample *mixeng_clip[2][2][2][2]; +extern t_sample *mixeng_conv[2][2][2][3]; +extern f_sample *mixeng_clip[2][2][2][3]; void *st_rate_start (int inrate, int outrate); void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, diff --git a/audio/wavaudio.c b/audio/wavaudio.c index a552b7e973..2dbc58cbe1 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -41,7 +41,8 @@ static struct { { 44100, 2, - AUD_FMT_S16 + AUD_FMT_S16, + AUDIO_HOST_ENDIANNESS }, "qemu.wav" }; @@ -131,6 +132,11 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) case AUD_FMT_U16: bits16 = 1; break; + + case AUD_FMT_S32: + case AUD_FMT_U32: + dolog ("WAVE files can not handle 32bit formats\n"); + return -1; } hdr[34] = bits16 ? 0x10 : 0x08; diff --git a/audio/wavcapture.c b/audio/wavcapture.c index d915fa02bf..4810fa30dd 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -37,15 +37,15 @@ static void wav_destroy (void *opaque) if (wav->f) { le_store (rlen, rifflen, 4); le_store (dlen, datalen, 4); - + qemu_fseek (wav->f, 4, SEEK_SET); qemu_put_buffer (wav->f, rlen, 4); - + qemu_fseek (wav->f, 32, SEEK_CUR); qemu_put_buffer (wav->f, dlen, 4); qemu_fclose (wav->f); } - + qemu_free (wav->path); }