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
This commit is contained in:
ths 2007-02-17 22:19:29 +00:00
parent b93aebecb0
commit f941aa256f
9 changed files with 215 additions and 49 deletions

View File

@ -157,6 +157,12 @@ static int aud_to_alsafmt (audfmt_e fmt)
case AUD_FMT_U16: case AUD_FMT_U16:
return SND_PCM_FORMAT_U16_LE; 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: default:
dolog ("Internal logic error: Bad audio format %d\n", fmt); dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
@ -199,6 +205,26 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
*fmt = AUD_FMT_U16; *fmt = AUD_FMT_U16;
break; 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: default:
dolog ("Unrecognized audio format %d\n", alsafmt); dolog ("Unrecognized audio format %d\n", alsafmt);
return -1; return -1;

View File

@ -80,7 +80,8 @@ static struct {
{ {
44100, /* freq */ 44100, /* freq */
2, /* nchannels */ 2, /* nchannels */
AUD_FMT_S16 /* fmt */ AUD_FMT_S16, /* fmt */
AUDIO_HOST_ENDIANNESS
} }
}, },
@ -91,7 +92,8 @@ static struct {
{ {
44100, /* freq */ 44100, /* freq */
2, /* nchannels */ 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 #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) void *audio_calloc (const char *funcname, int nmemb, size_t size)
{ {
int cond; int cond;
@ -227,6 +248,12 @@ const char *audio_audfmt_to_string (audfmt_e fmt)
case AUD_FMT_S16: case AUD_FMT_S16:
return "S16"; return "S16";
case AUD_FMT_U32:
return "U32";
case AUD_FMT_S32:
return "S32";
} }
dolog ("Bogus audfmt %d returning S16\n", fmt); 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; *defaultp = 0;
return AUD_FMT_U16; return AUD_FMT_U16;
} }
else if (!strcasecmp (s, "u32")) {
*defaultp = 0;
return AUD_FMT_U32;
}
else if (!strcasecmp (s, "s8")) { else if (!strcasecmp (s, "s8")) {
*defaultp = 0; *defaultp = 0;
return AUD_FMT_S8; return AUD_FMT_S8;
@ -251,6 +282,10 @@ audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp)
*defaultp = 0; *defaultp = 0;
return AUD_FMT_S16; return AUD_FMT_S16;
} }
else if (!strcasecmp (s, "s32")) {
*defaultp = 0;
return AUD_FMT_S32;
}
else { else {
dolog ("Bogus audio format `%s' using %s\n", dolog ("Bogus audio format `%s' using %s\n",
s, audio_audfmt_to_string (defval)); 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_U8:
case AUD_FMT_S16: case AUD_FMT_S16:
case AUD_FMT_U16: case AUD_FMT_U16:
case AUD_FMT_S32:
case AUD_FMT_U32:
break; break;
default: default:
invalid = 1; invalid = 1;
@ -563,6 +600,12 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
case AUD_FMT_U16: case AUD_FMT_U16:
bits = 16; bits = 16;
break; break;
case AUD_FMT_S32:
sign = 1;
case AUD_FMT_U32:
bits = 32;
break;
} }
return info->freq == as->freq return info->freq == as->freq
&& info->nchannels == as->nchannels && 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) 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) { switch (as->fmt) {
case AUD_FMT_S8: case AUD_FMT_S8:
@ -585,6 +628,14 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
sign = 1; sign = 1;
case AUD_FMT_U16: case AUD_FMT_U16:
bits = 16; bits = 16;
shift = 1;
break;
case AUD_FMT_S32:
sign = 1;
case AUD_FMT_U32:
bits = 32;
shift = 2;
break; break;
} }
@ -592,7 +643,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
info->bits = bits; info->bits = bits;
info->sign = sign; info->sign = sign;
info->nchannels = as->nchannels; info->nchannels = as->nchannels;
info->shift = (as->nchannels == 2) + (bits == 16); info->shift = (as->nchannels == 2) + shift;
info->align = (1 << info->shift) - 1; info->align = (1 << info->shift) - 1;
info->bytes_per_second = info->freq << info->shift; info->bytes_per_second = info->freq << info->shift;
info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); 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); memset (buf, 0x00, len << info->shift);
} }
else { else {
if (info->bits == 8) { switch (info->bits) {
case 8:
memset (buf, 0x80, len << info->shift); memset (buf, 0x80, len << info->shift);
} break;
else {
int i;
uint16_t *p = buf;
int shift = info->nchannels - 1;
short s = INT16_MAX;
if (info->swap_endianness) { case 16:
s = bswap16 (s); {
} int i;
uint16_t *p = buf;
int shift = info->nchannels - 1;
short s = INT16_MAX;
for (i = 0; i < len << shift; i++) { if (info->swap_endianness) {
p[i] = s; 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.nchannels == 2]
[hw->info.sign] [hw->info.sign]
[hw->info.swap_endianness] [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 (&s->cap_head, cap, entries);
LIST_INSERT_HEAD (&cap->cb_head, cb, entries); LIST_INSERT_HEAD (&cap->cb_head, cb, entries);

View File

@ -33,7 +33,9 @@ typedef enum {
AUD_FMT_U8, AUD_FMT_U8,
AUD_FMT_S8, AUD_FMT_S8,
AUD_FMT_U16, AUD_FMT_U16,
AUD_FMT_S16 AUD_FMT_S16,
AUD_FMT_U32,
AUD_FMT_S32
} audfmt_e; } audfmt_e;
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN

View File

@ -164,7 +164,7 @@ static int glue (audio_pcm_sw_init_, TYPE) (
[sw->info.nchannels == 2] [sw->info.nchannels == 2]
[sw->info.sign] [sw->info.sign]
[sw->info.swap_endianness] [sw->info.swap_endianness]
[sw->info.bits == 16]; [audio_bits_to_index (sw->info.bits)];
sw->name = qemu_strdup (name); sw->name = qemu_strdup (name);
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); 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.nchannels == 2]
[hw->info.sign] [hw->info.sign]
[hw->info.swap_endianness] [hw->info.swap_endianness]
[hw->info.bits == 16]; [audio_bits_to_index (hw->info.bits)];
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
goto err1; goto err1;

View File

@ -294,7 +294,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
UInt32 propertySize; UInt32 propertySize;
int err; int err;
int bits = 8;
const char *typ = "playback"; const char *typ = "playback";
AudioValueRange frameRange; AudioValueRange frameRange;
@ -305,10 +304,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
return -1; return -1;
} }
if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
bits = 16;
}
audio_pcm_init_info (&hw->info, as); audio_pcm_init_info (&hw->info, as);
/* open default output device */ /* open default output device */

View File

@ -82,6 +82,7 @@
#undef IN_T #undef IN_T
#undef SHIFT #undef SHIFT
/* Unsigned 16 bit */
#define IN_T uint16_t #define IN_T uint16_t
#define IN_MIN 0 #define IN_MIN 0
#define IN_MAX USHRT_MAX #define IN_MAX USHRT_MAX
@ -101,26 +102,72 @@
#undef IN_T #undef IN_T
#undef SHIFT #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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_natural_int8_t_from_stereo,
clip_swap_int16_t_from_stereo clip_swap_int16_t_from_stereo,
clip_swap_int32_t_from_stereo
} }
} }
} }

View File

@ -37,8 +37,8 @@ typedef void (t_sample) (st_sample_t *dst, const void *src,
int samples, volume_t *vol); int samples, volume_t *vol);
typedef void (f_sample) (void *dst, const st_sample_t *src, int samples); typedef void (f_sample) (void *dst, const st_sample_t *src, int samples);
extern t_sample *mixeng_conv[2][2][2][2]; extern t_sample *mixeng_conv[2][2][2][3];
extern f_sample *mixeng_clip[2][2][2][2]; extern f_sample *mixeng_clip[2][2][2][3];
void *st_rate_start (int inrate, int outrate); void *st_rate_start (int inrate, int outrate);
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,

View File

@ -41,7 +41,8 @@ static struct {
{ {
44100, 44100,
2, 2,
AUD_FMT_S16 AUD_FMT_S16,
AUDIO_HOST_ENDIANNESS
}, },
"qemu.wav" "qemu.wav"
}; };
@ -131,6 +132,11 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
case AUD_FMT_U16: case AUD_FMT_U16:
bits16 = 1; bits16 = 1;
break; 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; hdr[34] = bits16 ? 0x10 : 0x08;

View File

@ -37,15 +37,15 @@ static void wav_destroy (void *opaque)
if (wav->f) { if (wav->f) {
le_store (rlen, rifflen, 4); le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4); le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET); qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4); qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR); qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4); qemu_put_buffer (wav->f, dlen, 4);
qemu_fclose (wav->f); qemu_fclose (wav->f);
} }
qemu_free (wav->path); qemu_free (wav->path);
} }