qemu-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-commits] [COMMIT d563163] Windows Waveform Audio driver (no ADC su


From: Anthony Liguori
Subject: [Qemu-commits] [COMMIT d563163] Windows Waveform Audio driver (no ADC support yet)
Date: Fri, 09 Oct 2009 21:19:38 -0000

From: malc <address@hidden>

Signed-off-by: malc <address@hidden>

diff --git a/Makefile b/Makefile
index 8d78dc1..7d4d75c 100644
--- a/Makefile
+++ b/Makefile
@@ -141,7 +141,9 @@ audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
 audio-obj-$(CONFIG_FMOD) += fmodaudio.o
 audio-obj-$(CONFIG_ESD) += esdaudio.o
 audio-obj-$(CONFIG_PA) += paaudio.o
+audio-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
 audio-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
+audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
 audio-obj-y += wavcapture.o
 obj-y += $(addprefix audio/, $(audio-obj-y))
 
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 4acc8d5..317c9fc 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver;
 extern struct audio_driver dsound_audio_driver;
 extern struct audio_driver esd_audio_driver;
 extern struct audio_driver pa_audio_driver;
+extern struct audio_driver winwave_audio_driver;
 extern struct mixeng_volume nominal_volume;
 
 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
diff --git a/audio/audio_win_int.c b/audio/audio_win_int.c
new file mode 100644
index 0000000..5869052
--- /dev/null
+++ b/audio/audio_win_int.c
@@ -0,0 +1,108 @@
+/* public domain */
+
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "win-int"
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "audio.h"
+#include "audio_int.h"
+#include "audio_win_int.h"
+
+int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
+                                    struct audsettings *as)
+{
+    memset (wfx, 0, sizeof (*wfx));
+
+    wfx->wFormatTag = WAVE_FORMAT_PCM;
+    wfx->nChannels = as->nchannels;
+    wfx->nSamplesPerSec = as->freq;
+    wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
+    wfx->nBlockAlign = 1 << (as->nchannels == 2);
+    wfx->cbSize = 0;
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+        wfx->wBitsPerSample = 8;
+        break;
+
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+        wfx->wBitsPerSample = 16;
+        wfx->nAvgBytesPerSec <<= 1;
+        wfx->nBlockAlign <<= 1;
+        break;
+
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        wfx->wBitsPerSample = 32;
+        wfx->nAvgBytesPerSec <<= 2;
+        wfx->nBlockAlign <<= 2;
+        break;
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", as->freq);
+        return -1;
+    }
+
+    return 0;
+}
+
+int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
+                                  struct audsettings *as)
+{
+    if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
+        dolog ("Invalid wave format, tag is not PCM, but %d\n",
+               wfx->wFormatTag);
+        return -1;
+    }
+
+    if (!wfx->nSamplesPerSec) {
+        dolog ("Invalid wave format, frequency is zero\n");
+        return -1;
+    }
+    as->freq = wfx->nSamplesPerSec;
+
+    switch (wfx->nChannels) {
+    case 1:
+        as->nchannels = 1;
+        break;
+
+    case 2:
+        as->nchannels = 2;
+        break;
+
+    default:
+        dolog (
+            "Invalid wave format, number of channels is not 1 or 2, but %d\n",
+            wfx->nChannels
+            );
+        return -1;
+    }
+
+    switch (wfx->wBitsPerSample) {
+    case 8:
+        as->fmt = AUD_FMT_U8;
+        break;
+
+    case 16:
+        as->fmt = AUD_FMT_S16;
+        break;
+
+    case 32:
+        as->fmt = AUD_FMT_S32;
+        break;
+
+    default:
+        dolog ("Invalid wave format, bits per sample is not "
+               "8, 16 or 32, but %d\n",
+               wfx->wBitsPerSample);
+        return -1;
+    }
+
+    return 0;
+}
+
diff --git a/audio/audio_win_int.h b/audio/audio_win_int.h
new file mode 100644
index 0000000..fa5b3cb
--- /dev/null
+++ b/audio/audio_win_int.h
@@ -0,0 +1,10 @@
+#ifndef AUDIO_WIN_INT_H
+#define AUDIO_WIN_INT_H
+
+int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
+                                    struct audsettings *as);
+
+int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
+                                  struct audsettings *as);
+
+#endif /* AUDIO_WIN_INT_H */
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 5b255ac..e547955 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -37,6 +37,8 @@
 #include <objbase.h>
 #include <dsound.h>
 
+#include "audio_win_int.h"
+
 /* #define DEBUG_DSOUND */
 
 static struct {
@@ -304,101 +306,6 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
     return -1;
 }
 
-static int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
-                                           struct audsettings *as)
-{
-    memset (wfx, 0, sizeof (*wfx));
-
-    wfx->wFormatTag = WAVE_FORMAT_PCM;
-    wfx->nChannels = as->nchannels;
-    wfx->nSamplesPerSec = as->freq;
-    wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
-    wfx->nBlockAlign = 1 << (as->nchannels == 2);
-    wfx->cbSize = 0;
-
-    switch (as->fmt) {
-    case AUD_FMT_S8:
-    case AUD_FMT_U8:
-        wfx->wBitsPerSample = 8;
-        break;
-
-    case AUD_FMT_S16:
-    case AUD_FMT_U16:
-        wfx->wBitsPerSample = 16;
-        wfx->nAvgBytesPerSec <<= 1;
-        wfx->nBlockAlign <<= 1;
-        break;
-
-    case AUD_FMT_S32:
-    case AUD_FMT_U32:
-        wfx->wBitsPerSample = 32;
-        wfx->nAvgBytesPerSec <<= 2;
-        wfx->nBlockAlign <<= 2;
-        break;
-
-    default:
-        dolog ("Internal logic error: Bad audio format %d\n", as->freq);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
-                                         struct audsettings *as)
-{
-    if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
-        dolog ("Invalid wave format, tag is not PCM, but %d\n",
-               wfx->wFormatTag);
-        return -1;
-    }
-
-    if (!wfx->nSamplesPerSec) {
-        dolog ("Invalid wave format, frequency is zero\n");
-        return -1;
-    }
-    as->freq = wfx->nSamplesPerSec;
-
-    switch (wfx->nChannels) {
-    case 1:
-        as->nchannels = 1;
-        break;
-
-    case 2:
-        as->nchannels = 2;
-        break;
-
-    default:
-        dolog (
-            "Invalid wave format, number of channels is not 1 or 2, but %d\n",
-            wfx->nChannels
-            );
-        return -1;
-    }
-
-    switch (wfx->wBitsPerSample) {
-    case 8:
-        as->fmt = AUD_FMT_U8;
-        break;
-
-    case 16:
-        as->fmt = AUD_FMT_S16;
-        break;
-
-    case 32:
-        as->fmt = AUD_FMT_S32;
-        break;
-
-    default:
-        dolog ("Invalid wave format, bits per sample is not "
-               "8, 16 or 32, but %d\n",
-               wfx->wBitsPerSample);
-        return -1;
-    }
-
-    return 0;
-}
-
 #include "dsound_template.h"
 #define DSBTYPE_IN
 #include "dsound_template.h"
diff --git a/audio/winwaveaudio.c b/audio/winwaveaudio.c
new file mode 100644
index 0000000..139c7ef
--- /dev/null
+++ b/audio/winwaveaudio.c
@@ -0,0 +1,312 @@
+/* public domain */
+
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "winwave"
+#include "audio_int.h"
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "audio_win_int.h"
+
+static struct {
+    int dac_headers;
+    int dac_samples;
+} conf = {
+    .dac_headers = 4,
+    .dac_samples = 1024
+};
+
+typedef struct {
+    HWVoiceOut hw;
+    HWAVEOUT hwo;
+    WAVEHDR *hdrs;
+    void *pcm_buf;
+    int avail;
+    int pending;
+    int curhdr;
+    CRITICAL_SECTION crit_sect;
+} WaveVoiceOut;
+
+static void winwave_log_mmresult (MMRESULT mr)
+{
+    const char *str = "BUG";
+
+    switch (mr) {
+    case MMSYSERR_NOERROR:
+        str = "Success";
+        break;
+
+    case MMSYSERR_INVALHANDLE:
+        str = "Specified device handle is invalid";
+        break;
+
+    case MMSYSERR_BADDEVICEID:
+        str = "Specified device id is out of range";
+        break;
+
+    case MMSYSERR_NODRIVER:
+        str = "No device driver is present";
+        break;
+
+    case MMSYSERR_NOMEM:
+        str = "Unable to allocate or locl memory";
+        break;
+
+    case WAVERR_SYNC:
+        str = "Device is synchronous but waveOutOpen was called "
+            "without using the WINWAVE_ALLOWSYNC flag";
+        break;
+
+    case WAVERR_UNPREPARED:
+        str = "The data block pointed to by the pwh parameter "
+            "hasn't been prepared";
+        break;
+
+    default:
+        AUD_log (AUDIO_CAP, "Reason: Unknown (MMRESULT %#x)\n", mr);
+        return;
+    }
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", str);
+}
+
+static void GCC_FMT_ATTR (2, 3) winwave_logerr (
+    MMRESULT mr,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    winwave_log_mmresult (mr);
+}
+
+static void winwave_anal_close_out (WaveVoiceOut *wave)
+{
+    MMRESULT mr;
+
+    mr = waveOutClose (wave->hwo);
+    if (mr != MMSYSERR_NOERROR) {
+        winwave_logerr (mr, "waveOutClose\n");
+    }
+    wave->hwo = NULL;
+}
+
+static void CALLBACK winwave_callback (
+    HWAVEOUT hwo,
+    UINT msg,
+    DWORD_PTR dwInstance,
+    DWORD_PTR dwParam1,
+    DWORD_PTR dwParam2
+    )
+{
+    WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
+
+    switch (msg) {
+    case WOM_DONE:
+        {
+            WAVEHDR *h = (WAVEHDR *) dwParam1;
+            if (!h->dwUser) {
+                h->dwUser = 1;
+                EnterCriticalSection (&wave->crit_sect);
+                {
+                    wave->avail += conf.dac_samples;
+                }
+                LeaveCriticalSection (&wave->crit_sect);
+            }
+        }
+        break;
+
+    case WOM_CLOSE:
+    case WOM_OPEN:
+        break;
+
+    default:
+        AUD_log (AUDIO_CAP, "unknown wave callback msg %x\n", msg);
+    }
+}
+
+static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
+{
+    int i;
+    int err;
+    MMRESULT mr;
+    WAVEFORMATEX wfx;
+    WaveVoiceOut *wave;
+
+    wave = (WaveVoiceOut *) hw;
+
+    InitializeCriticalSection (&wave->crit_sect);
+
+    err =  waveformat_from_audio_settings (&wfx, as);
+    if (err) {
+        goto err0;
+    }
+
+    mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
+                      (DWORD_PTR) winwave_callback,
+                      (DWORD_PTR) wave, CALLBACK_FUNCTION);
+    if (mr != MMSYSERR_NOERROR) {
+        winwave_logerr (mr, "waveOutOpen\n");
+        goto err1;
+    }
+
+    wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
+                               sizeof (*wave->hdrs));
+    if (!wave->hdrs) {
+        goto err2;
+    }
+
+    audio_pcm_init_info (&hw->info, as);
+    hw->samples = conf.dac_samples * conf.dac_headers;
+    wave->avail = hw->samples;
+
+    wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
+                                  conf.dac_headers << hw->info.shift);
+    if (!wave->pcm_buf) {
+        goto err3;
+    }
+
+    for (i = 0; i < conf.dac_headers; ++i) {
+        WAVEHDR *h = &wave->hdrs[i];
+
+        h->dwUser = 0;
+        h->dwBufferLength = conf.dac_samples << hw->info.shift;
+        h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
+        h->dwFlags = 0;
+
+        mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
+        if (mr != MMSYSERR_NOERROR) {
+            winwave_logerr (mr, "waveOutPrepareHeader(%d)\n", wave->curhdr);
+            goto err4;
+        }
+    }
+
+    return 0;
+
+ err4:
+    qemu_free (wave->pcm_buf);
+ err3:
+    qemu_free (wave->hdrs);
+ err2:
+    winwave_anal_close_out (wave);
+ err1:
+ err0:
+    return -1;
+}
+
+static int winwave_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int winwave_run_out (HWVoiceOut *hw, int live)
+{
+    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
+    int decr;
+
+    EnterCriticalSection (&wave->crit_sect);
+    {
+        decr = audio_MIN (live, wave->avail);
+        decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
+        wave->pending += decr;
+        wave->avail -= decr;
+    }
+    LeaveCriticalSection (&wave->crit_sect);
+
+    while (wave->pending >= conf.dac_samples) {
+        MMRESULT mr;
+        WAVEHDR *h = &wave->hdrs[wave->curhdr];
+
+        h->dwUser = 0;
+        mr = waveOutWrite (wave->hwo, h, sizeof (*h));
+        if (mr != MMSYSERR_NOERROR) {
+            winwave_logerr (mr, "waveOutWrite(%d)\n", wave->curhdr);
+            break;
+        }
+
+        wave->pending -= conf.dac_samples;
+        wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
+    }
+    return decr;
+}
+
+static void winwave_fini_out (HWVoiceOut *hw)
+{
+    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
+
+    winwave_anal_close_out (wave);
+
+    qemu_free (wave->pcm_buf);
+    wave->pcm_buf = NULL;
+
+    qemu_free (wave->hdrs);
+    wave->hdrs = NULL;
+}
+
+static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    switch (cmd) {
+    case VOICE_ENABLE:
+        return 0;
+
+    case VOICE_DISABLE:
+        return 0;
+    }
+    return -1;
+}
+
+static void *winwave_audio_init (void)
+{
+    return &conf;
+}
+
+static void winwave_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+static struct audio_option winwave_options[] = {
+    {
+        .name        = "DAC_HEADERS",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.dac_headers,
+        .descr       = "DAC number of headers",
+    },
+    {
+        .name        = "DAC_SAMPLES",
+        .tag         = AUD_OPT_INT,
+        .valp        = &conf.dac_samples,
+        .descr       = "DAC number of samples per header",
+    },
+    { /* End of list */ }
+};
+
+static struct audio_pcm_ops winwave_pcm_ops = {
+    .init_out = winwave_init_out,
+    .fini_out = winwave_fini_out,
+    .run_out  = winwave_run_out,
+    .write    = winwave_write,
+    .ctl_out  = winwave_ctl_out
+};
+
+struct audio_driver winwave_audio_driver = {
+    .name           = "winwave",
+    .descr          = "Windows Waveform Audio http://msdn.microsoft.com";,
+    .options        = winwave_options,
+    .init           = winwave_audio_init,
+    .fini           = winwave_audio_fini,
+    .pcm_ops        = &winwave_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = INT_MAX,
+    .max_voices_in  = 0,
+    .voice_size_out = sizeof (WaveVoiceOut),
+    .voice_size_in  = 0
+};
diff --git a/configure b/configure
index 39658ff..3840e18 100755
--- a/configure
+++ b/configure
@@ -48,6 +48,7 @@ helper_cflags=""
 libs_softmmu=""
 libs_tools=""
 audio_pt_int=""
+audio_win_int=""
 
 # parse CC options first
 for opt do
@@ -242,11 +243,13 @@ case $targetos in
 CYGWIN*)
   mingw32="yes"
   QEMU_CFLAGS="-mno-cygwin $QEMU_CFLAGS"
-  audio_possible_drivers="sdl"
+  audio_possible_drivers="winwave sdl"
+  audio_drv_list="winwave"
 ;;
 MINGW32*)
   mingw32="yes"
-  audio_possible_drivers="dsound sdl fmod"
+  audio_possible_drivers="winwave dsound sdl fmod"
+  audio_drv_list="winwave"
 ;;
 GNU/kFreeBSD)
   audio_drv_list="oss"
@@ -1169,6 +1172,7 @@ for drv in $audio_drv_list; do
 
     dsound)
       libs_softmmu="-lole32 -ldxguid $libs_softmmu"
+      audio_win_int="yes"
     ;;
 
     oss)
@@ -1179,6 +1183,11 @@ for drv in $audio_drv_list; do
     # XXX: Probes for CoreAudio, DirectSound, SDL(?)
     ;;
 
+    winwave)
+      libs_softmmu="-lwinmm $libs_softmmu"
+      audio_win_int="yes"
+    ;;
+
     *)
     echo "$audio_possible_drivers" | grep -q "\<$drv\>" || {
         echo
@@ -1885,6 +1894,9 @@ done
 if test "$audio_pt_int" = "yes" ; then
   echo "CONFIG_AUDIO_PT_INT=y" >> $config_host_mak
 fi
+if test "$audio_win_int" = "yes" ; then
+  echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak
+fi
 if test "$mixemu" = "yes" ; then
   echo "CONFIG_MIXEMU=y" >> $config_host_mak
 fi




reply via email to

[Prev in Thread] Current Thread [Next in Thread]