Qemu support for S32 and U32 alsa output, by Vassili Karpov.
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 17 Feb 2007 22:19:29 +0000 (22:19 +0000)
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 17 Feb 2007 22:19:29 +0000 (22:19 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2427 c046a42c-6fe2-441c-8c8c-71466251a162

audio/alsaaudio.c
audio/audio.c
audio/audio.h
audio/audio_template.h
audio/coreaudio.c
audio/mixeng.c
audio/mixeng.h
audio/wavaudio.c
audio/wavcapture.c

index 71e5235..2e59dfa 100644 (file)
@@ -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;
index 556e6fd..5d3c7f1 100644 (file)
@@ -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;
+
+                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;
+                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);
index c097f39..287cc5c 100644 (file)
@@ -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
index 13e1c3e..850e101 100644 (file)
@@ -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;
index 8512f12..74d432f 100644 (file)
@@ -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 */
index 6308d41..34cc1ae 100644 (file)
@@ -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
 #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
             }
         }
     }
index 9e3bac1..95b68df 100644 (file)
@@ -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,
index a552b7e..2dbc58c 100644 (file)
@@ -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;
index d915fa0..4810fa3 100644 (file)
@@ -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);
 }