[PATCH 1/2] xaudio2: Rewrite to use FAudio

elee at codeweavers.com elee at codeweavers.com
Wed Feb 6 16:21:19 CST 2019


From: Ethan Lee <elee at codeweavers.com>

FAudio Website: https://github.com/FNA-XNA/FAudio

Signed-off-by: Ethan Lee <elee at codeweavers.com>
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
 configure.ac                      |   24 +-
 dlls/x3daudio1_0/Makefile.in      |    2 +
 dlls/x3daudio1_1/Makefile.in      |    2 +
 dlls/x3daudio1_2/Makefile.in      |    2 +
 dlls/x3daudio1_3/Makefile.in      |    2 +
 dlls/x3daudio1_4/Makefile.in      |    2 +
 dlls/x3daudio1_5/Makefile.in      |    2 +
 dlls/x3daudio1_6/Makefile.in      |    2 +
 dlls/x3daudio1_7/Makefile.in      |    2 +
 dlls/xapofx1_1/Makefile.in        |    6 +-
 dlls/xapofx1_2/Makefile.in        |    6 +-
 dlls/xapofx1_3/Makefile.in        |    6 +-
 dlls/xapofx1_4/Makefile.in        |    6 +-
 dlls/xapofx1_5/Makefile.in        |    6 +-
 dlls/xaudio2_0/Makefile.in        |    8 +-
 dlls/xaudio2_1/Makefile.in        |    8 +-
 dlls/xaudio2_2/Makefile.in        |    8 +-
 dlls/xaudio2_3/Makefile.in        |    8 +-
 dlls/xaudio2_4/Makefile.in        |    8 +-
 dlls/xaudio2_5/Makefile.in        |    8 +-
 dlls/xaudio2_6/Makefile.in        |    8 +-
 dlls/xaudio2_7/Makefile.in        |    9 +-
 dlls/xaudio2_7/compat.c           |  774 ++++-----
 dlls/xaudio2_7/tests/xaudio2.c    | 1075 +-----------
 dlls/xaudio2_7/x3daudio.c         |   36 +-
 dlls/xaudio2_7/xapo.c             |  405 +++++
 dlls/xaudio2_7/xapofx.c           |  792 +--------
 dlls/xaudio2_7/xaudio_allocator.c |   41 +
 dlls/xaudio2_7/xaudio_classes.idl |    7 -
 dlls/xaudio2_7/xaudio_dll.c       | 2598 ++++++++++++-----------------
 dlls/xaudio2_7/xaudio_private.h   |  174 +-
 dlls/xaudio2_8/Makefile.in        |    9 +-
 dlls/xaudio2_9/Makefile.in        |    9 +-
 33 files changed, 2086 insertions(+), 3969 deletions(-)
 create mode 100644 dlls/xaudio2_7/xapo.c
 create mode 100644 dlls/xaudio2_7/xaudio_allocator.c

diff --git a/configure.ac b/configure.ac
index 1b425d22a2..18e07909a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,6 +43,7 @@ AC_ARG_WITH(cups,      AS_HELP_STRING([--without-cups],[do not use CUPS]))
 AC_ARG_WITH(curses,    AS_HELP_STRING([--without-curses],[do not use (n)curses]),
             [if test "x$withval" = "xno"; then ac_cv_header_ncurses_h=no; ac_cv_header_curses_h=no; fi])
 AC_ARG_WITH(dbus,      AS_HELP_STRING([--without-dbus],[do not use DBus (dynamic device support)]))
+AC_ARG_WITH(faudio,    AS_HELP_STRING([--without-faudio],[do not use FAudio (XAudio2 support)]))
 AC_ARG_WITH(float-abi, AS_HELP_STRING([--with-float-abi=abi],[specify the ABI (soft|softfp|hard) for ARM platforms]))
 AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig]))
 AC_ARG_WITH(freetype,  AS_HELP_STRING([--without-freetype],[do not use the FreeType library]))
@@ -1634,6 +1635,16 @@ fi
 WINE_NOTICE_WITH(sdl,[test "x$ac_cv_lib_soname_SDL2" = "x"],
                  [libSDL2 ${notice_platform}development files not found, SDL2 won't be supported.])
 
+dnl **** Check for FAudio ****
+if test "x$with_faudio" != "xno"
+then
+    WINE_PACKAGE_FLAGS(FAUDIO,[faudio],[-lFAudio],,,
+        [AC_CHECK_HEADERS([FAudio.h],
+            [WINE_CHECK_SONAME(FAudio,FAudioCreate,,,[$FAUDIO_LIBS],[[libFAudio*]])])])
+fi
+WINE_NOTICE_WITH(faudio,[test "x$ac_cv_lib_soname_FAudio" = "x"],
+                 [libFAudio ${notice_platform}development files not found, XAudio2 won't be supported.])
+
 dnl **** Check for capi4linux ****
 if test "x$with_capi" != "xno"
 then
@@ -1798,19 +1809,8 @@ WINE_NOTICE_WITH(openal,[test "x$ac_cv_lib_openal" != xyes],
                  [libopenal ${notice_platform}development files not found (or too old), OpenAL won't be supported.],
                  [enable_openal32])
 
-dnl **** Check for openal-soft ****
-if test "x$ac_cv_lib_openal" = xyes
-then
-    AC_CACHE_CHECK([for openal-soft], ac_cv_have_openalsoft,
-        AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-            [[#include <AL/al.h>
-#include <AL/alc.h>
-#include <AL/alext.h>
-LPALCRENDERSAMPLESSOFT x;]])],[ac_cv_have_openalsoft=yes],[ac_cv_have_openalsoft=no]))
-fi
-if test "x$ac_cv_have_openalsoft" != xyes
+if test "x$ac_cv_lib_soname_FAudio" = "x"
 then
-    WINE_NOTICE([openal-soft ${notice_platform}development files not found (or too old), XAudio2 won't be supported.])
     enable_x3daudio1_0=${enable_x3daudio1_0:-no}
     enable_x3daudio1_1=${enable_x3daudio1_1:-no}
     enable_x3daudio1_2=${enable_x3daudio1_2:-no}
diff --git a/dlls/x3daudio1_0/Makefile.in b/dlls/x3daudio1_0/Makefile.in
index 9b4ce2189c..d2305be6f1 100644
--- a/dlls/x3daudio1_0/Makefile.in
+++ b/dlls/x3daudio1_0/Makefile.in
@@ -1,6 +1,8 @@
 EXTRADEFS = -DX3DAUDIO1_VER=0 -DXAUDIO2_VER=0
 MODULE    = x3daudio1_0.dll
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
 	x3daudio.c
diff --git a/dlls/x3daudio1_1/Makefile.in b/dlls/x3daudio1_1/Makefile.in
index d866dc3ddb..efe8d74539 100644
--- a/dlls/x3daudio1_1/Makefile.in
+++ b/dlls/x3daudio1_1/Makefile.in
@@ -1,6 +1,8 @@
 EXTRADEFS = -DX3DAUDIO1_VER=1 -DXAUDIO2_VER=1
 MODULE    = x3daudio1_1.dll
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
 	x3daudio.c
diff --git a/dlls/x3daudio1_2/Makefile.in b/dlls/x3daudio1_2/Makefile.in
index d5de11b258..3b52e063fc 100644
--- a/dlls/x3daudio1_2/Makefile.in
+++ b/dlls/x3daudio1_2/Makefile.in
@@ -1,6 +1,8 @@
 EXTRADEFS = -DX3DAUDIO1_VER=2 -DXAUDIO2_VER=2
 MODULE    = x3daudio1_2.dll
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
 	x3daudio.c
diff --git a/dlls/x3daudio1_3/Makefile.in b/dlls/x3daudio1_3/Makefile.in
index cfd2c6c6c6..9afd1e6431 100644
--- a/dlls/x3daudio1_3/Makefile.in
+++ b/dlls/x3daudio1_3/Makefile.in
@@ -1,6 +1,8 @@
 EXTRADEFS = -DX3DAUDIO1_VER=3 -DXAUDIO2_VER=3
 MODULE    = x3daudio1_3.dll
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
 	x3daudio.c
diff --git a/dlls/x3daudio1_4/Makefile.in b/dlls/x3daudio1_4/Makefile.in
index bd0eac7fc6..e481567cce 100644
--- a/dlls/x3daudio1_4/Makefile.in
+++ b/dlls/x3daudio1_4/Makefile.in
@@ -1,6 +1,8 @@
 EXTRADEFS = -DX3DAUDIO1_VER=4 -DXAUDIO2_VER=4
 MODULE    = x3daudio1_4.dll
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
 	x3daudio.c
diff --git a/dlls/x3daudio1_5/Makefile.in b/dlls/x3daudio1_5/Makefile.in
index dac67aef76..0a97959e7e 100644
--- a/dlls/x3daudio1_5/Makefile.in
+++ b/dlls/x3daudio1_5/Makefile.in
@@ -1,6 +1,8 @@
 EXTRADEFS = -DX3DAUDIO1_VER=5 -DXAUDIO2_VER=5
 MODULE    = x3daudio1_5.dll
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
 	x3daudio.c
diff --git a/dlls/x3daudio1_6/Makefile.in b/dlls/x3daudio1_6/Makefile.in
index 177fb8d34d..c88374a381 100644
--- a/dlls/x3daudio1_6/Makefile.in
+++ b/dlls/x3daudio1_6/Makefile.in
@@ -1,6 +1,8 @@
 EXTRADEFS = -DX3DAUDIO1_VER=6 -DXAUDIO2_VER=6
 MODULE    = x3daudio1_6.dll
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
 	x3daudio.c
diff --git a/dlls/x3daudio1_7/Makefile.in b/dlls/x3daudio1_7/Makefile.in
index 019588dce0..267a93fd6d 100644
--- a/dlls/x3daudio1_7/Makefile.in
+++ b/dlls/x3daudio1_7/Makefile.in
@@ -1,6 +1,8 @@
 EXTRADEFS = -DX3DAUDIO1_VER=7 -DXAUDIO2_VER=7
 MODULE    = x3daudio1_7.dll
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
 	x3daudio.c
diff --git a/dlls/xapofx1_1/Makefile.in b/dlls/xapofx1_1/Makefile.in
index f69ff86bd9..072ec3f5fb 100644
--- a/dlls/xapofx1_1/Makefile.in
+++ b/dlls/xapofx1_1/Makefile.in
@@ -2,8 +2,12 @@ EXTRADEFS = -DXAPOFX1_VER=1 -DXAUDIO2_VER=2
 MODULE    = xapofx1_1.dll
 IMPORTS   = ole32
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
-	xapofx.c
+	xaudio_allocator.c \
+	xapofx.c \
+	xapo.c
 
 RC_SRCS = version.rc
diff --git a/dlls/xapofx1_2/Makefile.in b/dlls/xapofx1_2/Makefile.in
index d56a2be4bb..f018a7e931 100644
--- a/dlls/xapofx1_2/Makefile.in
+++ b/dlls/xapofx1_2/Makefile.in
@@ -2,6 +2,10 @@ EXTRADEFS = -DXAPOFX1_VER=2 -DXAUDIO2_VER=3
 MODULE    = xapofx1_2.dll
 IMPORTS   = ole32
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
-	xapofx.c
+	xaudio_allocator.c \
+	xapofx.c \
+	xapo.c
diff --git a/dlls/xapofx1_3/Makefile.in b/dlls/xapofx1_3/Makefile.in
index 1139520b73..e2ae458257 100644
--- a/dlls/xapofx1_3/Makefile.in
+++ b/dlls/xapofx1_3/Makefile.in
@@ -2,8 +2,12 @@ EXTRADEFS = -DXAPOFX1_VER=3 -DXAUDIO2_VER=4
 MODULE    = xapofx1_3.dll
 IMPORTS   = ole32
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
-	xapofx.c
+	xaudio_allocator.c \
+	xapofx.c \
+	xapo.c
 
 RC_SRCS = version.rc
diff --git a/dlls/xapofx1_4/Makefile.in b/dlls/xapofx1_4/Makefile.in
index b49e4643af..0c6695f191 100644
--- a/dlls/xapofx1_4/Makefile.in
+++ b/dlls/xapofx1_4/Makefile.in
@@ -2,6 +2,10 @@ EXTRADEFS = -DXAPOFX1_VER=4 -DXAUDIO2_VER=6
 MODULE    = xapofx1_4.dll
 IMPORTS   = ole32
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
-	xapofx.c
+	xaudio_allocator.c \
+	xapofx.c \
+	xapo.c
diff --git a/dlls/xapofx1_5/Makefile.in b/dlls/xapofx1_5/Makefile.in
index 5055a16fd5..9bb7d704e5 100644
--- a/dlls/xapofx1_5/Makefile.in
+++ b/dlls/xapofx1_5/Makefile.in
@@ -2,6 +2,10 @@ EXTRADEFS = -DXAPOFX1_VER=5 -DXAUDIO2_VER=7
 MODULE    = xapofx1_5.dll
 IMPORTS   = ole32
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
-	xapofx.c
+	xaudio_allocator.c \
+	xapofx.c \
+	xapo.c
diff --git a/dlls/xaudio2_0/Makefile.in b/dlls/xaudio2_0/Makefile.in
index cf15c7bf02..3aa083b88f 100644
--- a/dlls/xaudio2_0/Makefile.in
+++ b/dlls/xaudio2_0/Makefile.in
@@ -1,12 +1,14 @@
 EXTRADEFS = -DXAUDIO2_VER=0
 MODULE    = xaudio2_0.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	xapofx.c \
-	xaudio_dll.c
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_1/Makefile.in b/dlls/xaudio2_1/Makefile.in
index 32a5a62a2a..87c6bfce85 100644
--- a/dlls/xaudio2_1/Makefile.in
+++ b/dlls/xaudio2_1/Makefile.in
@@ -1,12 +1,14 @@
 EXTRADEFS = -DXAUDIO2_VER=1
 MODULE    = xaudio2_1.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	xapofx.c \
-	xaudio_dll.c
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_2/Makefile.in b/dlls/xaudio2_2/Makefile.in
index f20de2d5f4..44eaf14991 100644
--- a/dlls/xaudio2_2/Makefile.in
+++ b/dlls/xaudio2_2/Makefile.in
@@ -1,12 +1,14 @@
 EXTRADEFS = -DXAUDIO2_VER=2
 MODULE    = xaudio2_2.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	xapofx.c \
-	xaudio_dll.c
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_3/Makefile.in b/dlls/xaudio2_3/Makefile.in
index ca749f247b..8b71f10fec 100644
--- a/dlls/xaudio2_3/Makefile.in
+++ b/dlls/xaudio2_3/Makefile.in
@@ -1,12 +1,14 @@
 EXTRADEFS = -DXAUDIO2_VER=3
 MODULE    = xaudio2_3.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	xapofx.c \
-	xaudio_dll.c
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_4/Makefile.in b/dlls/xaudio2_4/Makefile.in
index 0b74f68fdc..2c43df199d 100644
--- a/dlls/xaudio2_4/Makefile.in
+++ b/dlls/xaudio2_4/Makefile.in
@@ -1,12 +1,14 @@
 EXTRADEFS = -DXAUDIO2_VER=4
 MODULE    = xaudio2_4.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	xapofx.c \
-	xaudio_dll.c
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_5/Makefile.in b/dlls/xaudio2_5/Makefile.in
index 09356c94ac..0e5b825a46 100644
--- a/dlls/xaudio2_5/Makefile.in
+++ b/dlls/xaudio2_5/Makefile.in
@@ -1,12 +1,14 @@
 EXTRADEFS = -DXAUDIO2_VER=5
 MODULE    = xaudio2_5.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	xapofx.c \
-	xaudio_dll.c
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_6/Makefile.in b/dlls/xaudio2_6/Makefile.in
index e0ef588158..69d4574ca4 100644
--- a/dlls/xaudio2_6/Makefile.in
+++ b/dlls/xaudio2_6/Makefile.in
@@ -1,12 +1,14 @@
 EXTRADEFS = -DXAUDIO2_VER=6
 MODULE    = xaudio2_6.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	xapofx.c \
-	xaudio_dll.c
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_7/Makefile.in b/dlls/xaudio2_7/Makefile.in
index 2f2e232007..d7a1a35839 100644
--- a/dlls/xaudio2_7/Makefile.in
+++ b/dlls/xaudio2_7/Makefile.in
@@ -1,12 +1,13 @@
 EXTRADEFS = -DXAUDIO2_VER=7
 MODULE    = xaudio2_7.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	x3daudio.c \
-	xapofx.c \
-	xaudio_dll.c
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_7/compat.c b/dlls/xaudio2_7/compat.c
index 4980e25f2f..318f668589 100644
--- a/dlls/xaudio2_7/compat.c
+++ b/dlls/xaudio2_7/compat.c
@@ -124,15 +124,15 @@ static XAUDIO2_SEND_DESCRIPTOR *convert_send_descriptors23(const XAUDIO23_VOICE_
 
 /* BEGIN IXAudio2SourceVoice */
 #if XAUDIO2_VER == 0
-static XA2SourceImpl *impl_from_IXAudio20SourceVoice(IXAudio20SourceVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio20SourceVoice(IXAudio20SourceVoice *iface)
 {
-    return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio20SourceVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio20SourceVoice_iface);
 }
 
 static void WINAPI XA20SRC_GetVoiceDetails(IXAudio20SourceVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2SourceVoice_GetVoiceDetails(&This->IXAudio2SourceVoice_iface, &details);
@@ -145,7 +145,7 @@ static void WINAPI XA20SRC_GetVoiceDetails(IXAudio20SourceVoice *iface,
 static HRESULT WINAPI XA20SRC_SetOutputVoices(IXAudio20SourceVoice *iface,
         const XAUDIO23_VOICE_SENDS *pSendList)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     XAUDIO2_VOICE_SENDS sends, *psends = NULL;
     HRESULT hr;
 
@@ -168,14 +168,14 @@ static HRESULT WINAPI XA20SRC_SetOutputVoices(IXAudio20SourceVoice *iface,
 static HRESULT WINAPI XA20SRC_SetEffectChain(IXAudio20SourceVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_SetEffectChain(&This->IXAudio2SourceVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA20SRC_EnableEffect(IXAudio20SourceVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_EnableEffect(&This->IXAudio2SourceVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -183,7 +183,7 @@ static HRESULT WINAPI XA20SRC_EnableEffect(IXAudio20SourceVoice *iface,
 static HRESULT WINAPI XA20SRC_DisableEffect(IXAudio20SourceVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_DisableEffect(&This->IXAudio2SourceVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -191,7 +191,7 @@ static HRESULT WINAPI XA20SRC_DisableEffect(IXAudio20SourceVoice *iface,
 static void WINAPI XA20SRC_GetEffectState(IXAudio20SourceVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_GetEffectState(&This->IXAudio2SourceVoice_iface,
             EffectIndex, pEnabled);
 }
@@ -200,7 +200,7 @@ static HRESULT WINAPI XA20SRC_SetEffectParameters(IXAudio20SourceVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_SetEffectParameters(&This->IXAudio2SourceVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -208,7 +208,7 @@ static HRESULT WINAPI XA20SRC_SetEffectParameters(IXAudio20SourceVoice *iface,
 static HRESULT WINAPI XA20SRC_GetEffectParameters(IXAudio20SourceVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_GetEffectParameters(&This->IXAudio2SourceVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -216,7 +216,7 @@ static HRESULT WINAPI XA20SRC_GetEffectParameters(IXAudio20SourceVoice *iface,
 static HRESULT WINAPI XA20SRC_SetFilterParameters(IXAudio20SourceVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_SetFilterParameters(&This->IXAudio2SourceVoice_iface,
             pParameters, OperationSet);
 }
@@ -224,14 +224,14 @@ static HRESULT WINAPI XA20SRC_SetFilterParameters(IXAudio20SourceVoice *iface,
 static void WINAPI XA20SRC_GetFilterParameters(IXAudio20SourceVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_GetFilterParameters(&This->IXAudio2SourceVoice_iface, pParameters);
 }
 
 static HRESULT WINAPI XA20SRC_SetVolume(IXAudio20SourceVoice *iface,
         float Volume, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_SetVolume(&This->IXAudio2SourceVoice_iface,
             Volume, OperationSet);
 }
@@ -239,14 +239,14 @@ static HRESULT WINAPI XA20SRC_SetVolume(IXAudio20SourceVoice *iface,
 static void WINAPI XA20SRC_GetVolume(IXAudio20SourceVoice *iface,
         float *pVolume)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_GetVolume(&This->IXAudio2SourceVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA20SRC_SetChannelVolumes(IXAudio20SourceVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_SetChannelVolumes(&This->IXAudio2SourceVoice_iface,
             Channels, pVolumes, OperationSet);
 }
@@ -254,7 +254,7 @@ static HRESULT WINAPI XA20SRC_SetChannelVolumes(IXAudio20SourceVoice *iface,
 static void WINAPI XA20SRC_GetChannelVolumes(IXAudio20SourceVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_GetChannelVolumes(&This->IXAudio2SourceVoice_iface,
             Channels, pVolumes);
 }
@@ -264,7 +264,7 @@ static HRESULT WINAPI XA20SRC_SetOutputMatrix(IXAudio20SourceVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_SetOutputMatrix(&This->IXAudio2SourceVoice_iface,
             pDestinationVoice, SourceChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -274,7 +274,7 @@ static HRESULT WINAPI XA20SRC_GetOutputMatrix(IXAudio20SourceVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     IXAudio2SourceVoice_GetOutputMatrix(&This->IXAudio2SourceVoice_iface,
             pDestinationVoice, SourceChannels, DestinationChannels,
             pLevelMatrix);
@@ -283,62 +283,62 @@ static HRESULT WINAPI XA20SRC_GetOutputMatrix(IXAudio20SourceVoice *iface,
 
 static void WINAPI XA20SRC_DestroyVoice(IXAudio20SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_DestroyVoice(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA20SRC_Start(IXAudio20SourceVoice *iface, UINT32 Flags,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_Start(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
 }
 
 static HRESULT WINAPI XA20SRC_Stop(IXAudio20SourceVoice *iface, UINT32 Flags,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_Stop(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
 }
 
 static HRESULT WINAPI XA20SRC_SubmitSourceBuffer(IXAudio20SourceVoice *iface,
         const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_SubmitSourceBuffer(&This->IXAudio2SourceVoice_iface,
             pBuffer, pBufferWMA);
 }
 
 static HRESULT WINAPI XA20SRC_FlushSourceBuffers(IXAudio20SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_FlushSourceBuffers(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA20SRC_Discontinuity(IXAudio20SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_Discontinuity(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA20SRC_ExitLoop(IXAudio20SourceVoice *iface,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_ExitLoop(&This->IXAudio2SourceVoice_iface, OperationSet);
 }
 
 static void WINAPI XA20SRC_GetState(IXAudio20SourceVoice *iface,
         XAUDIO2_VOICE_STATE *pVoiceState)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_GetState(&This->IXAudio2SourceVoice_iface, pVoiceState, 0);
 }
 
 static HRESULT WINAPI XA20SRC_SetFrequencyRatio(IXAudio20SourceVoice *iface,
         float Ratio, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_SetFrequencyRatio(&This->IXAudio2SourceVoice_iface,
             Ratio, OperationSet);
 }
@@ -346,7 +346,7 @@ static HRESULT WINAPI XA20SRC_SetFrequencyRatio(IXAudio20SourceVoice *iface,
 static void WINAPI XA20SRC_GetFrequencyRatio(IXAudio20SourceVoice *iface,
         float *pRatio)
 {
-    XA2SourceImpl *This = impl_from_IXAudio20SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SourceVoice(iface);
     return IXAudio2SourceVoice_GetFrequencyRatio(&This->IXAudio2SourceVoice_iface, pRatio);
 }
 
@@ -381,15 +381,15 @@ const IXAudio20SourceVoiceVtbl XAudio20SourceVoice_Vtbl = {
 
 #elif XAUDIO2_VER <= 3
 
-static XA2SourceImpl *impl_from_IXAudio23SourceVoice(IXAudio23SourceVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio23SourceVoice(IXAudio23SourceVoice *iface)
 {
-    return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio23SourceVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio23SourceVoice_iface);
 }
 
 static void WINAPI XA23SRC_GetVoiceDetails(IXAudio23SourceVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2SourceVoice_GetVoiceDetails(&This->IXAudio2SourceVoice_iface, &details);
@@ -402,7 +402,7 @@ static void WINAPI XA23SRC_GetVoiceDetails(IXAudio23SourceVoice *iface,
 static HRESULT WINAPI XA23SRC_SetOutputVoices(IXAudio23SourceVoice *iface,
         const XAUDIO23_VOICE_SENDS *pSendList)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     XAUDIO2_VOICE_SENDS sends, *psends = NULL;
     HRESULT hr;
 
@@ -425,14 +425,14 @@ static HRESULT WINAPI XA23SRC_SetOutputVoices(IXAudio23SourceVoice *iface,
 static HRESULT WINAPI XA23SRC_SetEffectChain(IXAudio23SourceVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_SetEffectChain(&This->IXAudio2SourceVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA23SRC_EnableEffect(IXAudio23SourceVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_EnableEffect(&This->IXAudio2SourceVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -440,7 +440,7 @@ static HRESULT WINAPI XA23SRC_EnableEffect(IXAudio23SourceVoice *iface,
 static HRESULT WINAPI XA23SRC_DisableEffect(IXAudio23SourceVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_DisableEffect(&This->IXAudio2SourceVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -448,7 +448,7 @@ static HRESULT WINAPI XA23SRC_DisableEffect(IXAudio23SourceVoice *iface,
 static void WINAPI XA23SRC_GetEffectState(IXAudio23SourceVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_GetEffectState(&This->IXAudio2SourceVoice_iface,
             EffectIndex, pEnabled);
 }
@@ -457,7 +457,7 @@ static HRESULT WINAPI XA23SRC_SetEffectParameters(IXAudio23SourceVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_SetEffectParameters(&This->IXAudio2SourceVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -465,7 +465,7 @@ static HRESULT WINAPI XA23SRC_SetEffectParameters(IXAudio23SourceVoice *iface,
 static HRESULT WINAPI XA23SRC_GetEffectParameters(IXAudio23SourceVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_GetEffectParameters(&This->IXAudio2SourceVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -473,7 +473,7 @@ static HRESULT WINAPI XA23SRC_GetEffectParameters(IXAudio23SourceVoice *iface,
 static HRESULT WINAPI XA23SRC_SetFilterParameters(IXAudio23SourceVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_SetFilterParameters(&This->IXAudio2SourceVoice_iface,
             pParameters, OperationSet);
 }
@@ -481,14 +481,14 @@ static HRESULT WINAPI XA23SRC_SetFilterParameters(IXAudio23SourceVoice *iface,
 static void WINAPI XA23SRC_GetFilterParameters(IXAudio23SourceVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_GetFilterParameters(&This->IXAudio2SourceVoice_iface, pParameters);
 }
 
 static HRESULT WINAPI XA23SRC_SetVolume(IXAudio23SourceVoice *iface,
         float Volume, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_SetVolume(&This->IXAudio2SourceVoice_iface,
             Volume, OperationSet);
 }
@@ -496,14 +496,14 @@ static HRESULT WINAPI XA23SRC_SetVolume(IXAudio23SourceVoice *iface,
 static void WINAPI XA23SRC_GetVolume(IXAudio23SourceVoice *iface,
         float *pVolume)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_GetVolume(&This->IXAudio2SourceVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA23SRC_SetChannelVolumes(IXAudio23SourceVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_SetChannelVolumes(&This->IXAudio2SourceVoice_iface,
             Channels, pVolumes, OperationSet);
 }
@@ -511,7 +511,7 @@ static HRESULT WINAPI XA23SRC_SetChannelVolumes(IXAudio23SourceVoice *iface,
 static void WINAPI XA23SRC_GetChannelVolumes(IXAudio23SourceVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_GetChannelVolumes(&This->IXAudio2SourceVoice_iface,
             Channels, pVolumes);
 }
@@ -521,7 +521,7 @@ static HRESULT WINAPI XA23SRC_SetOutputMatrix(IXAudio23SourceVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_SetOutputMatrix(&This->IXAudio2SourceVoice_iface,
             pDestinationVoice, SourceChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -531,7 +531,7 @@ static void WINAPI XA23SRC_GetOutputMatrix(IXAudio23SourceVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_GetOutputMatrix(&This->IXAudio2SourceVoice_iface,
             pDestinationVoice, SourceChannels, DestinationChannels,
             pLevelMatrix);
@@ -539,62 +539,62 @@ static void WINAPI XA23SRC_GetOutputMatrix(IXAudio23SourceVoice *iface,
 
 static void WINAPI XA23SRC_DestroyVoice(IXAudio23SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_DestroyVoice(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA23SRC_Start(IXAudio23SourceVoice *iface, UINT32 Flags,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_Start(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
 }
 
 static HRESULT WINAPI XA23SRC_Stop(IXAudio23SourceVoice *iface, UINT32 Flags,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_Stop(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
 }
 
 static HRESULT WINAPI XA23SRC_SubmitSourceBuffer(IXAudio23SourceVoice *iface,
         const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_SubmitSourceBuffer(&This->IXAudio2SourceVoice_iface,
             pBuffer, pBufferWMA);
 }
 
 static HRESULT WINAPI XA23SRC_FlushSourceBuffers(IXAudio23SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_FlushSourceBuffers(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA23SRC_Discontinuity(IXAudio23SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_Discontinuity(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA23SRC_ExitLoop(IXAudio23SourceVoice *iface,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_ExitLoop(&This->IXAudio2SourceVoice_iface, OperationSet);
 }
 
 static void WINAPI XA23SRC_GetState(IXAudio23SourceVoice *iface,
         XAUDIO2_VOICE_STATE *pVoiceState)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_GetState(&This->IXAudio2SourceVoice_iface, pVoiceState, 0);
 }
 
 static HRESULT WINAPI XA23SRC_SetFrequencyRatio(IXAudio23SourceVoice *iface,
         float Ratio, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_SetFrequencyRatio(&This->IXAudio2SourceVoice_iface,
             Ratio, OperationSet);
 }
@@ -602,7 +602,7 @@ static HRESULT WINAPI XA23SRC_SetFrequencyRatio(IXAudio23SourceVoice *iface,
 static void WINAPI XA23SRC_GetFrequencyRatio(IXAudio23SourceVoice *iface,
         float *pRatio)
 {
-    XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SourceVoice(iface);
     return IXAudio2SourceVoice_GetFrequencyRatio(&This->IXAudio2SourceVoice_iface, pRatio);
 }
 
@@ -637,15 +637,15 @@ const IXAudio23SourceVoiceVtbl XAudio23SourceVoice_Vtbl = {
 
 #elif XAUDIO2_VER <= 7
 
-static XA2SourceImpl *impl_from_IXAudio27SourceVoice(IXAudio27SourceVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio27SourceVoice(IXAudio27SourceVoice *iface)
 {
-    return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio27SourceVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio27SourceVoice_iface);
 }
 
 static void WINAPI XA27SRC_GetVoiceDetails(IXAudio27SourceVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2SourceVoice_GetVoiceDetails(&This->IXAudio2SourceVoice_iface, &details);
@@ -658,35 +658,35 @@ static void WINAPI XA27SRC_GetVoiceDetails(IXAudio27SourceVoice *iface,
 static HRESULT WINAPI XA27SRC_SetOutputVoices(IXAudio27SourceVoice *iface,
         const XAUDIO2_VOICE_SENDS *pSendList)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetOutputVoices(&This->IXAudio2SourceVoice_iface, pSendList);
 }
 
 static HRESULT WINAPI XA27SRC_SetEffectChain(IXAudio27SourceVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetEffectChain(&This->IXAudio2SourceVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA27SRC_EnableEffect(IXAudio27SourceVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_EnableEffect(&This->IXAudio2SourceVoice_iface, EffectIndex, OperationSet);
 }
 
 static HRESULT WINAPI XA27SRC_DisableEffect(IXAudio27SourceVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_DisableEffect(&This->IXAudio2SourceVoice_iface, EffectIndex, OperationSet);
 }
 
 static void WINAPI XA27SRC_GetEffectState(IXAudio27SourceVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     IXAudio2SourceVoice_GetEffectState(&This->IXAudio2SourceVoice_iface, EffectIndex, pEnabled);
 }
 
@@ -694,7 +694,7 @@ static HRESULT WINAPI XA27SRC_SetEffectParameters(IXAudio27SourceVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetEffectParameters(&This->IXAudio2SourceVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -702,7 +702,7 @@ static HRESULT WINAPI XA27SRC_SetEffectParameters(IXAudio27SourceVoice *iface,
 static HRESULT WINAPI XA27SRC_GetEffectParameters(IXAudio27SourceVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_GetEffectParameters(&This->IXAudio2SourceVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -710,7 +710,7 @@ static HRESULT WINAPI XA27SRC_GetEffectParameters(IXAudio27SourceVoice *iface,
 static HRESULT WINAPI XA27SRC_SetFilterParameters(IXAudio27SourceVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetFilterParameters(&This->IXAudio2SourceVoice_iface,
             pParameters, OperationSet);
 }
@@ -718,7 +718,7 @@ static HRESULT WINAPI XA27SRC_SetFilterParameters(IXAudio27SourceVoice *iface,
 static void WINAPI XA27SRC_GetFilterParameters(IXAudio27SourceVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     IXAudio2SourceVoice_GetFilterParameters(&This->IXAudio2SourceVoice_iface, pParameters);
 }
 
@@ -726,7 +726,7 @@ static HRESULT WINAPI XA27SRC_SetOutputFilterParameters(IXAudio27SourceVoice *if
         IXAudio2Voice *pDestinationVoice,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetOutputFilterParameters(&This->IXAudio2SourceVoice_iface,
             pDestinationVoice, pParameters, OperationSet);
 }
@@ -735,7 +735,7 @@ static void WINAPI XA27SRC_GetOutputFilterParameters(IXAudio27SourceVoice *iface
         IXAudio2Voice *pDestinationVoice,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     IXAudio2SourceVoice_GetOutputFilterParameters(&This->IXAudio2SourceVoice_iface,
             pDestinationVoice, pParameters);
 }
@@ -743,21 +743,21 @@ static void WINAPI XA27SRC_GetOutputFilterParameters(IXAudio27SourceVoice *iface
 static HRESULT WINAPI XA27SRC_SetVolume(IXAudio27SourceVoice *iface, float Volume,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetVolume(&This->IXAudio2SourceVoice_iface, Volume,
             OperationSet);
 }
 
 static void WINAPI XA27SRC_GetVolume(IXAudio27SourceVoice *iface, float *pVolume)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     IXAudio2SourceVoice_GetVolume(&This->IXAudio2SourceVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA27SRC_SetChannelVolumes(IXAudio27SourceVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetChannelVolumes(&This->IXAudio2SourceVoice_iface, Channels,
             pVolumes, OperationSet);
 }
@@ -765,7 +765,7 @@ static HRESULT WINAPI XA27SRC_SetChannelVolumes(IXAudio27SourceVoice *iface,
 static void WINAPI XA27SRC_GetChannelVolumes(IXAudio27SourceVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     IXAudio2SourceVoice_GetChannelVolumes(&This->IXAudio2SourceVoice_iface, Channels,
             pVolumes);
 }
@@ -775,7 +775,7 @@ static HRESULT WINAPI XA27SRC_SetOutputMatrix(IXAudio27SourceVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetOutputMatrix(&This->IXAudio2SourceVoice_iface,
             pDestinationVoice, SourceChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -785,74 +785,74 @@ static void WINAPI XA27SRC_GetOutputMatrix(IXAudio27SourceVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     IXAudio2SourceVoice_GetOutputMatrix(&This->IXAudio2SourceVoice_iface, pDestinationVoice,
             SourceChannels, DestinationChannels, pLevelMatrix);
 }
 
 static void WINAPI XA27SRC_DestroyVoice(IXAudio27SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     IXAudio2SourceVoice_DestroyVoice(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA27SRC_Start(IXAudio27SourceVoice *iface, UINT32 Flags,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_Start(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
 }
 
 static HRESULT WINAPI XA27SRC_Stop(IXAudio27SourceVoice *iface, UINT32 Flags,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_Stop(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
 }
 
 static HRESULT WINAPI XA27SRC_SubmitSourceBuffer(IXAudio27SourceVoice *iface,
         const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SubmitSourceBuffer(&This->IXAudio2SourceVoice_iface, pBuffer,
             pBufferWMA);
 }
 
 static HRESULT WINAPI XA27SRC_FlushSourceBuffers(IXAudio27SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_FlushSourceBuffers(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA27SRC_Discontinuity(IXAudio27SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_Discontinuity(&This->IXAudio2SourceVoice_iface);
 }
 
 static HRESULT WINAPI XA27SRC_ExitLoop(IXAudio27SourceVoice *iface, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_ExitLoop(&This->IXAudio2SourceVoice_iface, OperationSet);
 }
 
 static void WINAPI XA27SRC_GetState(IXAudio27SourceVoice *iface,
         XAUDIO2_VOICE_STATE *pVoiceState)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_GetState(&This->IXAudio2SourceVoice_iface, pVoiceState, 0);
 }
 
 static HRESULT WINAPI XA27SRC_SetFrequencyRatio(IXAudio27SourceVoice *iface,
         float Ratio, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetFrequencyRatio(&This->IXAudio2SourceVoice_iface, Ratio, OperationSet);
 }
 
 static void WINAPI XA27SRC_GetFrequencyRatio(IXAudio27SourceVoice *iface, float *pRatio)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_GetFrequencyRatio(&This->IXAudio2SourceVoice_iface, pRatio);
 }
 
@@ -860,7 +860,7 @@ static HRESULT WINAPI XA27SRC_SetSourceSampleRate(
     IXAudio27SourceVoice *iface,
     UINT32 NewSourceSampleRate)
 {
-    XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SourceVoice(iface);
     return IXAudio2SourceVoice_SetSourceSampleRate(&This->IXAudio2SourceVoice_iface, NewSourceSampleRate);
 }
 
@@ -901,15 +901,15 @@ const IXAudio27SourceVoiceVtbl XAudio27SourceVoice_Vtbl = {
 
 /* BEGIN IXAudio2SubmixVoice */
 #if XAUDIO2_VER == 0
-static XA2SubmixImpl *impl_from_IXAudio20SubmixVoice(IXAudio20SubmixVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio20SubmixVoice(IXAudio20SubmixVoice *iface)
 {
-    return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio20SubmixVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio20SubmixVoice_iface);
 }
 
 static void WINAPI XA20SUB_GetVoiceDetails(IXAudio20SubmixVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2SubmixVoice_GetVoiceDetails(&This->IXAudio2SubmixVoice_iface, &details);
@@ -922,7 +922,7 @@ static void WINAPI XA20SUB_GetVoiceDetails(IXAudio20SubmixVoice *iface,
 static HRESULT WINAPI XA20SUB_SetOutputVoices(IXAudio20SubmixVoice *iface,
         const XAUDIO23_VOICE_SENDS *pSendList)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     XAUDIO2_VOICE_SENDS sends, *psends;
     HRESULT hr;
 
@@ -945,14 +945,14 @@ static HRESULT WINAPI XA20SUB_SetOutputVoices(IXAudio20SubmixVoice *iface,
 static HRESULT WINAPI XA20SUB_SetEffectChain(IXAudio20SubmixVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetEffectChain(&This->IXAudio2SubmixVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA20SUB_EnableEffect(IXAudio20SubmixVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_EnableEffect(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -960,7 +960,7 @@ static HRESULT WINAPI XA20SUB_EnableEffect(IXAudio20SubmixVoice *iface,
 static HRESULT WINAPI XA20SUB_DisableEffect(IXAudio20SubmixVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_DisableEffect(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -968,7 +968,7 @@ static HRESULT WINAPI XA20SUB_DisableEffect(IXAudio20SubmixVoice *iface,
 static void WINAPI XA20SUB_GetEffectState(IXAudio20SubmixVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetEffectState(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pEnabled);
 }
@@ -977,7 +977,7 @@ static HRESULT WINAPI XA20SUB_SetEffectParameters(IXAudio20SubmixVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetEffectParameters(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -985,7 +985,7 @@ static HRESULT WINAPI XA20SUB_SetEffectParameters(IXAudio20SubmixVoice *iface,
 static HRESULT WINAPI XA20SUB_GetEffectParameters(IXAudio20SubmixVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetEffectParameters(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -993,7 +993,7 @@ static HRESULT WINAPI XA20SUB_GetEffectParameters(IXAudio20SubmixVoice *iface,
 static HRESULT WINAPI XA20SUB_SetFilterParameters(IXAudio20SubmixVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetFilterParameters(&This->IXAudio2SubmixVoice_iface,
             pParameters, OperationSet);
 }
@@ -1001,14 +1001,14 @@ static HRESULT WINAPI XA20SUB_SetFilterParameters(IXAudio20SubmixVoice *iface,
 static void WINAPI XA20SUB_GetFilterParameters(IXAudio20SubmixVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetFilterParameters(&This->IXAudio2SubmixVoice_iface, pParameters);
 }
 
 static HRESULT WINAPI XA20SUB_SetVolume(IXAudio20SubmixVoice *iface,
         float Volume, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetVolume(&This->IXAudio2SubmixVoice_iface,
             Volume, OperationSet);
 }
@@ -1016,14 +1016,14 @@ static HRESULT WINAPI XA20SUB_SetVolume(IXAudio20SubmixVoice *iface,
 static void WINAPI XA20SUB_GetVolume(IXAudio20SubmixVoice *iface,
         float *pVolume)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetVolume(&This->IXAudio2SubmixVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA20SUB_SetChannelVolumes(IXAudio20SubmixVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetChannelVolumes(&This->IXAudio2SubmixVoice_iface,
             Channels, pVolumes, OperationSet);
 }
@@ -1031,7 +1031,7 @@ static HRESULT WINAPI XA20SUB_SetChannelVolumes(IXAudio20SubmixVoice *iface,
 static void WINAPI XA20SUB_GetChannelVolumes(IXAudio20SubmixVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetChannelVolumes(&This->IXAudio2SubmixVoice_iface,
             Channels, pVolumes);
 }
@@ -1041,7 +1041,7 @@ static HRESULT WINAPI XA20SUB_SetOutputMatrix(IXAudio20SubmixVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetOutputMatrix(&This->IXAudio2SubmixVoice_iface,
             pDestinationVoice, SubmixChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -1051,7 +1051,7 @@ static HRESULT WINAPI XA20SUB_GetOutputMatrix(IXAudio20SubmixVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 SubmixChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     IXAudio2SubmixVoice_GetOutputMatrix(&This->IXAudio2SubmixVoice_iface,
             pDestinationVoice, SubmixChannels, DestinationChannels,
             pLevelMatrix);
@@ -1060,7 +1060,7 @@ static HRESULT WINAPI XA20SUB_GetOutputMatrix(IXAudio20SubmixVoice *iface,
 
 static void WINAPI XA20SUB_DestroyVoice(IXAudio20SubmixVoice *iface)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio20SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20SubmixVoice(iface);
     return IXAudio2SubmixVoice_DestroyVoice(&This->IXAudio2SubmixVoice_iface);
 }
 
@@ -1086,15 +1086,15 @@ const IXAudio20SubmixVoiceVtbl XAudio20SubmixVoice_Vtbl = {
 
 #elif XAUDIO2_VER <= 3
 
-static XA2SubmixImpl *impl_from_IXAudio23SubmixVoice(IXAudio23SubmixVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio23SubmixVoice(IXAudio23SubmixVoice *iface)
 {
-    return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio23SubmixVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio23SubmixVoice_iface);
 }
 
 static void WINAPI XA23SUB_GetVoiceDetails(IXAudio23SubmixVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2SubmixVoice_GetVoiceDetails(&This->IXAudio2SubmixVoice_iface, &details);
@@ -1107,7 +1107,7 @@ static void WINAPI XA23SUB_GetVoiceDetails(IXAudio23SubmixVoice *iface,
 static HRESULT WINAPI XA23SUB_SetOutputVoices(IXAudio23SubmixVoice *iface,
         const XAUDIO23_VOICE_SENDS *pSendList)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     XAUDIO2_VOICE_SENDS sends, *psends = NULL;
     HRESULT hr;
 
@@ -1130,14 +1130,14 @@ static HRESULT WINAPI XA23SUB_SetOutputVoices(IXAudio23SubmixVoice *iface,
 static HRESULT WINAPI XA23SUB_SetEffectChain(IXAudio23SubmixVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetEffectChain(&This->IXAudio2SubmixVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA23SUB_EnableEffect(IXAudio23SubmixVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_EnableEffect(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1145,7 +1145,7 @@ static HRESULT WINAPI XA23SUB_EnableEffect(IXAudio23SubmixVoice *iface,
 static HRESULT WINAPI XA23SUB_DisableEffect(IXAudio23SubmixVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_DisableEffect(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1153,7 +1153,7 @@ static HRESULT WINAPI XA23SUB_DisableEffect(IXAudio23SubmixVoice *iface,
 static void WINAPI XA23SUB_GetEffectState(IXAudio23SubmixVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetEffectState(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pEnabled);
 }
@@ -1162,7 +1162,7 @@ static HRESULT WINAPI XA23SUB_SetEffectParameters(IXAudio23SubmixVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetEffectParameters(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -1170,7 +1170,7 @@ static HRESULT WINAPI XA23SUB_SetEffectParameters(IXAudio23SubmixVoice *iface,
 static HRESULT WINAPI XA23SUB_GetEffectParameters(IXAudio23SubmixVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetEffectParameters(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -1178,7 +1178,7 @@ static HRESULT WINAPI XA23SUB_GetEffectParameters(IXAudio23SubmixVoice *iface,
 static HRESULT WINAPI XA23SUB_SetFilterParameters(IXAudio23SubmixVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetFilterParameters(&This->IXAudio2SubmixVoice_iface,
             pParameters, OperationSet);
 }
@@ -1186,14 +1186,14 @@ static HRESULT WINAPI XA23SUB_SetFilterParameters(IXAudio23SubmixVoice *iface,
 static void WINAPI XA23SUB_GetFilterParameters(IXAudio23SubmixVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetFilterParameters(&This->IXAudio2SubmixVoice_iface, pParameters);
 }
 
 static HRESULT WINAPI XA23SUB_SetVolume(IXAudio23SubmixVoice *iface,
         float Volume, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetVolume(&This->IXAudio2SubmixVoice_iface,
             Volume, OperationSet);
 }
@@ -1201,14 +1201,14 @@ static HRESULT WINAPI XA23SUB_SetVolume(IXAudio23SubmixVoice *iface,
 static void WINAPI XA23SUB_GetVolume(IXAudio23SubmixVoice *iface,
         float *pVolume)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetVolume(&This->IXAudio2SubmixVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA23SUB_SetChannelVolumes(IXAudio23SubmixVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetChannelVolumes(&This->IXAudio2SubmixVoice_iface,
             Channels, pVolumes, OperationSet);
 }
@@ -1216,7 +1216,7 @@ static HRESULT WINAPI XA23SUB_SetChannelVolumes(IXAudio23SubmixVoice *iface,
 static void WINAPI XA23SUB_GetChannelVolumes(IXAudio23SubmixVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetChannelVolumes(&This->IXAudio2SubmixVoice_iface,
             Channels, pVolumes);
 }
@@ -1226,7 +1226,7 @@ static HRESULT WINAPI XA23SUB_SetOutputMatrix(IXAudio23SubmixVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetOutputMatrix(&This->IXAudio2SubmixVoice_iface,
             pDestinationVoice, SubmixChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -1236,7 +1236,7 @@ static void WINAPI XA23SUB_GetOutputMatrix(IXAudio23SubmixVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 SubmixChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetOutputMatrix(&This->IXAudio2SubmixVoice_iface,
             pDestinationVoice, SubmixChannels, DestinationChannels,
             pLevelMatrix);
@@ -1244,7 +1244,7 @@ static void WINAPI XA23SUB_GetOutputMatrix(IXAudio23SubmixVoice *iface,
 
 static void WINAPI XA23SUB_DestroyVoice(IXAudio23SubmixVoice *iface)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23SubmixVoice(iface);
     return IXAudio2SubmixVoice_DestroyVoice(&This->IXAudio2SubmixVoice_iface);
 }
 
@@ -1270,15 +1270,15 @@ const IXAudio23SubmixVoiceVtbl XAudio23SubmixVoice_Vtbl = {
 
 #elif XAUDIO2_VER <= 7
 
-static XA2SubmixImpl *impl_from_IXAudio27SubmixVoice(IXAudio27SubmixVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio27SubmixVoice(IXAudio27SubmixVoice *iface)
 {
-    return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio27SubmixVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio27SubmixVoice_iface);
 }
 
 static void WINAPI XA27SUB_GetVoiceDetails(IXAudio27SubmixVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2SubmixVoice_GetVoiceDetails(&This->IXAudio2SubmixVoice_iface, &details);
@@ -1291,21 +1291,21 @@ static void WINAPI XA27SUB_GetVoiceDetails(IXAudio27SubmixVoice *iface,
 static HRESULT WINAPI XA27SUB_SetOutputVoices(IXAudio27SubmixVoice *iface,
         const XAUDIO2_VOICE_SENDS *pSendList)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetOutputVoices(&This->IXAudio2SubmixVoice_iface, pSendList);
 }
 
 static HRESULT WINAPI XA27SUB_SetEffectChain(IXAudio27SubmixVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetEffectChain(&This->IXAudio2SubmixVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA27SUB_EnableEffect(IXAudio27SubmixVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_EnableEffect(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1313,7 +1313,7 @@ static HRESULT WINAPI XA27SUB_EnableEffect(IXAudio27SubmixVoice *iface,
 static HRESULT WINAPI XA27SUB_DisableEffect(IXAudio27SubmixVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_DisableEffect(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1321,7 +1321,7 @@ static HRESULT WINAPI XA27SUB_DisableEffect(IXAudio27SubmixVoice *iface,
 static void WINAPI XA27SUB_GetEffectState(IXAudio27SubmixVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetEffectState(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pEnabled);
 }
@@ -1330,7 +1330,7 @@ static HRESULT WINAPI XA27SUB_SetEffectParameters(IXAudio27SubmixVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetEffectParameters(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -1338,7 +1338,7 @@ static HRESULT WINAPI XA27SUB_SetEffectParameters(IXAudio27SubmixVoice *iface,
 static HRESULT WINAPI XA27SUB_GetEffectParameters(IXAudio27SubmixVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetEffectParameters(&This->IXAudio2SubmixVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -1346,7 +1346,7 @@ static HRESULT WINAPI XA27SUB_GetEffectParameters(IXAudio27SubmixVoice *iface,
 static HRESULT WINAPI XA27SUB_SetFilterParameters(IXAudio27SubmixVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetFilterParameters(&This->IXAudio2SubmixVoice_iface,
             pParameters, OperationSet);
 }
@@ -1354,7 +1354,7 @@ static HRESULT WINAPI XA27SUB_SetFilterParameters(IXAudio27SubmixVoice *iface,
 static void WINAPI XA27SUB_GetFilterParameters(IXAudio27SubmixVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetFilterParameters(&This->IXAudio2SubmixVoice_iface, pParameters);
 }
 
@@ -1362,7 +1362,7 @@ static HRESULT WINAPI XA27SUB_SetOutputFilterParameters(IXAudio27SubmixVoice *if
         IXAudio2Voice *pDestinationVoice,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetOutputFilterParameters(&This->IXAudio2SubmixVoice_iface,
             pDestinationVoice, pParameters, OperationSet);
 }
@@ -1371,7 +1371,7 @@ static void WINAPI XA27SUB_GetOutputFilterParameters(IXAudio27SubmixVoice *iface
         IXAudio2Voice *pDestinationVoice,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     IXAudio2SubmixVoice_GetOutputFilterParameters(&This->IXAudio2SubmixVoice_iface,
             pDestinationVoice, pParameters);
 }
@@ -1379,7 +1379,7 @@ static void WINAPI XA27SUB_GetOutputFilterParameters(IXAudio27SubmixVoice *iface
 static HRESULT WINAPI XA27SUB_SetVolume(IXAudio27SubmixVoice *iface,
         float Volume, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetVolume(&This->IXAudio2SubmixVoice_iface,
             Volume, OperationSet);
 }
@@ -1387,14 +1387,14 @@ static HRESULT WINAPI XA27SUB_SetVolume(IXAudio27SubmixVoice *iface,
 static void WINAPI XA27SUB_GetVolume(IXAudio27SubmixVoice *iface,
         float *pVolume)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetVolume(&This->IXAudio2SubmixVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA27SUB_SetChannelVolumes(IXAudio27SubmixVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetChannelVolumes(&This->IXAudio2SubmixVoice_iface,
             Channels, pVolumes, OperationSet);
 }
@@ -1402,7 +1402,7 @@ static HRESULT WINAPI XA27SUB_SetChannelVolumes(IXAudio27SubmixVoice *iface,
 static void WINAPI XA27SUB_GetChannelVolumes(IXAudio27SubmixVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetChannelVolumes(&This->IXAudio2SubmixVoice_iface,
             Channels, pVolumes);
 }
@@ -1412,7 +1412,7 @@ static HRESULT WINAPI XA27SUB_SetOutputMatrix(IXAudio27SubmixVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_SetOutputMatrix(&This->IXAudio2SubmixVoice_iface,
             pDestinationVoice, SubmixChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -1422,7 +1422,7 @@ static void WINAPI XA27SUB_GetOutputMatrix(IXAudio27SubmixVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 SubmixChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_GetOutputMatrix(&This->IXAudio2SubmixVoice_iface,
             pDestinationVoice, SubmixChannels, DestinationChannels,
             pLevelMatrix);
@@ -1430,7 +1430,7 @@ static void WINAPI XA27SUB_GetOutputMatrix(IXAudio27SubmixVoice *iface,
 
 static void WINAPI XA27SUB_DestroyVoice(IXAudio27SubmixVoice *iface)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio27SubmixVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27SubmixVoice(iface);
     return IXAudio2SubmixVoice_DestroyVoice(&This->IXAudio2SubmixVoice_iface);
 }
 
@@ -1461,15 +1461,15 @@ const IXAudio27SubmixVoiceVtbl XAudio27SubmixVoice_Vtbl = {
 
 /* BEGIN IXAudio2MasteringVoice */
 #if XAUDIO2_VER == 0
-static IXAudio2Impl *impl_from_IXAudio20MasteringVoice(IXAudio20MasteringVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio20MasteringVoice(IXAudio20MasteringVoice *iface)
 {
-    return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio20MasteringVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio20MasteringVoice_iface);
 }
 
 static void WINAPI XA20M_GetVoiceDetails(IXAudio20MasteringVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2MasteringVoice_GetVoiceDetails(&This->IXAudio2MasteringVoice_iface, &details);
@@ -1482,7 +1482,7 @@ static void WINAPI XA20M_GetVoiceDetails(IXAudio20MasteringVoice *iface,
 static HRESULT WINAPI XA20M_SetOutputVoices(IXAudio20MasteringVoice *iface,
         const XAUDIO23_VOICE_SENDS *pSendList)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     XAUDIO2_VOICE_SENDS sends, *psends;
     HRESULT hr;
 
@@ -1505,14 +1505,14 @@ static HRESULT WINAPI XA20M_SetOutputVoices(IXAudio20MasteringVoice *iface,
 static HRESULT WINAPI XA20M_SetEffectChain(IXAudio20MasteringVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetEffectChain(&This->IXAudio2MasteringVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA20M_EnableEffect(IXAudio20MasteringVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_EnableEffect(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1520,7 +1520,7 @@ static HRESULT WINAPI XA20M_EnableEffect(IXAudio20MasteringVoice *iface,
 static HRESULT WINAPI XA20M_DisableEffect(IXAudio20MasteringVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_DisableEffect(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1528,7 +1528,7 @@ static HRESULT WINAPI XA20M_DisableEffect(IXAudio20MasteringVoice *iface,
 static void WINAPI XA20M_GetEffectState(IXAudio20MasteringVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetEffectState(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pEnabled);
 }
@@ -1537,7 +1537,7 @@ static HRESULT WINAPI XA20M_SetEffectParameters(IXAudio20MasteringVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetEffectParameters(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -1545,7 +1545,7 @@ static HRESULT WINAPI XA20M_SetEffectParameters(IXAudio20MasteringVoice *iface,
 static HRESULT WINAPI XA20M_GetEffectParameters(IXAudio20MasteringVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetEffectParameters(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -1553,7 +1553,7 @@ static HRESULT WINAPI XA20M_GetEffectParameters(IXAudio20MasteringVoice *iface,
 static HRESULT WINAPI XA20M_SetFilterParameters(IXAudio20MasteringVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetFilterParameters(&This->IXAudio2MasteringVoice_iface,
             pParameters, OperationSet);
 }
@@ -1561,14 +1561,14 @@ static HRESULT WINAPI XA20M_SetFilterParameters(IXAudio20MasteringVoice *iface,
 static void WINAPI XA20M_GetFilterParameters(IXAudio20MasteringVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetFilterParameters(&This->IXAudio2MasteringVoice_iface, pParameters);
 }
 
 static HRESULT WINAPI XA20M_SetVolume(IXAudio20MasteringVoice *iface,
         float Volume, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetVolume(&This->IXAudio2MasteringVoice_iface,
             Volume, OperationSet);
 }
@@ -1576,14 +1576,14 @@ static HRESULT WINAPI XA20M_SetVolume(IXAudio20MasteringVoice *iface,
 static void WINAPI XA20M_GetVolume(IXAudio20MasteringVoice *iface,
         float *pVolume)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetVolume(&This->IXAudio2MasteringVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA20M_SetChannelVolumes(IXAudio20MasteringVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetChannelVolumes(&This->IXAudio2MasteringVoice_iface,
             Channels, pVolumes, OperationSet);
 }
@@ -1591,7 +1591,7 @@ static HRESULT WINAPI XA20M_SetChannelVolumes(IXAudio20MasteringVoice *iface,
 static void WINAPI XA20M_GetChannelVolumes(IXAudio20MasteringVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetChannelVolumes(&This->IXAudio2MasteringVoice_iface,
             Channels, pVolumes);
 }
@@ -1601,7 +1601,7 @@ static HRESULT WINAPI XA20M_SetOutputMatrix(IXAudio20MasteringVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetOutputMatrix(&This->IXAudio2MasteringVoice_iface,
             pDestinationVoice, MasteringChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -1611,7 +1611,7 @@ static HRESULT WINAPI XA20M_GetOutputMatrix(IXAudio20MasteringVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 MasteringChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     IXAudio2MasteringVoice_GetOutputMatrix(&This->IXAudio2MasteringVoice_iface,
             pDestinationVoice, MasteringChannels, DestinationChannels,
             pLevelMatrix);
@@ -1620,7 +1620,7 @@ static HRESULT WINAPI XA20M_GetOutputMatrix(IXAudio20MasteringVoice *iface,
 
 static void WINAPI XA20M_DestroyVoice(IXAudio20MasteringVoice *iface)
 {
-    IXAudio2Impl *This = impl_from_IXAudio20MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio20MasteringVoice(iface);
     return IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
 }
 
@@ -1646,15 +1646,15 @@ const IXAudio20MasteringVoiceVtbl XAudio20MasteringVoice_Vtbl = {
 
 #elif XAUDIO2_VER <= 3
 
-static IXAudio2Impl *impl_from_IXAudio23MasteringVoice(IXAudio23MasteringVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio23MasteringVoice(IXAudio23MasteringVoice *iface)
 {
-    return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio23MasteringVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio23MasteringVoice_iface);
 }
 
 static void WINAPI XA23M_GetVoiceDetails(IXAudio23MasteringVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2MasteringVoice_GetVoiceDetails(&This->IXAudio2MasteringVoice_iface, &details);
@@ -1667,7 +1667,7 @@ static void WINAPI XA23M_GetVoiceDetails(IXAudio23MasteringVoice *iface,
 static HRESULT WINAPI XA23M_SetOutputVoices(IXAudio23MasteringVoice *iface,
         const XAUDIO23_VOICE_SENDS *pSendList)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     XAUDIO2_VOICE_SENDS sends, *psends = NULL;
     HRESULT hr;
 
@@ -1690,14 +1690,14 @@ static HRESULT WINAPI XA23M_SetOutputVoices(IXAudio23MasteringVoice *iface,
 static HRESULT WINAPI XA23M_SetEffectChain(IXAudio23MasteringVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetEffectChain(&This->IXAudio2MasteringVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA23M_EnableEffect(IXAudio23MasteringVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_EnableEffect(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1705,7 +1705,7 @@ static HRESULT WINAPI XA23M_EnableEffect(IXAudio23MasteringVoice *iface,
 static HRESULT WINAPI XA23M_DisableEffect(IXAudio23MasteringVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_DisableEffect(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1713,7 +1713,7 @@ static HRESULT WINAPI XA23M_DisableEffect(IXAudio23MasteringVoice *iface,
 static void WINAPI XA23M_GetEffectState(IXAudio23MasteringVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetEffectState(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pEnabled);
 }
@@ -1722,7 +1722,7 @@ static HRESULT WINAPI XA23M_SetEffectParameters(IXAudio23MasteringVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetEffectParameters(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -1730,7 +1730,7 @@ static HRESULT WINAPI XA23M_SetEffectParameters(IXAudio23MasteringVoice *iface,
 static HRESULT WINAPI XA23M_GetEffectParameters(IXAudio23MasteringVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetEffectParameters(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -1738,7 +1738,7 @@ static HRESULT WINAPI XA23M_GetEffectParameters(IXAudio23MasteringVoice *iface,
 static HRESULT WINAPI XA23M_SetFilterParameters(IXAudio23MasteringVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetFilterParameters(&This->IXAudio2MasteringVoice_iface,
             pParameters, OperationSet);
 }
@@ -1746,14 +1746,14 @@ static HRESULT WINAPI XA23M_SetFilterParameters(IXAudio23MasteringVoice *iface,
 static void WINAPI XA23M_GetFilterParameters(IXAudio23MasteringVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetFilterParameters(&This->IXAudio2MasteringVoice_iface, pParameters);
 }
 
 static HRESULT WINAPI XA23M_SetVolume(IXAudio23MasteringVoice *iface,
         float Volume, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetVolume(&This->IXAudio2MasteringVoice_iface,
             Volume, OperationSet);
 }
@@ -1761,14 +1761,14 @@ static HRESULT WINAPI XA23M_SetVolume(IXAudio23MasteringVoice *iface,
 static void WINAPI XA23M_GetVolume(IXAudio23MasteringVoice *iface,
         float *pVolume)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetVolume(&This->IXAudio2MasteringVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA23M_SetChannelVolumes(IXAudio23MasteringVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetChannelVolumes(&This->IXAudio2MasteringVoice_iface,
             Channels, pVolumes, OperationSet);
 }
@@ -1776,7 +1776,7 @@ static HRESULT WINAPI XA23M_SetChannelVolumes(IXAudio23MasteringVoice *iface,
 static void WINAPI XA23M_GetChannelVolumes(IXAudio23MasteringVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetChannelVolumes(&This->IXAudio2MasteringVoice_iface,
             Channels, pVolumes);
 }
@@ -1786,7 +1786,7 @@ static HRESULT WINAPI XA23M_SetOutputMatrix(IXAudio23MasteringVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetOutputMatrix(&This->IXAudio2MasteringVoice_iface,
             pDestinationVoice, MasteringChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -1796,7 +1796,7 @@ static void WINAPI XA23M_GetOutputMatrix(IXAudio23MasteringVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 MasteringChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetOutputMatrix(&This->IXAudio2MasteringVoice_iface,
             pDestinationVoice, MasteringChannels, DestinationChannels,
             pLevelMatrix);
@@ -1804,7 +1804,7 @@ static void WINAPI XA23M_GetOutputMatrix(IXAudio23MasteringVoice *iface,
 
 static void WINAPI XA23M_DestroyVoice(IXAudio23MasteringVoice *iface)
 {
-    IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio23MasteringVoice(iface);
     return IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
 }
 
@@ -1830,15 +1830,15 @@ const IXAudio23MasteringVoiceVtbl XAudio23MasteringVoice_Vtbl = {
 
 #elif XAUDIO2_VER <= 7
 
-static IXAudio2Impl *impl_from_IXAudio27MasteringVoice(IXAudio27MasteringVoice *iface)
+XA2VoiceImpl *impl_from_IXAudio27MasteringVoice(IXAudio27MasteringVoice *iface)
 {
-    return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio27MasteringVoice_iface);
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio27MasteringVoice_iface);
 }
 
 static void WINAPI XA27M_GetVoiceDetails(IXAudio27MasteringVoice *iface,
         XAUDIO27_VOICE_DETAILS *pVoiceDetails)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     XAUDIO2_VOICE_DETAILS details;
 
     IXAudio2MasteringVoice_GetVoiceDetails(&This->IXAudio2MasteringVoice_iface, &details);
@@ -1851,21 +1851,21 @@ static void WINAPI XA27M_GetVoiceDetails(IXAudio27MasteringVoice *iface,
 static HRESULT WINAPI XA27M_SetOutputVoices(IXAudio27MasteringVoice *iface,
         const XAUDIO2_VOICE_SENDS *pSendList)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetOutputVoices(&This->IXAudio2MasteringVoice_iface, pSendList);
 }
 
 static HRESULT WINAPI XA27M_SetEffectChain(IXAudio27MasteringVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetEffectChain(&This->IXAudio2MasteringVoice_iface, pEffectChain);
 }
 
 static HRESULT WINAPI XA27M_EnableEffect(IXAudio27MasteringVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_EnableEffect(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1873,7 +1873,7 @@ static HRESULT WINAPI XA27M_EnableEffect(IXAudio27MasteringVoice *iface,
 static HRESULT WINAPI XA27M_DisableEffect(IXAudio27MasteringVoice *iface,
         UINT32 EffectIndex, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_DisableEffect(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, OperationSet);
 }
@@ -1881,7 +1881,7 @@ static HRESULT WINAPI XA27M_DisableEffect(IXAudio27MasteringVoice *iface,
 static void WINAPI XA27M_GetEffectState(IXAudio27MasteringVoice *iface,
         UINT32 EffectIndex, BOOL *pEnabled)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetEffectState(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pEnabled);
 }
@@ -1890,7 +1890,7 @@ static HRESULT WINAPI XA27M_SetEffectParameters(IXAudio27MasteringVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetEffectParameters(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pParameters, ParametersByteSize, OperationSet);
 }
@@ -1898,7 +1898,7 @@ static HRESULT WINAPI XA27M_SetEffectParameters(IXAudio27MasteringVoice *iface,
 static HRESULT WINAPI XA27M_GetEffectParameters(IXAudio27MasteringVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetEffectParameters(&This->IXAudio2MasteringVoice_iface,
             EffectIndex, pParameters, ParametersByteSize);
 }
@@ -1906,7 +1906,7 @@ static HRESULT WINAPI XA27M_GetEffectParameters(IXAudio27MasteringVoice *iface,
 static HRESULT WINAPI XA27M_SetFilterParameters(IXAudio27MasteringVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetFilterParameters(&This->IXAudio2MasteringVoice_iface,
             pParameters, OperationSet);
 }
@@ -1914,7 +1914,7 @@ static HRESULT WINAPI XA27M_SetFilterParameters(IXAudio27MasteringVoice *iface,
 static void WINAPI XA27M_GetFilterParameters(IXAudio27MasteringVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetFilterParameters(&This->IXAudio2MasteringVoice_iface, pParameters);
 }
 
@@ -1922,7 +1922,7 @@ static HRESULT WINAPI XA27M_SetOutputFilterParameters(IXAudio27MasteringVoice *i
         IXAudio2Voice *pDestinationVoice,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetOutputFilterParameters(&This->IXAudio2MasteringVoice_iface,
             pDestinationVoice, pParameters, OperationSet);
 }
@@ -1931,7 +1931,7 @@ static void WINAPI XA27M_GetOutputFilterParameters(IXAudio27MasteringVoice *ifac
         IXAudio2Voice *pDestinationVoice,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     IXAudio2MasteringVoice_GetOutputFilterParameters(&This->IXAudio2MasteringVoice_iface,
             pDestinationVoice, pParameters);
 }
@@ -1939,7 +1939,7 @@ static void WINAPI XA27M_GetOutputFilterParameters(IXAudio27MasteringVoice *ifac
 static HRESULT WINAPI XA27M_SetVolume(IXAudio27MasteringVoice *iface,
         float Volume, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetVolume(&This->IXAudio2MasteringVoice_iface,
             Volume, OperationSet);
 }
@@ -1947,14 +1947,14 @@ static HRESULT WINAPI XA27M_SetVolume(IXAudio27MasteringVoice *iface,
 static void WINAPI XA27M_GetVolume(IXAudio27MasteringVoice *iface,
         float *pVolume)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetVolume(&This->IXAudio2MasteringVoice_iface, pVolume);
 }
 
 static HRESULT WINAPI XA27M_SetChannelVolumes(IXAudio27MasteringVoice *iface,
         UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetChannelVolumes(&This->IXAudio2MasteringVoice_iface,
             Channels, pVolumes, OperationSet);
 }
@@ -1962,7 +1962,7 @@ static HRESULT WINAPI XA27M_SetChannelVolumes(IXAudio27MasteringVoice *iface,
 static void WINAPI XA27M_GetChannelVolumes(IXAudio27MasteringVoice *iface,
         UINT32 Channels, float *pVolumes)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetChannelVolumes(&This->IXAudio2MasteringVoice_iface,
             Channels, pVolumes);
 }
@@ -1972,7 +1972,7 @@ static HRESULT WINAPI XA27M_SetOutputMatrix(IXAudio27MasteringVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_SetOutputMatrix(&This->IXAudio2MasteringVoice_iface,
             pDestinationVoice, MasteringChannels, DestinationChannels,
             pLevelMatrix, OperationSet);
@@ -1982,7 +1982,7 @@ static void WINAPI XA27M_GetOutputMatrix(IXAudio27MasteringVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 MasteringChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_GetOutputMatrix(&This->IXAudio2MasteringVoice_iface,
             pDestinationVoice, MasteringChannels, DestinationChannels,
             pLevelMatrix);
@@ -1990,7 +1990,7 @@ static void WINAPI XA27M_GetOutputMatrix(IXAudio27MasteringVoice *iface,
 
 static void WINAPI XA27M_DestroyVoice(IXAudio27MasteringVoice *iface)
 {
-    IXAudio2Impl *This = impl_from_IXAudio27MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio27MasteringVoice(iface);
     return IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
 }
 
@@ -2048,93 +2048,16 @@ static ULONG WINAPI XA20_Release(IXAudio20 *iface)
 static HRESULT WINAPI XA20_GetDeviceCount(IXAudio20 *iface, UINT32 *pCount)
 {
     IXAudio2Impl *This = impl_from_IXAudio20(iface);
-
     TRACE("%p, %p\n", This, pCount);
-
-    *pCount = This->ndevs;
-
-    return S_OK;
+    return FAudio_GetDeviceCount(This->faudio, pCount);
 }
 
 static HRESULT WINAPI XA20_GetDeviceDetails(IXAudio20 *iface, UINT32 index,
         XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
 {
     IXAudio2Impl *This = impl_from_IXAudio20(iface);
-    HRESULT hr;
-    IMMDevice *dev;
-    IAudioClient *client;
-    IPropertyStore *ps;
-    WAVEFORMATEX *wfx;
-    PROPVARIANT var;
-
     TRACE("%p, %u, %p\n", This, index, pDeviceDetails);
-
-    if(index >= This->ndevs)
-        return E_INVALIDARG;
-
-    hr = IMMDeviceEnumerator_GetDevice(This->devenum, This->devids[index], &dev);
-    if(FAILED(hr)){
-        WARN("GetDevice failed: %08x\n", hr);
-        return hr;
-    }
-
-    hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER,
-            NULL, (void**)&client);
-    if(FAILED(hr)){
-        WARN("Activate failed: %08x\n", hr);
-        IMMDevice_Release(dev);
-        return hr;
-    }
-
-    hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, &ps);
-    if(FAILED(hr)){
-        WARN("OpenPropertyStore failed: %08x\n", hr);
-        IAudioClient_Release(client);
-        IMMDevice_Release(dev);
-        return hr;
-    }
-
-    PropVariantInit(&var);
-
-    hr = IPropertyStore_GetValue(ps, (PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &var);
-    if(FAILED(hr)){
-        WARN("GetValue failed: %08x\n", hr);
-        goto done;
-    }
-
-    lstrcpynW(pDeviceDetails->DisplayName, var.u.pwszVal, ARRAY_SIZE(pDeviceDetails->DisplayName));
-
-    PropVariantClear(&var);
-
-    hr = IAudioClient_GetMixFormat(client, &wfx);
-    if(FAILED(hr)){
-        WARN("GetMixFormat failed: %08x\n", hr);
-        goto done;
-    }
-
-    lstrcpyW(pDeviceDetails->DeviceID, This->devids[index]);
-
-    if(index == 0)
-        pDeviceDetails->Role = GlobalDefaultDevice;
-    else
-        pDeviceDetails->Role = NotDefaultDevice;
-
-    if(sizeof(WAVEFORMATEX) + wfx->cbSize > sizeof(pDeviceDetails->OutputFormat)){
-        FIXME("AudioClient format is too large to fit into WAVEFORMATEXTENSIBLE!\n");
-        CoTaskMemFree(wfx);
-        hr = E_FAIL;
-        goto done;
-    }
-    memcpy(&pDeviceDetails->OutputFormat, wfx, sizeof(WAVEFORMATEX) + wfx->cbSize);
-
-    CoTaskMemFree(wfx);
-
-done:
-    IPropertyStore_Release(ps);
-    IAudioClient_Release(client);
-    IMMDevice_Release(dev);
-
-    return hr;
+    return FAudio_GetDeviceDetails(This->faudio, index, (FAudioDeviceDetails *)pDeviceDetails);
 }
 
 static HRESULT WINAPI XA20_Initialize(IXAudio20 *iface, UINT32 flags,
@@ -2222,12 +2145,41 @@ static HRESULT WINAPI XA20_CreateMasteringVoice(IXAudio20 *iface,
             inputChannels, inputSampleRate, flags, deviceIndex,
             pEffectChain);
 
-    if(deviceIndex >= This->ndevs)
-        return E_INVALIDARG;
+    EnterCriticalSection(&This->lock);
+
+    /* XAUDIO2_VER == 0 */
+    *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->mst.IXAudio20MasteringVoice_iface;
+
+    EnterCriticalSection(&This->mst.lock);
+
+    if(This->mst.in_use){
+        LeaveCriticalSection(&This->mst.lock);
+        LeaveCriticalSection(&This->lock);
+        return COMPAT_E_INVALID_CALL;
+    }
+
+    LeaveCriticalSection(&This->lock);
 
-    return IXAudio2_CreateMasteringVoice(&This->IXAudio2_iface, ppMasteringVoice,
-            inputChannels, inputSampleRate, flags, This->devids[deviceIndex],
-            pEffectChain, AudioCategory_GameEffects);
+    This->mst.effect_chain = wrap_effect_chain(pEffectChain);
+
+    pthread_mutex_lock(&This->mst.engine_lock);
+
+    This->mst.engine_thread = CreateThread(NULL, 0, &engine_thread, &This->mst, 0, NULL);
+
+    pthread_cond_wait(&This->mst.engine_done, &This->mst.engine_lock);
+
+    pthread_mutex_unlock(&This->mst.engine_lock);
+
+    FAudio_SetEngineProcedureEXT(This->faudio, &engine_cb, &This->mst);
+
+    FAudio_CreateMasteringVoice(This->faudio, &This->mst.faudio_voice, inputChannels,
+            inputSampleRate, flags, deviceIndex, This->mst.effect_chain);
+
+    This->mst.in_use = TRUE;
+
+    LeaveCriticalSection(&This->mst.lock);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI XA20_StartEngine(IXAudio20 *iface)
@@ -2331,93 +2283,16 @@ static ULONG WINAPI XA22_Release(IXAudio22 *iface)
 static HRESULT WINAPI XA22_GetDeviceCount(IXAudio22 *iface, UINT32 *pCount)
 {
     IXAudio2Impl *This = impl_from_IXAudio22(iface);
-
     TRACE("%p, %p\n", This, pCount);
-
-    *pCount = This->ndevs;
-
-    return S_OK;
+    return FAudio_GetDeviceCount(This->faudio, pCount);
 }
 
 static HRESULT WINAPI XA22_GetDeviceDetails(IXAudio22 *iface, UINT32 index,
         XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
 {
     IXAudio2Impl *This = impl_from_IXAudio22(iface);
-    HRESULT hr;
-    IMMDevice *dev;
-    IAudioClient *client;
-    IPropertyStore *ps;
-    WAVEFORMATEX *wfx;
-    PROPVARIANT var;
-
     TRACE("%p, %u, %p\n", This, index, pDeviceDetails);
-
-    if(index >= This->ndevs)
-        return E_INVALIDARG;
-
-    hr = IMMDeviceEnumerator_GetDevice(This->devenum, This->devids[index], &dev);
-    if(FAILED(hr)){
-        WARN("GetDevice failed: %08x\n", hr);
-        return hr;
-    }
-
-    hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER,
-            NULL, (void**)&client);
-    if(FAILED(hr)){
-        WARN("Activate failed: %08x\n", hr);
-        IMMDevice_Release(dev);
-        return hr;
-    }
-
-    hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, &ps);
-    if(FAILED(hr)){
-        WARN("OpenPropertyStore failed: %08x\n", hr);
-        IAudioClient_Release(client);
-        IMMDevice_Release(dev);
-        return hr;
-    }
-
-    PropVariantInit(&var);
-
-    hr = IPropertyStore_GetValue(ps, (PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &var);
-    if(FAILED(hr)){
-        WARN("GetValue failed: %08x\n", hr);
-        goto done;
-    }
-
-    lstrcpynW(pDeviceDetails->DisplayName, var.u.pwszVal, ARRAY_SIZE(pDeviceDetails->DisplayName));
-
-    PropVariantClear(&var);
-
-    hr = IAudioClient_GetMixFormat(client, &wfx);
-    if(FAILED(hr)){
-        WARN("GetMixFormat failed: %08x\n", hr);
-        goto done;
-    }
-
-    lstrcpyW(pDeviceDetails->DeviceID, This->devids[index]);
-
-    if(index == 0)
-        pDeviceDetails->Role = GlobalDefaultDevice;
-    else
-        pDeviceDetails->Role = NotDefaultDevice;
-
-    if(sizeof(WAVEFORMATEX) + wfx->cbSize > sizeof(pDeviceDetails->OutputFormat)){
-        FIXME("AudioClient format is too large to fit into WAVEFORMATEXTENSIBLE!\n");
-        CoTaskMemFree(wfx);
-        hr = E_FAIL;
-        goto done;
-    }
-    memcpy(&pDeviceDetails->OutputFormat, wfx, sizeof(WAVEFORMATEX) + wfx->cbSize);
-
-    CoTaskMemFree(wfx);
-
-done:
-    IPropertyStore_Release(ps);
-    IAudioClient_Release(client);
-    IMMDevice_Release(dev);
-
-    return hr;
+    return FAudio_GetDeviceDetails(This->faudio, index, (FAudioDeviceDetails *)pDeviceDetails);
 }
 
 static HRESULT WINAPI XA22_Initialize(IXAudio22 *iface, UINT32 flags,
@@ -2505,12 +2380,41 @@ static HRESULT WINAPI XA22_CreateMasteringVoice(IXAudio22 *iface,
             inputChannels, inputSampleRate, flags, deviceIndex,
             pEffectChain);
 
-    if(deviceIndex >= This->ndevs)
-        return E_INVALIDARG;
+    EnterCriticalSection(&This->lock);
+
+    /* 1 <= XAUDIO2_VER <= 2 */
+    *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->mst.IXAudio23MasteringVoice_iface;
+
+    EnterCriticalSection(&This->mst.lock);
+
+    if(This->mst.in_use){
+        LeaveCriticalSection(&This->mst.lock);
+        LeaveCriticalSection(&This->lock);
+        return COMPAT_E_INVALID_CALL;
+    }
+
+    LeaveCriticalSection(&This->lock);
+
+    This->mst.effect_chain = wrap_effect_chain(pEffectChain);
+
+    pthread_mutex_lock(&This->mst.engine_lock);
+
+    This->mst.engine_thread = CreateThread(NULL, 0, &engine_thread, &This->mst, 0, NULL);
+
+    pthread_cond_wait(&This->mst.engine_done, &This->mst.engine_lock);
+
+    pthread_mutex_unlock(&This->mst.engine_lock);
+
+    FAudio_SetEngineProcedureEXT(This->faudio, &engine_cb, &This->mst);
 
-    return IXAudio2_CreateMasteringVoice(&This->IXAudio2_iface, ppMasteringVoice,
-            inputChannels, inputSampleRate, flags, This->devids[deviceIndex],
-            pEffectChain, AudioCategory_GameEffects);
+    FAudio_CreateMasteringVoice(This->faudio, &This->mst.faudio_voice, inputChannels,
+            inputSampleRate, flags, deviceIndex, This->mst.effect_chain);
+
+    This->mst.in_use = TRUE;
+
+    LeaveCriticalSection(&This->mst.lock);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI XA22_StartEngine(IXAudio22 *iface)
@@ -2613,93 +2517,16 @@ static ULONG WINAPI XA27_Release(IXAudio27 *iface)
 static HRESULT WINAPI XA27_GetDeviceCount(IXAudio27 *iface, UINT32 *pCount)
 {
     IXAudio2Impl *This = impl_from_IXAudio27(iface);
-
     TRACE("%p, %p\n", This, pCount);
-
-    *pCount = This->ndevs;
-
-    return S_OK;
+    return FAudio_GetDeviceCount(This->faudio, pCount);
 }
 
 static HRESULT WINAPI XA27_GetDeviceDetails(IXAudio27 *iface, UINT32 index,
         XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
 {
     IXAudio2Impl *This = impl_from_IXAudio27(iface);
-    HRESULT hr;
-    IMMDevice *dev;
-    IAudioClient *client;
-    IPropertyStore *ps;
-    WAVEFORMATEX *wfx;
-    PROPVARIANT var;
-
     TRACE("%p, %u, %p\n", This, index, pDeviceDetails);
-
-    if(index >= This->ndevs)
-        return E_INVALIDARG;
-
-    hr = IMMDeviceEnumerator_GetDevice(This->devenum, This->devids[index], &dev);
-    if(FAILED(hr)){
-        WARN("GetDevice failed: %08x\n", hr);
-        return hr;
-    }
-
-    hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER,
-            NULL, (void**)&client);
-    if(FAILED(hr)){
-        WARN("Activate failed: %08x\n", hr);
-        IMMDevice_Release(dev);
-        return hr;
-    }
-
-    hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, &ps);
-    if(FAILED(hr)){
-        WARN("OpenPropertyStore failed: %08x\n", hr);
-        IAudioClient_Release(client);
-        IMMDevice_Release(dev);
-        return hr;
-    }
-
-    PropVariantInit(&var);
-
-    hr = IPropertyStore_GetValue(ps, (PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &var);
-    if(FAILED(hr)){
-        WARN("GetValue failed: %08x\n", hr);
-        goto done;
-    }
-
-    lstrcpynW(pDeviceDetails->DisplayName, var.u.pwszVal, ARRAY_SIZE(pDeviceDetails->DisplayName));
-
-    PropVariantClear(&var);
-
-    hr = IAudioClient_GetMixFormat(client, &wfx);
-    if(FAILED(hr)){
-        WARN("GetMixFormat failed: %08x\n", hr);
-        goto done;
-    }
-
-    lstrcpyW(pDeviceDetails->DeviceID, This->devids[index]);
-
-    if(index == 0)
-        pDeviceDetails->Role = GlobalDefaultDevice;
-    else
-        pDeviceDetails->Role = NotDefaultDevice;
-
-    if(sizeof(WAVEFORMATEX) + wfx->cbSize > sizeof(pDeviceDetails->OutputFormat)){
-        FIXME("AudioClient format is too large to fit into WAVEFORMATEXTENSIBLE!\n");
-        CoTaskMemFree(wfx);
-        hr = E_FAIL;
-        goto done;
-    }
-    memcpy(&pDeviceDetails->OutputFormat, wfx, sizeof(WAVEFORMATEX) + wfx->cbSize);
-
-    CoTaskMemFree(wfx);
-
-done:
-    IPropertyStore_Release(ps);
-    IAudioClient_Release(client);
-    IMMDevice_Release(dev);
-
-    return hr;
+    return FAudio_GetDeviceDetails(This->faudio, index, (FAudioDeviceDetails *)pDeviceDetails);
 }
 
 static HRESULT WINAPI XA27_Initialize(IXAudio27 *iface, UINT32 flags,
@@ -2759,12 +2586,45 @@ static HRESULT WINAPI XA27_CreateMasteringVoice(IXAudio27 *iface,
             inputChannels, inputSampleRate, flags, deviceIndex,
             pEffectChain);
 
-    if(deviceIndex >= This->ndevs)
-        return E_INVALIDARG;
+    EnterCriticalSection(&This->lock);
 
-    return IXAudio2_CreateMasteringVoice(&This->IXAudio2_iface, ppMasteringVoice,
-            inputChannels, inputSampleRate, flags, This->devids[deviceIndex],
-            pEffectChain, AudioCategory_GameEffects);
+    /* 3 <= XAUDIO2_VER <= 7 */
+#if XAUDIO2_VER == 3
+    *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->mst.IXAudio23MasteringVoice_iface;
+#else
+    *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->mst.IXAudio27MasteringVoice_iface;
+#endif
+
+    EnterCriticalSection(&This->mst.lock);
+
+    if(This->mst.in_use){
+        LeaveCriticalSection(&This->mst.lock);
+        LeaveCriticalSection(&This->lock);
+        return COMPAT_E_INVALID_CALL;
+    }
+
+    LeaveCriticalSection(&This->lock);
+
+    This->mst.effect_chain = wrap_effect_chain(pEffectChain);
+
+    pthread_mutex_lock(&This->mst.engine_lock);
+
+    This->mst.engine_thread = CreateThread(NULL, 0, &engine_thread, &This->mst, 0, NULL);
+
+    pthread_cond_wait(&This->mst.engine_done, &This->mst.engine_lock);
+
+    pthread_mutex_unlock(&This->mst.engine_lock);
+
+    FAudio_SetEngineProcedureEXT(This->faudio, &engine_cb, &This->mst);
+
+    FAudio_CreateMasteringVoice(This->faudio, &This->mst.faudio_voice, inputChannels,
+            inputSampleRate, flags, deviceIndex, This->mst.effect_chain);
+
+    This->mst.in_use = TRUE;
+
+    LeaveCriticalSection(&This->mst.lock);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI XA27_StartEngine(IXAudio27 *iface)
diff --git a/dlls/xaudio2_7/tests/xaudio2.c b/dlls/xaudio2_7/tests/xaudio2.c
index 0c1d9a7805..6f9b7d12cd 100644
--- a/dlls/xaudio2_7/tests/xaudio2.c
+++ b/dlls/xaudio2_7/tests/xaudio2.c
@@ -33,915 +33,6 @@ static BOOL xaudio27;
 static HRESULT (WINAPI *pXAudio2Create)(IXAudio2 **, UINT32, XAUDIO2_PROCESSOR) = NULL;
 static HRESULT (WINAPI *pCreateAudioVolumeMeter)(IUnknown**) = NULL;
 
-#define XA2CALL_0(method) if(xaudio27) hr = IXAudio27_##method((IXAudio27*)xa); else hr = IXAudio2_##method(xa);
-#define XA2CALL_0V(method) if(xaudio27) IXAudio27_##method((IXAudio27*)xa); else IXAudio2_##method(xa);
-#define XA2CALL_V(method, ...) if(xaudio27) IXAudio27_##method((IXAudio27*)xa, __VA_ARGS__); else IXAudio2_##method(xa, __VA_ARGS__);
-#define XA2CALL(method, ...) if(xaudio27) hr = IXAudio27_##method((IXAudio27*)xa, __VA_ARGS__); else hr = IXAudio2_##method(xa, __VA_ARGS__);
-
-static void fill_buf(float *buf, WAVEFORMATEX *fmt, DWORD hz, DWORD len_frames)
-{
-    if(winetest_interactive){
-        DWORD offs, c;
-        for(offs = 0; offs < len_frames; ++offs)
-            for(c = 0; c < fmt->nChannels; ++c)
-                buf[offs * fmt->nChannels + c] = sinf(offs * hz * 2 * M_PI / fmt->nSamplesPerSec);
-    }else
-        memset(buf, 0, sizeof(float) * len_frames * fmt->nChannels);
-}
-
-static struct _cb_state {
-    BOOL start_called, end_called;
-} ecb_state, src1_state, src2_state;
-
-static int pass_state = 0;
-static BOOL buffers_called = FALSE;
-
-static void WINAPI ECB_OnProcessingPassStart(IXAudio2EngineCallback *This)
-{
-    ok(!xaudio27 || pass_state == 0, "Callbacks called out of order: %u\n", pass_state);
-    ++pass_state;
-}
-
-static void WINAPI ECB_OnProcessingPassEnd(IXAudio2EngineCallback *This)
-{
-    ok(!xaudio27 || pass_state == (buffers_called ? 7 : 5), "Callbacks called out of order: %u\n", pass_state);
-    pass_state = 0;
-    buffers_called = FALSE;
-}
-
-static void WINAPI ECB_OnCriticalError(IXAudio2EngineCallback *This, HRESULT Error)
-{
-    ok(0, "Unexpected OnCriticalError\n");
-}
-
-static const IXAudio2EngineCallbackVtbl ecb_vtbl = {
-    ECB_OnProcessingPassStart,
-    ECB_OnProcessingPassEnd,
-    ECB_OnCriticalError
-};
-
-static IXAudio2EngineCallback ecb = { &ecb_vtbl };
-
-static IXAudio2VoiceCallback vcb1;
-static IXAudio2VoiceCallback vcb2;
-
-static void WINAPI VCB_OnVoiceProcessingPassStart(IXAudio2VoiceCallback *This,
-        UINT32 BytesRequired)
-{
-    if(This == &vcb1){
-        ok(!xaudio27 || pass_state == (buffers_called ? 4 : 3), "Callbacks called out of order: %u\n", pass_state);
-        ++pass_state;
-    }else{
-        ok(!xaudio27 || pass_state == 1, "Callbacks called out of order: %u\n", pass_state);
-        ++pass_state;
-    }
-}
-
-static void WINAPI VCB_OnVoiceProcessingPassEnd(IXAudio2VoiceCallback *This)
-{
-    if(This == &vcb1){
-        ok(!xaudio27 || pass_state == (buffers_called ? 6 : 4), "Callbacks called out of order: %u\n", pass_state);
-        ++pass_state;
-    }else{
-        ok(!xaudio27 || pass_state == (buffers_called ? 3 : 2), "Callbacks called out of order: %u\n", pass_state);
-        ++pass_state;
-    }
-}
-
-static void WINAPI VCB_OnStreamEnd(IXAudio2VoiceCallback *This)
-{
-    ok(0, "Unexpected OnStreamEnd\n");
-}
-
-static void WINAPI VCB_OnBufferStart(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-    if(This == &vcb1){
-        ok(!xaudio27 || pass_state == 5, "Callbacks called out of order: %u\n", pass_state);
-        ++pass_state;
-    }else{
-        ok(!xaudio27 || pass_state == 2, "Callbacks called out of order: %u\n", pass_state);
-        ++pass_state;
-        buffers_called = TRUE;
-    }
-}
-
-static void WINAPI VCB_OnBufferEnd(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-    if(This == &vcb1){
-        ok(!xaudio27 || pass_state == 5, "Callbacks called out of order: %u\n", pass_state);
-        ++pass_state;
-    }else{
-        ok(!xaudio27 || pass_state == 2, "Callbacks called out of order: %u\n", pass_state);
-        ++pass_state;
-        buffers_called = TRUE;
-    }
-}
-
-static void WINAPI VCB_OnLoopEnd(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-    ok(0, "Unexpected OnLoopEnd\n");
-}
-
-static void WINAPI VCB_OnVoiceError(IXAudio2VoiceCallback *This,
-        void *pBuffercontext, HRESULT Error)
-{
-    ok(0, "Unexpected OnVoiceError\n");
-}
-
-static const IXAudio2VoiceCallbackVtbl vcb_vtbl = {
-    VCB_OnVoiceProcessingPassStart,
-    VCB_OnVoiceProcessingPassEnd,
-    VCB_OnStreamEnd,
-    VCB_OnBufferStart,
-    VCB_OnBufferEnd,
-    VCB_OnLoopEnd,
-    VCB_OnVoiceError
-};
-
-static IXAudio2VoiceCallback vcb1 = { &vcb_vtbl };
-static IXAudio2VoiceCallback vcb2 = { &vcb_vtbl };
-
-static void test_simple_streaming(IXAudio2 *xa)
-{
-    HRESULT hr;
-    IXAudio2MasteringVoice *master;
-    IXAudio2SourceVoice *src, *src2;
-    IUnknown *vumeter;
-    WAVEFORMATEX fmt;
-    XAUDIO2_BUFFER buf, buf2;
-    XAUDIO2_VOICE_STATE state;
-    XAUDIO2_EFFECT_DESCRIPTOR effect;
-    XAUDIO2_EFFECT_CHAIN chain;
-    DWORD chmask;
-
-    memset(&ecb_state, 0, sizeof(ecb_state));
-    memset(&src1_state, 0, sizeof(src1_state));
-    memset(&src2_state, 0, sizeof(src2_state));
-
-    XA2CALL_0V(StopEngine);
-
-    /* Tests show in native XA2.8, ECB is called from a mixer thread, but VCBs
-     * may be called from other threads in any order. So we can't rely on any
-     * sequencing between VCB calls.
-     *
-     * XA2.7 does all mixing from a single thread, so call sequence can be
-     * tested. */
-    XA2CALL(RegisterForCallbacks, &ecb);
-    ok(hr == S_OK, "RegisterForCallbacks failed: %08x\n", hr);
-
-    if(xaudio27)
-        hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL);
-    else
-        hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects);
-    ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr);
-
-    if(!xaudio27){
-        chmask = 0xdeadbeef;
-        IXAudio2MasteringVoice_GetChannelMask(master, &chmask);
-        ok(chmask == (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT), "Got unexpected channel mask: 0x%x\n", chmask);
-    }
-
-    /* create first source voice */
-    fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
-    fmt.nChannels = 2;
-    fmt.nSamplesPerSec = 44100;
-    fmt.wBitsPerSample = 32;
-    fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
-    fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
-    fmt.cbSize = 0;
-
-    XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &vcb1, NULL, NULL);
-    ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
-
-    if(xaudio27){
-        XAUDIO27_VOICE_DETAILS details;
-        IXAudio27SourceVoice_GetVoiceDetails((IXAudio27SourceVoice*)src, &details);
-        ok(details.CreationFlags == 0, "Got wrong flags: 0x%x\n", details.CreationFlags);
-        ok(details.InputChannels == 2, "Got wrong channel count: 0x%x\n", details.InputChannels);
-        ok(details.InputSampleRate == 44100, "Got wrong sample rate: 0x%x\n", details.InputSampleRate);
-    }else{
-        XAUDIO2_VOICE_DETAILS details;
-        IXAudio2SourceVoice_GetVoiceDetails(src, &details);
-        ok(details.CreationFlags == 0, "Got wrong creation flags: 0x%x\n", details.CreationFlags);
-        ok(details.ActiveFlags == 0, "Got wrong active flags: 0x%x\n", details.CreationFlags);
-        ok(details.InputChannels == 2, "Got wrong channel count: 0x%x\n", details.InputChannels);
-        ok(details.InputSampleRate == 44100, "Got wrong sample rate: 0x%x\n", details.InputSampleRate);
-    }
-
-    memset(&buf, 0, sizeof(buf));
-    buf.AudioBytes = 22050 * fmt.nBlockAlign;
-    buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes);
-    fill_buf((float*)buf.pAudioData, &fmt, 440, 22050);
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Start failed: %08x\n", hr);
-
-    /* create second source voice */
-    XA2CALL(CreateSourceVoice, &src2, &fmt, 0, 1.f, &vcb2, NULL, NULL);
-    ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
-
-    if(xaudio27){
-        XAUDIO27_VOICE_DETAILS details;
-        IXAudio27SourceVoice_GetVoiceDetails((IXAudio27SourceVoice*)src2, &details);
-        ok(details.CreationFlags == 0, "Got wrong flags: 0x%x\n", details.CreationFlags);
-        ok(details.InputChannels == 2, "Got wrong channel count: 0x%x\n", details.InputChannels);
-        ok(details.InputSampleRate == 44100, "Got wrong sample rate: 0x%x\n", details.InputSampleRate);
-    }else{
-        XAUDIO2_VOICE_DETAILS details;
-        IXAudio2SourceVoice_GetVoiceDetails(src2, &details);
-        ok(details.CreationFlags == 0, "Got wrong creation flags: 0x%x\n", details.CreationFlags);
-        ok(details.ActiveFlags == 0, "Got wrong active flags: 0x%x\n", details.CreationFlags);
-        ok(details.InputChannels == 2, "Got wrong channel count: 0x%x\n", details.InputChannels);
-        ok(details.InputSampleRate == 44100, "Got wrong sample rate: 0x%x\n", details.InputSampleRate);
-    }
-
-    memset(&buf2, 0, sizeof(buf2));
-    buf2.AudioBytes = 22050 * fmt.nBlockAlign;
-    buf2.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf2.AudioBytes);
-    fill_buf((float*)buf2.pAudioData, &fmt, 220, 22050);
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src2, &buf2, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    hr = IXAudio2SourceVoice_Start(src2, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Start failed: %08x\n", hr);
-
-    XA2CALL_0(StartEngine);
-    ok(hr == S_OK, "StartEngine failed: %08x\n", hr);
-
-    /* hook up volume meter */
-    if(xaudio27){
-        IXAPO *xapo;
-
-        hr = CoCreateInstance(&CLSID_AudioVolumeMeter27, NULL,
-                CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&vumeter);
-        ok(hr == S_OK, "CoCreateInstance(AudioVolumeMeter) failed: %08x\n", hr);
-
-        hr = IUnknown_QueryInterface(vumeter, &IID_IXAPO27, (void**)&xapo);
-        ok(hr == S_OK, "Couldn't get IXAPO27 interface: %08x\n", hr);
-        if(SUCCEEDED(hr))
-            IXAPO_Release(xapo);
-    }else{
-        IXAPO *xapo;
-
-        hr = pCreateAudioVolumeMeter(&vumeter);
-        ok(hr == S_OK, "CreateAudioVolumeMeter failed: %08x\n", hr);
-
-        hr = IUnknown_QueryInterface(vumeter, &IID_IXAPO, (void**)&xapo);
-        ok(hr == S_OK, "Couldn't get IXAPO interface: %08x\n", hr);
-        if(SUCCEEDED(hr))
-            IXAPO_Release(xapo);
-    }
-
-    effect.InitialState = TRUE;
-    effect.OutputChannels = 2;
-    effect.pEffect = vumeter;
-
-    chain.EffectCount = 1;
-    chain.pEffectDescriptors = &effect;
-
-    hr = IXAudio2MasteringVoice_SetEffectChain(master, &chain);
-    ok(hr == S_OK, "SetEffectchain failed: %08x\n", hr);
-
-    IUnknown_Release(vumeter);
-
-    while(1){
-        if(xaudio27)
-            IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state);
-        else
-            IXAudio2SourceVoice_GetState(src, &state, 0);
-        if(state.SamplesPlayed >= 22050)
-            break;
-        Sleep(100);
-    }
-
-    ok(state.SamplesPlayed == 22050, "Got wrong samples played\n");
-
-    HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData);
-    HeapFree(GetProcessHeap(), 0, (void*)buf2.pAudioData);
-
-    if(xaudio27){
-        IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src);
-        IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src2);
-    }else{
-        IXAudio2SourceVoice_DestroyVoice(src);
-        IXAudio2SourceVoice_DestroyVoice(src2);
-    }
-    IXAudio2MasteringVoice_DestroyVoice(master);
-
-    XA2CALL_V(UnregisterForCallbacks, &ecb);
-}
-
-static void WINAPI vcb_buf_OnVoiceProcessingPassStart(IXAudio2VoiceCallback *This,
-        UINT32 BytesRequired)
-{
-}
-
-static void WINAPI vcb_buf_OnVoiceProcessingPassEnd(IXAudio2VoiceCallback *This)
-{
-}
-
-static void WINAPI vcb_buf_OnStreamEnd(IXAudio2VoiceCallback *This)
-{
-    ok(0, "Unexpected OnStreamEnd\n");
-}
-
-struct vcb_buf_testdata {
-    int idx;
-    IXAudio2SourceVoice *src;
-};
-
-static int obs_calls = 0;
-static int obe_calls = 0;
-
-static void WINAPI vcb_buf_OnBufferStart(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-    struct vcb_buf_testdata *data = pBufferContext;
-    XAUDIO2_VOICE_STATE state;
-
-    ok(data->idx == obs_calls, "Buffer callback out of order: %u\n", data->idx);
-
-    if(xaudio27)
-        IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)data->src, &state);
-    else
-        IXAudio2SourceVoice_GetState(data->src, &state, 0);
-
-    ok(state.BuffersQueued == 5 - obs_calls, "Got wrong number of buffers remaining: %u\n", state.BuffersQueued);
-    ok(state.pCurrentBufferContext == pBufferContext, "Got wrong buffer from GetState\n");
-
-    ++obs_calls;
-}
-
-static void WINAPI vcb_buf_OnBufferEnd(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-    struct vcb_buf_testdata *data = pBufferContext;
-    XAUDIO2_VOICE_STATE state;
-
-    ok(data->idx == obe_calls, "Buffer callback out of order: %u\n", data->idx);
-
-    if(xaudio27)
-        IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)data->src, &state);
-    else
-        IXAudio2SourceVoice_GetState(data->src, &state, 0);
-
-    ok(state.BuffersQueued == 5 - obe_calls - 1, "Got wrong number of buffers remaining: %u\n", state.BuffersQueued);
-    if(state.BuffersQueued == 0)
-        ok(state.pCurrentBufferContext == NULL, "Got wrong buffer from GetState: %p\n", state.pCurrentBufferContext);
-    else
-        ok(state.pCurrentBufferContext == data + 1, "Got wrong buffer from GetState: %p\n", state.pCurrentBufferContext);
-
-    ++obe_calls;
-}
-
-static void WINAPI vcb_buf_OnLoopEnd(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-    ok(0, "Unexpected OnLoopEnd\n");
-}
-
-static void WINAPI vcb_buf_OnVoiceError(IXAudio2VoiceCallback *This,
-        void *pBuffercontext, HRESULT Error)
-{
-    ok(0, "Unexpected OnVoiceError\n");
-}
-
-static const IXAudio2VoiceCallbackVtbl vcb_buf_vtbl = {
-    vcb_buf_OnVoiceProcessingPassStart,
-    vcb_buf_OnVoiceProcessingPassEnd,
-    vcb_buf_OnStreamEnd,
-    vcb_buf_OnBufferStart,
-    vcb_buf_OnBufferEnd,
-    vcb_buf_OnLoopEnd,
-    vcb_buf_OnVoiceError
-};
-
-static IXAudio2VoiceCallback vcb_buf = { &vcb_buf_vtbl };
-
-static int nloopends = 0;
-static int nstreamends = 0;
-
-static void WINAPI loop_buf_OnStreamEnd(IXAudio2VoiceCallback *This)
-{
-    ++nstreamends;
-}
-
-static void WINAPI loop_buf_OnBufferStart(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-}
-
-static void WINAPI loop_buf_OnBufferEnd(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-}
-
-static void WINAPI loop_buf_OnLoopEnd(IXAudio2VoiceCallback *This,
-        void *pBufferContext)
-{
-    ++nloopends;
-}
-
-static void WINAPI loop_buf_OnVoiceError(IXAudio2VoiceCallback *This,
-        void *pBuffercontext, HRESULT Error)
-{
-}
-
-static const IXAudio2VoiceCallbackVtbl loop_buf_vtbl = {
-    vcb_buf_OnVoiceProcessingPassStart,
-    vcb_buf_OnVoiceProcessingPassEnd,
-    loop_buf_OnStreamEnd,
-    loop_buf_OnBufferStart,
-    loop_buf_OnBufferEnd,
-    loop_buf_OnLoopEnd,
-    loop_buf_OnVoiceError
-};
-
-static IXAudio2VoiceCallback loop_buf = { &loop_buf_vtbl };
-
-static void test_buffer_callbacks(IXAudio2 *xa)
-{
-    HRESULT hr;
-    IXAudio2MasteringVoice *master;
-    IXAudio2SourceVoice *src;
-    WAVEFORMATEX fmt;
-    XAUDIO2_BUFFER buf;
-    XAUDIO2_VOICE_STATE state;
-    struct vcb_buf_testdata testdata[5];
-    int i, timeout;
-
-    obs_calls = 0;
-    obe_calls = 0;
-
-    XA2CALL_0V(StopEngine);
-
-    if(xaudio27)
-        hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL);
-    else
-        hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects);
-    ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr);
-
-    /* test OnBufferStart/End callbacks */
-    fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
-    fmt.nChannels = 2;
-    fmt.nSamplesPerSec = 44100;
-    fmt.wBitsPerSample = 32;
-    fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
-    fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
-    fmt.cbSize = 0;
-
-    XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &vcb_buf, NULL, NULL);
-    ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
-
-    memset(&buf, 0, sizeof(buf));
-    buf.AudioBytes = 4410 * fmt.nBlockAlign;
-    buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes);
-    fill_buf((float*)buf.pAudioData, &fmt, 440, 4410);
-
-    /* submit same buffer fragment 5 times */
-    for(i = 0; i < 5; ++i){
-        testdata[i].idx = i;
-        testdata[i].src = src;
-        buf.pContext = &testdata[i];
-
-        hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-        ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-    }
-
-    hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Start failed: %08x\n", hr);
-
-
-    XA2CALL_0(StartEngine);
-    ok(hr == S_OK, "StartEngine failed: %08x\n", hr);
-
-    if(xaudio27){
-        hr = IXAudio27SourceVoice_SetSourceSampleRate((IXAudio27SourceVoice*)src, 48000);
-        todo_wine ok(hr == S_OK, "SetSourceSampleRate failed: %08x\n", hr);
-    }else{
-        hr = IXAudio2SourceVoice_SetSourceSampleRate(src, 48000);
-        ok(hr == XAUDIO2_E_INVALID_CALL, "SetSourceSampleRate should have failed: %08x\n", hr);
-    }
-
-    while(1){
-        if(xaudio27)
-            IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state);
-        else
-            IXAudio2SourceVoice_GetState(src, &state, 0);
-        if(state.SamplesPlayed >= 4410 * 5)
-            break;
-        Sleep(100);
-    }
-
-    ok(state.SamplesPlayed == 4410 * 5, "Got wrong samples played\n");
-
-    if(xaudio27)
-        IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src);
-    else
-        IXAudio2SourceVoice_DestroyVoice(src);
-
-
-    /* test OnStreamEnd callback */
-    XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &loop_buf, NULL, NULL);
-    ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
-
-    buf.Flags = XAUDIO2_END_OF_STREAM;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Start failed: %08x\n", hr);
-
-    timeout = 0;
-    while(nstreamends == 0 && timeout < 1000){
-        Sleep(100);
-        timeout += 100;
-    }
-
-    ok(nstreamends == 1, "Got wrong number of OnStreamEnd calls: %u\n", nstreamends);
-
-    /* xaudio resets SamplesPlayed after processing an end-of-stream buffer */
-    if(xaudio27)
-        IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state);
-    else
-        IXAudio2SourceVoice_GetState(src, &state, 0);
-    ok(state.SamplesPlayed == 0, "Got wrong samples played\n");
-
-    if(xaudio27)
-        IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src);
-    else
-        IXAudio2SourceVoice_DestroyVoice(src);
-
-
-    IXAudio2MasteringVoice_DestroyVoice(master);
-
-    HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData);
-}
-
-static UINT32 play_to_completion(IXAudio2SourceVoice *src, UINT32 max_samples)
-{
-    XAUDIO2_VOICE_STATE state;
-    HRESULT hr;
-
-    nloopends = 0;
-
-    hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Start failed: %08x\n", hr);
-
-    while(1){
-        if(xaudio27)
-            IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state);
-        else
-            IXAudio2SourceVoice_GetState(src, &state, 0);
-        if(state.BuffersQueued == 0)
-            break;
-        if(state.SamplesPlayed >= max_samples){
-            if(xaudio27)
-                IXAudio27SourceVoice_ExitLoop((IXAudio27SourceVoice*)src, XAUDIO2_COMMIT_NOW);
-            else
-                IXAudio2SourceVoice_ExitLoop(src, XAUDIO2_COMMIT_NOW);
-        }
-        Sleep(100);
-    }
-
-    hr = IXAudio2SourceVoice_Stop(src, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Start failed: %08x\n", hr);
-
-    return state.SamplesPlayed;
-}
-
-static void test_looping(IXAudio2 *xa)
-{
-    HRESULT hr;
-    IXAudio2MasteringVoice *master;
-    IXAudio2SourceVoice *src;
-    WAVEFORMATEX fmt;
-    XAUDIO2_BUFFER buf;
-    UINT32 played, running_total = 0;
-
-    XA2CALL_0V(StopEngine);
-
-    if(xaudio27)
-        hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL);
-    else
-        hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects);
-    ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr);
-
-
-    fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
-    fmt.nChannels = 2;
-    fmt.nSamplesPerSec = 44100;
-    fmt.wBitsPerSample = 32;
-    fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
-    fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
-    fmt.cbSize = 0;
-
-    XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &loop_buf, NULL, NULL);
-    ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
-
-    memset(&buf, 0, sizeof(buf));
-
-    buf.AudioBytes = 44100 * fmt.nBlockAlign;
-    buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes);
-    fill_buf((float*)buf.pAudioData, &fmt, 440, 44100);
-
-    XA2CALL_0(StartEngine);
-    ok(hr == S_OK, "StartEngine failed: %08x\n", hr);
-
-    /* play from middle to end */
-    buf.PlayBegin = 22050;
-    buf.PlayLength = 0;
-    buf.LoopBegin = 0;
-    buf.LoopLength = 0;
-    buf.LoopCount = 0;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    played = play_to_completion(src, -1);
-    ok(played - running_total == 22050, "Got wrong samples played: %u\n", played - running_total);
-    running_total = played;
-    ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends);
-
-    /* play 4410 samples from middle */
-    buf.PlayBegin = 22050;
-    buf.PlayLength = 4410;
-    buf.LoopBegin = 0;
-    buf.LoopLength = 0;
-    buf.LoopCount = 0;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    played = play_to_completion(src, -1);
-    ok(played - running_total == 4410, "Got wrong samples played: %u\n", played - running_total);
-    running_total = played;
-    ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends);
-
-    /* loop 4410 samples in middle */
-    buf.PlayBegin = 0;
-    buf.PlayLength = 0;
-    buf.LoopBegin = 22050;
-    buf.LoopLength = 4410;
-    buf.LoopCount = 1;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    played = play_to_completion(src, -1);
-    ok(played - running_total == 44100 + 4410, "Got wrong samples played: %u\n", played - running_total);
-    running_total = played;
-    ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
-
-    /* play last half, then loop the whole buffer */
-    buf.PlayBegin = 22050;
-    buf.PlayLength = 0;
-    buf.LoopBegin = 0;
-    buf.LoopLength = 0;
-    buf.LoopCount = 1;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    played = play_to_completion(src, -1);
-    ok(played - running_total == 22050 + 44100, "Got wrong samples played: %u\n", played - running_total);
-    running_total = played;
-    ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
-
-    /* play short segment from middle, loop to the beginning, and end at PlayEnd */
-    buf.PlayBegin = 22050;
-    buf.PlayLength = 4410;
-    buf.LoopBegin = 0;
-    buf.LoopLength = 0;
-    buf.LoopCount = 1;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    played = play_to_completion(src, -1);
-    ok(played - running_total == 4410 + (22050 + 4410), "Got wrong samples played: %u\n", played - running_total);
-    running_total = played;
-    ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
-
-    /* invalid: LoopEnd must be <= PlayEnd
-     * xaudio27: play until LoopEnd, loop to beginning, play until PlayEnd */
-    buf.PlayBegin = 22050;
-    buf.PlayLength = 4410;
-    buf.LoopBegin = 0;
-    buf.LoopLength = 22050 + 4410 * 2;
-    buf.LoopCount = 1;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    if(xaudio27){
-        ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-        played = play_to_completion(src, -1);
-        ok(played - running_total == 4410 + (22050 + 4410 * 2), "Got wrong samples played: %u\n", played - running_total);
-        running_total = played;
-        ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
-    }else
-        ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr);
-
-    /* invalid: LoopEnd must be within play range
-     * xaudio27: plays only play range */
-    buf.PlayBegin = 22050;
-    buf.PlayLength = 0; /* == until end of buffer */
-    buf.LoopBegin = 0;
-    buf.LoopLength = 22050;
-    buf.LoopCount = 1;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    if(xaudio27){
-        ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-        played = play_to_completion(src, -1);
-        ok(played - running_total == 22050, "Got wrong samples played: %u\n", played - running_total);
-        running_total = played;
-        ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends);
-    }else
-        ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr);
-
-    /* invalid: LoopBegin must be before PlayEnd
-     * xaudio27: crashes */
-    if(!xaudio27){
-        buf.PlayBegin = 0;
-        buf.PlayLength = 4410;
-        buf.LoopBegin = 22050;
-        buf.LoopLength = 4410;
-        buf.LoopCount = 1;
-
-        hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-        ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr);
-    }
-
-    /* infinite looping buffer */
-    buf.PlayBegin = 22050;
-    buf.PlayLength = 0;
-    buf.LoopBegin = 0;
-    buf.LoopLength = 0;
-    buf.LoopCount = 255;
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    played = play_to_completion(src, running_total + 88200);
-    ok(played - running_total == 22050 + 44100 * 2, "Got wrong samples played: %u\n", played - running_total);
-    ok(nloopends == (played - running_total) / 88200 + 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
-    running_total = played;
-
-    if(xaudio27)
-        IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src);
-    else
-        IXAudio2SourceVoice_DestroyVoice(src);
-    IXAudio2MasteringVoice_DestroyVoice(master);
-    HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData);
-}
-
-static void test_submix(IXAudio2 *xa)
-{
-    HRESULT hr;
-    IXAudio2MasteringVoice *master;
-    IXAudio2SubmixVoice *sub;
-
-    XA2CALL_0V(StopEngine);
-
-    if(xaudio27)
-        hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL);
-    else
-        hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects);
-    ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr);
-
-    XA2CALL(CreateSubmixVoice, &sub, 2, 44100, 0, 0, NULL, NULL);
-    ok(hr == S_OK, "CreateSubmixVoice failed: %08x\n", hr);
-
-    if(xaudio27){
-        XAUDIO27_VOICE_DETAILS details;
-        IXAudio27SubmixVoice_GetVoiceDetails((IXAudio27SubmixVoice*)sub, &details);
-        ok(details.CreationFlags == 0, "Got wrong flags: 0x%x\n", details.CreationFlags);
-        ok(details.InputChannels == 2, "Got wrong channel count: 0x%x\n", details.InputChannels);
-        ok(details.InputSampleRate == 44100, "Got wrong sample rate: 0x%x\n", details.InputSampleRate);
-    }else{
-        XAUDIO2_VOICE_DETAILS details;
-        IXAudio2SubmixVoice_GetVoiceDetails(sub, &details);
-        ok(details.CreationFlags == 0, "Got wrong creation flags: 0x%x\n", details.CreationFlags);
-        ok(details.ActiveFlags == 0, "Got wrong active flags: 0x%x\n", details.CreationFlags);
-        ok(details.InputChannels == 2, "Got wrong channel count: 0x%x\n", details.InputChannels);
-        ok(details.InputSampleRate == 44100, "Got wrong sample rate: 0x%x\n", details.InputSampleRate);
-    }
-
-    IXAudio2SubmixVoice_DestroyVoice(sub);
-    IXAudio2MasteringVoice_DestroyVoice(master);
-}
-
-static void test_flush(IXAudio2 *xa)
-{
-    HRESULT hr;
-    IXAudio2MasteringVoice *master;
-    IXAudio2SourceVoice *src;
-    WAVEFORMATEX fmt;
-    XAUDIO2_BUFFER buf;
-    XAUDIO2_VOICE_STATE state;
-
-    XA2CALL_0V(StopEngine);
-
-    if(xaudio27)
-        hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL);
-    else
-        hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects);
-    ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr);
-
-    fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
-    fmt.nChannels = 2;
-    fmt.nSamplesPerSec = 44100;
-    fmt.wBitsPerSample = 32;
-    fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
-    fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
-    fmt.cbSize = 0;
-
-    XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, NULL, NULL, NULL);
-    ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
-
-    memset(&buf, 0, sizeof(buf));
-    buf.AudioBytes = 22050 * fmt.nBlockAlign;
-    buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes);
-    fill_buf((float*)buf.pAudioData, &fmt, 440, 22050);
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Start failed: %08x\n", hr);
-
-    XA2CALL_0(StartEngine);
-    ok(hr == S_OK, "StartEngine failed: %08x\n", hr);
-
-    while(1){
-        if(xaudio27)
-            IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state);
-        else
-            IXAudio2SourceVoice_GetState(src, &state, 0);
-        if(state.SamplesPlayed >= 2205)
-            break;
-        Sleep(10);
-    }
-
-    hr = IXAudio2SourceVoice_Stop(src, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Stop failed: %08x\n", hr);
-
-    hr = IXAudio2SourceVoice_FlushSourceBuffers(src);
-    ok(hr == S_OK, "FlushSourceBuffers failed: %08x\n", hr);
-
-    hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "Start failed: %08x\n", hr);
-
-    Sleep(100);
-
-    hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
-    ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
-
-    if(xaudio27){
-        IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src);
-    }else{
-        IXAudio2SourceVoice_DestroyVoice(src);
-    }
-    IXAudio2MasteringVoice_DestroyVoice(master);
-
-    HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData);
-}
-
-static UINT32 test_DeviceDetails(IXAudio27 *xa)
-{
-    HRESULT hr;
-    XAUDIO2_DEVICE_DETAILS dd;
-    UINT32 count, i;
-
-    hr = IXAudio27_GetDeviceCount(xa, &count);
-    ok(hr == S_OK, "GetDeviceCount failed: %08x\n", hr);
-
-    if(count == 0)
-        return 0;
-
-    for(i = 0; i < count; ++i){
-        hr = IXAudio27_GetDeviceDetails(xa, i, &dd);
-        ok(hr == S_OK, "GetDeviceDetails failed: %08x\n", hr);
-
-        if(i == 0)
-            ok(dd.Role == GlobalDefaultDevice, "Got wrong role for index 0: 0x%x\n", dd.Role);
-        else
-            ok(dd.Role == NotDefaultDevice, "Got wrong role for index %u: 0x%x\n", i, dd.Role);
-    }
-
-    return count;
-}
-
 static void test_xapo_creation_legacy(const char *module, unsigned int version)
 {
     HANDLE xapofxdll;
@@ -952,19 +43,16 @@ static void test_xapo_creation_legacy(const char *module, unsigned int version)
     HRESULT (CDECL *pCreateFX)(REFCLSID,IUnknown**) = NULL;
 
     /* CLSIDs are the same across all versions */
-    static struct {
-        const GUID *clsid;
-        BOOL todo;
-    } const_clsids[] = {
-        { &CLSID_FXEQ27, FALSE },
-        { &CLSID_FXMasteringLimiter27, TRUE },
-        { &CLSID_FXReverb27, FALSE },
-        { &CLSID_FXEcho27, TRUE},
+    static const GUID *const_clsids[] = {
+        &CLSID_FXEQ27,
+        &CLSID_FXMasteringLimiter27,
+        &CLSID_FXReverb27,
+        &CLSID_FXEcho27,
         /* older versions of xapofx actually have support for new clsids */
-        { &CLSID_FXEQ, FALSE },
-        { &CLSID_FXMasteringLimiter, TRUE },
-        { &CLSID_FXReverb, FALSE },
-        { &CLSID_FXEcho, TRUE}
+        &CLSID_FXEQ,
+        &CLSID_FXMasteringLimiter,
+        &CLSID_FXReverb,
+        &CLSID_FXEcho
     };
 
     /* different CLSID for each version */
@@ -1005,9 +93,8 @@ static void test_xapo_creation_legacy(const char *module, unsigned int version)
 
     if(pCreateFX){
         for(i = 0; i < ARRAY_SIZE(const_clsids); ++i){
-            hr = pCreateFX(const_clsids[i].clsid, &fx_unk);
-            todo_wine_if(const_clsids[i].todo)
-                ok(hr == S_OK, "%s: CreateFX(%s) failed: %08x\n", module, wine_dbgstr_guid(const_clsids[i].clsid), hr);
+            hr = pCreateFX(const_clsids[i], &fx_unk);
+            ok(hr == S_OK, "%s: CreateFX(%s) failed: %08x\n", module, wine_dbgstr_guid(const_clsids[i]), hr);
             if(SUCCEEDED(hr)){
                 IXAPO *xapo;
                 hr = IUnknown_QueryInterface(fx_unk, &IID_IXAPO27, (void**)&xapo);
@@ -1017,7 +104,7 @@ static void test_xapo_creation_legacy(const char *module, unsigned int version)
                 IUnknown_Release(fx_unk);
             }
 
-            hr = CoCreateInstance(const_clsids[i].clsid, NULL, CLSCTX_INPROC_SERVER,
+            hr = CoCreateInstance(const_clsids[i], NULL, CLSCTX_INPROC_SERVER,
                     &IID_IUnknown, (void**)&fx_unk);
             ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance should have failed: %08x\n", hr);
             if(SUCCEEDED(hr))
@@ -1062,18 +149,15 @@ static void test_xapo_creation_modern(const char *module)
     HRESULT (WINAPI *pCAR)(IUnknown**) = NULL;
 
     /* CLSIDs are the same across all versions */
-    static struct {
-        const GUID *clsid;
-        BOOL todo;
-    } const_clsids[] = {
-        { &CLSID_FXEQ27, FALSE },
-        { &CLSID_FXMasteringLimiter27, TRUE },
-        { &CLSID_FXReverb27, FALSE },
-        { &CLSID_FXEcho27, TRUE},
-        { &CLSID_FXEQ, FALSE },
-        { &CLSID_FXMasteringLimiter, TRUE },
-        { &CLSID_FXReverb, FALSE },
-        { &CLSID_FXEcho, TRUE}
+    static const GUID *const_clsids[] = {
+        &CLSID_FXEQ27,
+        &CLSID_FXMasteringLimiter27,
+        &CLSID_FXReverb27,
+        &CLSID_FXEcho27,
+        &CLSID_FXEQ,
+        &CLSID_FXMasteringLimiter,
+        &CLSID_FXReverb,
+        &CLSID_FXEcho
     };
 
     xaudio2dll = LoadLibraryA(module);
@@ -1091,9 +175,8 @@ static void test_xapo_creation_modern(const char *module)
 
     if(pCreateFX){
         for(i = 0; i < ARRAY_SIZE(const_clsids); ++i){
-            hr = pCreateFX(const_clsids[i].clsid, &fx_unk, NULL, 0);
-            todo_wine_if(const_clsids[i].todo)
-                ok(hr == S_OK, "%s: CreateFX(%s) failed: %08x\n", module, wine_dbgstr_guid(const_clsids[i].clsid), hr);
+            hr = pCreateFX(const_clsids[i], &fx_unk, NULL, 0);
+            ok(hr == S_OK, "%s: CreateFX(%s) failed: %08x\n", module, wine_dbgstr_guid(const_clsids[i]), hr);
             if(SUCCEEDED(hr)){
                 IXAPO *xapo;
                 hr = IUnknown_QueryInterface(fx_unk, &IID_IXAPO, (void**)&xapo);
@@ -1103,7 +186,7 @@ static void test_xapo_creation_modern(const char *module)
                 IUnknown_Release(fx_unk);
             }
 
-            hr = CoCreateInstance(const_clsids[i].clsid, NULL, CLSCTX_INPROC_SERVER,
+            hr = CoCreateInstance(const_clsids[i], NULL, CLSCTX_INPROC_SERVER,
                     &IID_IUnknown, (void**)&fx_unk);
             ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance should have failed: %08x\n", hr);
             if(SUCCEEDED(hr))
@@ -1165,97 +248,12 @@ static void test_xapo_creation(void)
     test_xapo_creation_modern("xaudio2_8.dll");
 }
 
-static void test_setchannelvolumes(IXAudio2 *xa)
-{
-    HRESULT hr;
-    IXAudio2MasteringVoice *master;
-    IXAudio2SourceVoice *src_2ch, *src_8ch;
-    WAVEFORMATEX fmt_2ch, fmt_8ch;
-    float volumes[] = {0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f};
-
-    if(xaudio27)
-        hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 8, 44100, 0, 0, NULL);
-    else
-        hr = IXAudio2_CreateMasteringVoice(xa, &master, 8, 44100, 0, NULL, NULL, AudioCategory_GameEffects);
-    ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr);
-
-    fmt_2ch.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
-    fmt_2ch.nChannels = 2;
-    fmt_2ch.nSamplesPerSec = 44100;
-    fmt_2ch.wBitsPerSample = 32;
-    fmt_2ch.nBlockAlign = fmt_2ch.nChannels * fmt_2ch.wBitsPerSample / 8;
-    fmt_2ch.nAvgBytesPerSec = fmt_2ch.nSamplesPerSec * fmt_2ch.nBlockAlign;
-    fmt_2ch.cbSize = 0;
-
-    fmt_8ch.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
-    fmt_8ch.nChannels = 8;
-    fmt_8ch.nSamplesPerSec = 44100;
-    fmt_8ch.wBitsPerSample = 32;
-    fmt_8ch.nBlockAlign = fmt_8ch.nChannels * fmt_8ch.wBitsPerSample / 8;
-    fmt_8ch.nAvgBytesPerSec = fmt_8ch.nSamplesPerSec * fmt_8ch.nBlockAlign;
-    fmt_8ch.cbSize = 0;
-
-    XA2CALL(CreateSourceVoice, &src_2ch, &fmt_2ch, 0, 1.f, NULL, NULL, NULL);
-    ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
-
-    XA2CALL(CreateSourceVoice, &src_8ch, &fmt_8ch, 0, 1.f, NULL, NULL, NULL);
-    ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
-
-    hr = IXAudio2SourceVoice_SetChannelVolumes(src_2ch, 2, volumes, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "SetChannelVolumes failed: %08x\n", hr);
-
-    hr = IXAudio2SourceVoice_SetChannelVolumes(src_8ch, 8, volumes, XAUDIO2_COMMIT_NOW);
-    ok(hr == S_OK, "SetChannelVolumes failed: %08x\n", hr);
-
-    if(xaudio27){
-        /* XAudio 2.7 doesn't check the number of channels */
-        hr = IXAudio2SourceVoice_SetChannelVolumes(src_8ch, 2, volumes, XAUDIO2_COMMIT_NOW);
-        ok(hr == S_OK, "SetChannelVolumes failed: %08x\n", hr);
-    }else{
-        /* the number of channels must be the same as the number of channels on the source voice */
-        hr = IXAudio2SourceVoice_SetChannelVolumes(src_8ch, 2, volumes, XAUDIO2_COMMIT_NOW);
-        ok(hr == XAUDIO2_E_INVALID_CALL, "SetChannelVolumes should have failed: %08x\n", hr);
-
-        hr = IXAudio2SourceVoice_SetChannelVolumes(src_2ch, 8, volumes, XAUDIO2_COMMIT_NOW);
-        ok(hr == XAUDIO2_E_INVALID_CALL, "SetChannelVolumes should have failed: %08x\n", hr);
-
-        /* volumes must not be NULL, XAudio 2.7 doesn't check this */
-        hr = IXAudio2SourceVoice_SetChannelVolumes(src_2ch, 2, NULL, XAUDIO2_COMMIT_NOW);
-        ok(hr == XAUDIO2_E_INVALID_CALL, "SetChannelVolumes should have failed: %08x\n", hr);
-    }
-
-    if(xaudio27){
-        IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src_2ch);
-        IXAudio27SourceVoice_DestroyVoice((IXAudio27SourceVoice*)src_8ch);
-    }else{
-        IXAudio2SourceVoice_DestroyVoice(src_2ch);
-        IXAudio2SourceVoice_DestroyVoice(src_8ch);
-    }
-
-    IXAudio2MasteringVoice_DestroyVoice(master);
-}
-
-static UINT32 check_has_devices(IXAudio2 *xa)
-{
-    HRESULT hr;
-    IXAudio2MasteringVoice *master;
-
-    hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects);
-    if(hr != S_OK)
-        return 0;
-
-    IXAudio2MasteringVoice_DestroyVoice(master);
-
-    return 1;
-}
-
 START_TEST(xaudio2)
 {
     HRESULT hr;
     IXAudio27 *xa27 = NULL;
     IXAudio2 *xa = NULL;
     HANDLE xa28dll;
-    UINT32 has_devices;
 
     CoInitialize(NULL);
 
@@ -1276,20 +274,6 @@ START_TEST(xaudio2)
         hr = IXAudio27_QueryInterface(xa27, &IID_IXAudio28, (void**) &xa);
         ok(hr != S_OK, "QueryInterface with IID_IXAudio28 on IXAudio27 object returned success. Expected to fail\n");
 
-        hr = IXAudio27_Initialize(xa27, 0, XAUDIO2_ANY_PROCESSOR);
-        ok(hr == S_OK, "Initialize failed: %08x\n", hr);
-
-        has_devices = test_DeviceDetails(xa27);
-        if(has_devices){
-            test_simple_streaming((IXAudio2*)xa27);
-            test_buffer_callbacks((IXAudio2*)xa27);
-            test_looping((IXAudio2*)xa27);
-            test_submix((IXAudio2*)xa27);
-            test_flush((IXAudio2*)xa27);
-            test_setchannelvolumes((IXAudio2*)xa27);
-        }else
-            skip("No audio devices available\n");
-
         IXAudio27_Release(xa27);
     }else
         win_skip("XAudio 2.7 not available\n");
@@ -1304,17 +288,6 @@ START_TEST(xaudio2)
         hr = IXAudio2_QueryInterface(xa, &IID_IXAudio27, (void**)&xa27);
         ok(hr == E_NOINTERFACE, "XA28 object should support IXAudio27, gave: %08x\n", hr);
 
-        has_devices = check_has_devices(xa);
-        if(has_devices){
-            test_simple_streaming(xa);
-            test_buffer_callbacks(xa);
-            test_looping(xa);
-            test_submix(xa);
-            test_flush(xa);
-            test_setchannelvolumes(xa);
-        }else
-            skip("No audio devices available\n");
-
         IXAudio2_Release(xa);
     }else
         win_skip("XAudio 2.8 not available\n");
diff --git a/dlls/xaudio2_7/x3daudio.c b/dlls/xaudio2_7/x3daudio.c
index 58f7062ad6..ee3367e092 100644
--- a/dlls/xaudio2_7/x3daudio.c
+++ b/dlls/xaudio2_7/x3daudio.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2016 Andrew Eikum for CodeWeavers
+ * Copyright (c) 2018 Ethan Lee for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -18,11 +19,14 @@
 
 #include <stdarg.h>
 
-#include "xaudio_private.h"
+#include "windef.h"
+#include "winbase.h"
 #include "x3daudio.h"
 
 #include "wine/debug.h"
 
+#include <F3DAudio.h>
+
 #if XAUDIO2_VER >= 8 || defined X3DAUDIO1_VER
 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
 #endif
@@ -34,8 +38,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
 
     switch (reason)
     {
-    case DLL_WINE_PREATTACH:
-        return FALSE;  /* prefer native version */
     case DLL_PROCESS_ATTACH:
         DisableThreadLibraryCalls( hinstDLL );
         break;
@@ -48,7 +50,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
 HRESULT CDECL X3DAudioInitialize(UINT32 chanmask, float speedofsound,
         X3DAUDIO_HANDLE handle)
 {
-    FIXME("0x%x, %f, %p: Stub!\n", chanmask, speedofsound, handle);
+    TRACE("0x%x, %f, %p\n", chanmask, speedofsound, handle);
+    F3DAudioInitialize(chanmask, speedofsound, handle);
     return S_OK;
 }
 #endif /* XAUDIO2_VER >= 8 */
@@ -57,7 +60,8 @@ HRESULT CDECL X3DAudioInitialize(UINT32 chanmask, float speedofsound,
 void CDECL LEGACY_X3DAudioInitialize(UINT32 chanmask, float speedofsound,
         X3DAUDIO_HANDLE handle)
 {
-    FIXME("0x%x, %f, %p: Stub!\n", chanmask, speedofsound, handle);
+    TRACE("0x%x, %f, %p\n", chanmask, speedofsound, handle);
+    F3DAudioInitialize(chanmask, speedofsound, handle);
 }
 #endif /* X3DAUDIO1_VER */
 
@@ -66,19 +70,13 @@ void CDECL X3DAudioCalculate(const X3DAUDIO_HANDLE handle,
         const X3DAUDIO_LISTENER *listener, const X3DAUDIO_EMITTER *emitter,
         UINT32 flags, X3DAUDIO_DSP_SETTINGS *out)
 {
-    static int once = 0;
-    if(!once){
-        FIXME("%p %p %p 0x%x %p: Stub!\n", handle, listener, emitter, flags, out);
-        ++once;
-    }
-
-    out->LPFDirectCoefficient = 0;
-    out->LPFReverbCoefficient = 0;
-    out->ReverbLevel = 0;
-    out->DopplerFactor = 1;
-    out->EmitterToListenerAngle = 0;
-    out->EmitterToListenerDistance = 0;
-    out->EmitterVelocityComponent = 0;
-    out->ListenerVelocityComponent = 0;
+    TRACE("%p, %p, %p, 0x%x, %p\n", handle, listener, emitter, flags, out);
+    F3DAudioCalculate(
+        handle,
+        (const F3DAUDIO_LISTENER*) listener,
+        (const F3DAUDIO_EMITTER*) emitter,
+        flags,
+        (F3DAUDIO_DSP_SETTINGS*) out
+    );
 }
 #endif /* XAUDIO2_VER >= 8 || defined X3DAUDIO1_VER */
diff --git a/dlls/xaudio2_7/xapo.c b/dlls/xaudio2_7/xapo.c
new file mode 100644
index 0000000000..ccad417ea5
--- /dev/null
+++ b/dlls/xaudio2_7/xapo.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2015 Mark Harmstone
+ * Copyright (c) 2015 Andrew Eikum for CodeWeavers
+ * Copyright (c) 2018 Ethan Lee for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#define COBJMACROS
+
+#include "xaudio_private.h"
+#include "xaudio2fx.h"
+#include "xapofx.h"
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+#include <FAPO.h>
+#include <FAPOFX.h>
+#include <FAudioFX.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
+
+static XA2XAPOFXImpl *impl_from_IXAPO(IXAPO *iface)
+{
+    return CONTAINING_RECORD(iface, XA2XAPOFXImpl, IXAPO_iface);
+}
+
+static XA2XAPOFXImpl *impl_from_IXAPOParameters(IXAPOParameters *iface)
+{
+    return CONTAINING_RECORD(iface, XA2XAPOFXImpl, IXAPOParameters_iface);
+}
+
+static HRESULT WINAPI XAPOFX_QueryInterface(IXAPO *iface, REFIID riid, void **ppvObject)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+
+    TRACE("%p, %s, %p\n", This, wine_dbgstr_guid(riid), ppvObject);
+
+    if(IsEqualGUID(riid, &IID_IUnknown) ||
+            IsEqualGUID(riid, &IID_IXAPO) ||
+            IsEqualGUID(riid, &IID_IXAPO27))
+        *ppvObject = &This->IXAPO_iface;
+    else if(IsEqualGUID(riid, &IID_IXAPOParameters) ||
+            IsEqualGUID(riid, &IID_IXAPO27Parameters))
+        *ppvObject = &This->IXAPOParameters_iface;
+    else
+        *ppvObject = NULL;
+
+    if(*ppvObject){
+        IUnknown_AddRef((IUnknown*)*ppvObject);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI XAPOFX_AddRef(IXAPO *iface)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    ULONG ref = This->fapo->AddRef(This->fapo);
+    TRACE("(%p)->(): Refcount now %u\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI XAPOFX_Release(IXAPO *iface)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    ULONG ref = This->fapo->Release(This->fapo);
+
+    TRACE("(%p)->(): Refcount now %u\n", This, ref);
+
+    if(!ref)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI XAPOFX_GetRegistrationProperties(IXAPO *iface,
+    XAPO_REGISTRATION_PROPERTIES **props)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    HRESULT hr;
+    FAPORegistrationProperties *fprops;
+
+    TRACE("%p, %p\n", This, props);
+
+    hr = This->fapo->GetRegistrationProperties(This->fapo, &fprops);
+    if(FAILED(hr))
+        return hr;
+
+    /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
+    *props = (XAPO_REGISTRATION_PROPERTIES*) fprops;
+    return hr;
+}
+
+static HRESULT WINAPI XAPOFX_IsInputFormatSupported(IXAPO *iface,
+        const WAVEFORMATEX *output_fmt, const WAVEFORMATEX *input_fmt,
+        WAVEFORMATEX **supported_fmt)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p, %p, %p, %p\n", This, output_fmt, input_fmt, supported_fmt);
+    return This->fapo->IsInputFormatSupported(This->fapo,
+            (const FAudioWaveFormatEx *)output_fmt,
+            (const FAudioWaveFormatEx *)input_fmt,
+            (FAudioWaveFormatEx **)supported_fmt);
+}
+
+static HRESULT WINAPI XAPOFX_IsOutputFormatSupported(IXAPO *iface,
+        const WAVEFORMATEX *input_fmt, const WAVEFORMATEX *output_fmt,
+        WAVEFORMATEX **supported_fmt)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p, %p, %p, %p\n", This, input_fmt, output_fmt, supported_fmt);
+    return This->fapo->IsOutputFormatSupported(This->fapo,
+            (const FAudioWaveFormatEx *)input_fmt,
+            (const FAudioWaveFormatEx *)output_fmt,
+            (FAudioWaveFormatEx **)supported_fmt);
+}
+
+static HRESULT WINAPI XAPOFX_Initialize(IXAPO *iface, const void *data,
+        UINT32 data_len)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p, %p, %u\n", This, data, data_len);
+    return This->fapo->Initialize(This->fapo, data, data_len);
+}
+
+static void WINAPI XAPOFX_Reset(IXAPO *iface)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p\n", This);
+    This->fapo->Reset(This->fapo);
+}
+
+static HRESULT WINAPI XAPOFX_LockForProcess(IXAPO *iface, UINT32 in_params_count,
+        const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *in_params,
+        UINT32 out_params_count,
+        const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *out_params)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p, %u, %p, %u, %p\n", This, in_params_count, in_params,
+            out_params_count, out_params);
+    return This->fapo->LockForProcess(This->fapo,
+            in_params_count,
+            (const FAPOLockForProcessBufferParameters *)in_params,
+            out_params_count,
+            (const FAPOLockForProcessBufferParameters *)out_params);
+}
+
+static void WINAPI XAPOFX_UnlockForProcess(IXAPO *iface)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p\n", This);
+    This->fapo->UnlockForProcess(This->fapo);
+}
+
+static void WINAPI XAPOFX_Process(IXAPO *iface, UINT32 in_params_count,
+        const XAPO_PROCESS_BUFFER_PARAMETERS *in_params,
+        UINT32 out_params_count,
+        const XAPO_PROCESS_BUFFER_PARAMETERS *out_params, BOOL enabled)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p, %u, %p, %u, %p, %u\n", This, in_params_count, in_params,
+            out_params_count, out_params, enabled);
+    This->fapo->Process(This->fapo, in_params_count,
+            (const FAPOProcessBufferParameters *)in_params, out_params_count,
+            (FAPOProcessBufferParameters *)out_params, enabled);
+}
+
+static UINT32 WINAPI XAPOFX_CalcInputFrames(IXAPO *iface, UINT32 output_frames)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p, %u\n", This, output_frames);
+    return 0;
+}
+
+static UINT32 WINAPI XAPOFX_CalcOutputFrames(IXAPO *iface, UINT32 input_frames)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPO(iface);
+    TRACE("%p, %u\n", This, input_frames);
+    return 0;
+}
+
+static const IXAPOVtbl XAPOFX_Vtbl = {
+    XAPOFX_QueryInterface,
+    XAPOFX_AddRef,
+    XAPOFX_Release,
+    XAPOFX_GetRegistrationProperties,
+    XAPOFX_IsInputFormatSupported,
+    XAPOFX_IsOutputFormatSupported,
+    XAPOFX_Initialize,
+    XAPOFX_Reset,
+    XAPOFX_LockForProcess,
+    XAPOFX_UnlockForProcess,
+    XAPOFX_Process,
+    XAPOFX_CalcInputFrames,
+    XAPOFX_CalcOutputFrames
+};
+
+static HRESULT WINAPI XAPOFXParams_QueryInterface(IXAPOParameters *iface,
+        REFIID riid, void **ppvObject)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPOParameters(iface);
+    return XAPOFX_QueryInterface(&This->IXAPO_iface, riid, ppvObject);
+}
+
+static ULONG WINAPI XAPOFXParams_AddRef(IXAPOParameters *iface)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPOParameters(iface);
+    return XAPOFX_AddRef(&This->IXAPO_iface);
+}
+
+static ULONG WINAPI XAPOFXParams_Release(IXAPOParameters *iface)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPOParameters(iface);
+    return XAPOFX_Release(&This->IXAPO_iface);
+}
+
+static void WINAPI XAPOFXParams_SetParameters(IXAPOParameters *iface,
+        const void *params, UINT32 params_len)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPOParameters(iface);
+    TRACE("%p, %p, %u\n", This, params, params_len);
+    This->fapo->SetParameters(This->fapo, params, params_len);
+}
+
+static void WINAPI XAPOFXParams_GetParameters(IXAPOParameters *iface, void *params,
+        UINT32 params_len)
+{
+    XA2XAPOFXImpl *This = impl_from_IXAPOParameters(iface);
+    TRACE("%p, %p, %u\n", This, params, params_len);
+    This->fapo->GetParameters(This->fapo, params, params_len);
+}
+
+static const IXAPOParametersVtbl XAPOFXParameters_Vtbl = {
+    XAPOFXParams_QueryInterface,
+    XAPOFXParams_AddRef,
+    XAPOFXParams_Release,
+    XAPOFXParams_SetParameters,
+    XAPOFXParams_GetParameters
+};
+
+struct xapo_cf {
+    IClassFactory IClassFactory_iface;
+    LONG ref;
+    const CLSID *class;
+};
+
+static struct xapo_cf *xapo_impl_from_IClassFactory(IClassFactory *iface)
+{
+    return CONTAINING_RECORD(iface, struct xapo_cf, IClassFactory_iface);
+}
+
+static HRESULT WINAPI xapocf_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
+{
+    if(IsEqualGUID(riid, &IID_IUnknown)
+            || IsEqualGUID(riid, &IID_IClassFactory))
+    {
+        IClassFactory_AddRef(iface);
+        *ppobj = iface;
+        return S_OK;
+    }
+
+    *ppobj = NULL;
+    WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI xapocf_AddRef(IClassFactory *iface)
+{
+    struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+    TRACE("(%p)->(): Refcount now %u\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI xapocf_Release(IClassFactory *iface)
+{
+    struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+    TRACE("(%p)->(): Refcount now %u\n", This, ref);
+    if (!ref)
+        HeapFree(GetProcessHeap(), 0, This);
+    return ref;
+}
+
+static inline HRESULT get_fapo_from_clsid(REFCLSID clsid, FAPO **fapo)
+{
+#ifndef XAPOFX1_VER
+    if(IsEqualGUID(clsid, &CLSID_AudioVolumeMeter27))
+        return FAudioCreateVolumeMeterWithCustomAllocatorEXT(
+            fapo,
+            0,
+            XAudio_Internal_Malloc,
+            XAudio_Internal_Free,
+            XAudio_Internal_Realloc
+        );
+    if(IsEqualGUID(clsid, &CLSID_AudioReverb27))
+        return FAudioCreateReverbWithCustomAllocatorEXT(
+            fapo,
+            0,
+            XAudio_Internal_Malloc,
+            XAudio_Internal_Free,
+            XAudio_Internal_Realloc
+        );
+#endif
+#if XAUDIO2_VER >= 8 || defined XAPOFX1_VER
+    if(IsEqualGUID(clsid, &CLSID_FXReverb) ||
+            IsEqualGUID(clsid, &CLSID_FXEQ) ||
+            IsEqualGUID(clsid, &CLSID_FXEcho) ||
+            IsEqualGUID(clsid, &CLSID_FXMasteringLimiter))
+        return FAPOFX_CreateFXWithCustomAllocatorEXT(
+            (const FAudioGUID*) clsid,
+            fapo,
+            NULL,
+            0,
+            XAudio_Internal_Malloc,
+            XAudio_Internal_Free,
+            XAudio_Internal_Realloc
+        );
+#endif
+    ERR("Invalid XAPO CLSID!");
+    return E_INVALIDARG;
+}
+
+static HRESULT WINAPI xapocf_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
+        REFIID riid, void **ppobj)
+{
+    struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
+    HRESULT hr;
+    XA2XAPOFXImpl *object;
+
+    TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
+
+    *ppobj = NULL;
+
+    if(pOuter)
+        return CLASS_E_NOAGGREGATION;
+
+    object = heap_alloc(sizeof(*object));
+    object->IXAPO_iface.lpVtbl = &XAPOFX_Vtbl;
+    object->IXAPOParameters_iface.lpVtbl = &XAPOFXParameters_Vtbl;
+
+    hr = get_fapo_from_clsid(This->class, &object->fapo);
+
+    if(FAILED(hr)){
+        HeapFree(GetProcessHeap(), 0, object);
+        return hr;
+    }
+
+    hr = IXAPO_QueryInterface(&object->IXAPO_iface, riid, ppobj);
+    if(FAILED(hr)){
+        HeapFree(GetProcessHeap(), 0, object);
+        return hr;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI xapocf_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
+    FIXME("(%p)->(%d): stub!\n", This, dolock);
+    return S_OK;
+}
+
+static const IClassFactoryVtbl xapo_Vtbl =
+{
+    xapocf_QueryInterface,
+    xapocf_AddRef,
+    xapocf_Release,
+    xapocf_CreateInstance,
+    xapocf_LockServer
+};
+
+HRESULT make_xapo_factory(REFCLSID clsid, REFIID riid, void **ppv)
+{
+    HRESULT hr;
+    struct xapo_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xapo_cf));
+    ret->IClassFactory_iface.lpVtbl = &xapo_Vtbl;
+    ret->class = clsid;
+    ret->ref = 0;
+    hr = IClassFactory_QueryInterface(&ret->IClassFactory_iface, riid, ppv);
+    if(FAILED(hr))
+        HeapFree(GetProcessHeap(), 0, ret);
+    return hr;
+}
diff --git a/dlls/xaudio2_7/xapofx.c b/dlls/xaudio2_7/xapofx.c
index e450851b25..100ba02d3b 100644
--- a/dlls/xaudio2_7/xapofx.c
+++ b/dlls/xaudio2_7/xapofx.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015 Andrew Eikum for CodeWeavers
+ * Copyright (c) 2018 Ethan Lee for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,13 +24,17 @@
 #define NONAMELESSUNION
 #define COBJMACROS
 
+#ifdef XAPOFX1_VER
 #include "initguid.h"
+#endif /* XAPOFX1_VER */
 #include "xaudio_private.h"
 #include "xapofx.h"
 
 #include "wine/debug.h"
 
+#if XAUDIO2_VER >= 8 || defined XAPOFX1_VER
 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
+#endif
 
 #ifdef XAPOFX1_VER
 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
@@ -38,8 +43,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
 
     switch (reason)
     {
-    case DLL_WINE_PREATTACH:
-        return FALSE;  /* prefer native version */
     case DLL_PROCESS_ATTACH:
         DisableThreadLibraryCalls( hinstDLL );
         break;
@@ -48,779 +51,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
 }
 #endif /* XAPOFX1_VER */
 
-typedef struct _VUMeterImpl {
-    IXAPO IXAPO_iface;
-    IXAPOParameters IXAPOParameters_iface;
-
-    LONG ref;
-} VUMeterImpl;
-
-static VUMeterImpl *VUMeterImpl_from_IXAPO(IXAPO *iface)
-{
-    return CONTAINING_RECORD(iface, VUMeterImpl, IXAPO_iface);
-}
-
-static VUMeterImpl *VUMeterImpl_from_IXAPOParameters(IXAPOParameters *iface)
-{
-    return CONTAINING_RECORD(iface, VUMeterImpl, IXAPOParameters_iface);
-}
-
-static HRESULT WINAPI VUMXAPO_QueryInterface(IXAPO *iface, REFIID riid,
-        void **ppvObject)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-
-    TRACE("%p, %s, %p\n", This, wine_dbgstr_guid(riid), ppvObject);
-
-    if(IsEqualGUID(riid, &IID_IUnknown) ||
-            IsEqualGUID(riid, &IID_IXAPO) ||
-            IsEqualGUID(riid, &IID_IXAPO27))
-        *ppvObject = &This->IXAPO_iface;
-    else if(IsEqualGUID(riid, &IID_IXAPOParameters))
-        *ppvObject = &This->IXAPOParameters_iface;
-    else
-        *ppvObject = NULL;
-
-    if(*ppvObject){
-        IUnknown_AddRef((IUnknown*)*ppvObject);
-        return S_OK;
-    }
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI VUMXAPO_AddRef(IXAPO *iface)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
-    TRACE("(%p)->(): Refcount now %u\n", This, ref);
-    return ref;
-}
-
-static ULONG WINAPI VUMXAPO_Release(IXAPO *iface)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p)->(): Refcount now %u\n", This, ref);
-
-    if(!ref)
-        HeapFree(GetProcessHeap(), 0, This);
-
-    return ref;
-}
-
-static HRESULT WINAPI VUMXAPO_GetRegistrationProperties(IXAPO *iface,
-    XAPO_REGISTRATION_PROPERTIES **props)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p, %p\n", This, props);
-    /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI VUMXAPO_IsInputFormatSupported(IXAPO *iface,
-        const WAVEFORMATEX *output_fmt, const WAVEFORMATEX *input_fmt,
-        WAVEFORMATEX **supported_fmt)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %p, %p\n", This, output_fmt, input_fmt, supported_fmt);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI VUMXAPO_IsOutputFormatSupported(IXAPO *iface,
-        const WAVEFORMATEX *input_fmt, const WAVEFORMATEX *output_fmt,
-        WAVEFORMATEX **supported_fmt)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %p, %p\n", This, input_fmt, output_fmt, supported_fmt);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI VUMXAPO_Initialize(IXAPO *iface, const void *data,
-        UINT32 data_len)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %u\n", This, data, data_len);
-    return E_NOTIMPL;
-}
-
-static void WINAPI VUMXAPO_Reset(IXAPO *iface)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p\n", This);
-}
-
-static HRESULT WINAPI VUMXAPO_LockForProcess(IXAPO *iface,
-        UINT32 in_params_count,
-        const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *in_params,
-        UINT32 out_params_count,
-        const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *out_params)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p, %u, %p, %u, %p\n", This, in_params_count, in_params,
-            out_params_count, out_params);
-    return E_NOTIMPL;
-}
-
-static void WINAPI VUMXAPO_UnlockForProcess(IXAPO *iface)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p\n", This);
-}
-
-static void WINAPI VUMXAPO_Process(IXAPO *iface, UINT32 in_params_count,
-        const XAPO_PROCESS_BUFFER_PARAMETERS *in_params,
-        UINT32 out_params_count,
-        const XAPO_PROCESS_BUFFER_PARAMETERS *out_params, BOOL enabled)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p, %u, %p, %u, %p, %u\n", This, in_params_count, in_params,
-            out_params_count, out_params, enabled);
-}
-
-static UINT32 WINAPI VUMXAPO_CalcInputFrames(IXAPO *iface, UINT32 output_frames)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p, %u\n", This, output_frames);
-    return 0;
-}
-
-static UINT32 WINAPI VUMXAPO_CalcOutputFrames(IXAPO *iface, UINT32 input_frames)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
-    TRACE("%p, %u\n", This, input_frames);
-    return 0;
-}
-
-static const IXAPOVtbl VUMXAPO_Vtbl = {
-    VUMXAPO_QueryInterface,
-    VUMXAPO_AddRef,
-    VUMXAPO_Release,
-    VUMXAPO_GetRegistrationProperties,
-    VUMXAPO_IsInputFormatSupported,
-    VUMXAPO_IsOutputFormatSupported,
-    VUMXAPO_Initialize,
-    VUMXAPO_Reset,
-    VUMXAPO_LockForProcess,
-    VUMXAPO_UnlockForProcess,
-    VUMXAPO_Process,
-    VUMXAPO_CalcInputFrames,
-    VUMXAPO_CalcOutputFrames
-};
-
-static HRESULT WINAPI VUMXAPOParams_QueryInterface(IXAPOParameters *iface,
-        REFIID riid, void **ppvObject)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
-    return VUMXAPO_QueryInterface(&This->IXAPO_iface, riid, ppvObject);
-}
-
-static ULONG WINAPI VUMXAPOParams_AddRef(IXAPOParameters *iface)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
-    return VUMXAPO_AddRef(&This->IXAPO_iface);
-}
-
-static ULONG WINAPI VUMXAPOParams_Release(IXAPOParameters *iface)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
-    return VUMXAPO_Release(&This->IXAPO_iface);
-}
-
-static void WINAPI VUMXAPOParams_SetParameters(IXAPOParameters *iface,
-        const void *params, UINT32 params_len)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
-    TRACE("%p, %p, %u\n", This, params, params_len);
-}
-
-static void WINAPI VUMXAPOParams_GetParameters(IXAPOParameters *iface,
-        void *params, UINT32 params_len)
-{
-    VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
-    TRACE("%p, %p, %u\n", This, params, params_len);
-}
-
-static const IXAPOParametersVtbl VUMXAPOParameters_Vtbl = {
-    VUMXAPOParams_QueryInterface,
-    VUMXAPOParams_AddRef,
-    VUMXAPOParams_Release,
-    VUMXAPOParams_SetParameters,
-    VUMXAPOParams_GetParameters
-};
-
-typedef struct _ReverbImpl {
-    IXAPO IXAPO_iface;
-    IXAPOParameters IXAPOParameters_iface;
-
-    LONG ref;
-} ReverbImpl;
-
-static ReverbImpl *ReverbImpl_from_IXAPO(IXAPO *iface)
-{
-    return CONTAINING_RECORD(iface, ReverbImpl, IXAPO_iface);
-}
-
-static ReverbImpl *ReverbImpl_from_IXAPOParameters(IXAPOParameters *iface)
-{
-    return CONTAINING_RECORD(iface, ReverbImpl, IXAPOParameters_iface);
-}
-
-static HRESULT WINAPI RVBXAPO_QueryInterface(IXAPO *iface, REFIID riid, void **ppvObject)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-
-    TRACE("%p, %s, %p\n", This, wine_dbgstr_guid(riid), ppvObject);
-
-    if(IsEqualGUID(riid, &IID_IUnknown) ||
-            IsEqualGUID(riid, &IID_IXAPO) ||
-            IsEqualGUID(riid, &IID_IXAPO27))
-        *ppvObject = &This->IXAPO_iface;
-    else if(IsEqualGUID(riid, &IID_IXAPOParameters))
-        *ppvObject = &This->IXAPOParameters_iface;
-    else
-        *ppvObject = NULL;
-
-    if(*ppvObject){
-        IUnknown_AddRef((IUnknown*)*ppvObject);
-        return S_OK;
-    }
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI RVBXAPO_AddRef(IXAPO *iface)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
-    TRACE("(%p)->(): Refcount now %u\n", This, ref);
-    return ref;
-}
-
-static ULONG WINAPI RVBXAPO_Release(IXAPO *iface)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p)->(): Refcount now %u\n", This, ref);
-
-    if(!ref)
-        HeapFree(GetProcessHeap(), 0, This);
-
-    return ref;
-}
-
-static HRESULT WINAPI RVBXAPO_GetRegistrationProperties(IXAPO *iface,
-    XAPO_REGISTRATION_PROPERTIES **props)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p, %p\n", This, props);
-    /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI RVBXAPO_IsInputFormatSupported(IXAPO *iface,
-        const WAVEFORMATEX *output_fmt, const WAVEFORMATEX *input_fmt,
-        WAVEFORMATEX **supported_fmt)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %p, %p\n", This, output_fmt, input_fmt, supported_fmt);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI RVBXAPO_IsOutputFormatSupported(IXAPO *iface,
-        const WAVEFORMATEX *input_fmt, const WAVEFORMATEX *output_fmt,
-        WAVEFORMATEX **supported_fmt)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %p, %p\n", This, input_fmt, output_fmt, supported_fmt);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI RVBXAPO_Initialize(IXAPO *iface, const void *data,
-        UINT32 data_len)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %u\n", This, data, data_len);
-    return E_NOTIMPL;
-}
-
-static void WINAPI RVBXAPO_Reset(IXAPO *iface)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p\n", This);
-}
-
-static HRESULT WINAPI RVBXAPO_LockForProcess(IXAPO *iface, UINT32 in_params_count,
-        const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *in_params,
-        UINT32 out_params_count,
-        const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *out_params)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p, %u, %p, %u, %p\n", This, in_params_count, in_params,
-            out_params_count, out_params);
-    return E_NOTIMPL;
-}
-
-static void WINAPI RVBXAPO_UnlockForProcess(IXAPO *iface)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p\n", This);
-}
-
-static void WINAPI RVBXAPO_Process(IXAPO *iface, UINT32 in_params_count,
-        const XAPO_PROCESS_BUFFER_PARAMETERS *in_params,
-        UINT32 out_params_count,
-        const XAPO_PROCESS_BUFFER_PARAMETERS *out_params, BOOL enabled)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p, %u, %p, %u, %p, %u\n", This, in_params_count, in_params,
-            out_params_count, out_params, enabled);
-}
-
-static UINT32 WINAPI RVBXAPO_CalcInputFrames(IXAPO *iface, UINT32 output_frames)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p, %u\n", This, output_frames);
-    return 0;
-}
-
-static UINT32 WINAPI RVBXAPO_CalcOutputFrames(IXAPO *iface, UINT32 input_frames)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
-    TRACE("%p, %u\n", This, input_frames);
-    return 0;
-}
-
-static const IXAPOVtbl RVBXAPO_Vtbl = {
-    RVBXAPO_QueryInterface,
-    RVBXAPO_AddRef,
-    RVBXAPO_Release,
-    RVBXAPO_GetRegistrationProperties,
-    RVBXAPO_IsInputFormatSupported,
-    RVBXAPO_IsOutputFormatSupported,
-    RVBXAPO_Initialize,
-    RVBXAPO_Reset,
-    RVBXAPO_LockForProcess,
-    RVBXAPO_UnlockForProcess,
-    RVBXAPO_Process,
-    RVBXAPO_CalcInputFrames,
-    RVBXAPO_CalcOutputFrames
-};
-
-static HRESULT WINAPI RVBXAPOParams_QueryInterface(IXAPOParameters *iface,
-        REFIID riid, void **ppvObject)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
-    return RVBXAPO_QueryInterface(&This->IXAPO_iface, riid, ppvObject);
-}
-
-static ULONG WINAPI RVBXAPOParams_AddRef(IXAPOParameters *iface)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
-    return RVBXAPO_AddRef(&This->IXAPO_iface);
-}
-
-static ULONG WINAPI RVBXAPOParams_Release(IXAPOParameters *iface)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
-    return RVBXAPO_Release(&This->IXAPO_iface);
-}
-
-static void WINAPI RVBXAPOParams_SetParameters(IXAPOParameters *iface,
-        const void *params, UINT32 params_len)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
-    TRACE("%p, %p, %u\n", This, params, params_len);
-}
-
-static void WINAPI RVBXAPOParams_GetParameters(IXAPOParameters *iface, void *params,
-        UINT32 params_len)
-{
-    ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
-    TRACE("%p, %p, %u\n", This, params, params_len);
-}
-
-static const IXAPOParametersVtbl RVBXAPOParameters_Vtbl = {
-    RVBXAPOParams_QueryInterface,
-    RVBXAPOParams_AddRef,
-    RVBXAPOParams_Release,
-    RVBXAPOParams_SetParameters,
-    RVBXAPOParams_GetParameters
-};
-
-typedef struct _EQImpl {
-    IXAPO IXAPO_iface;
-    IXAPOParameters IXAPOParameters_iface;
-
-    LONG ref;
-} EQImpl;
-
-static EQImpl *EQImpl_from_IXAPO(IXAPO *iface)
-{
-    return CONTAINING_RECORD(iface, EQImpl, IXAPO_iface);
-}
-
-static EQImpl *EQImpl_from_IXAPOParameters(IXAPOParameters *iface)
-{
-    return CONTAINING_RECORD(iface, EQImpl, IXAPOParameters_iface);
-}
-
-static HRESULT WINAPI EQXAPO_QueryInterface(IXAPO *iface, REFIID riid, void **ppvObject)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-
-    TRACE("%p, %s, %p\n", This, wine_dbgstr_guid(riid), ppvObject);
-
-    if(IsEqualGUID(riid, &IID_IUnknown) ||
-            IsEqualGUID(riid, &IID_IXAPO) ||
-            IsEqualGUID(riid, &IID_IXAPO27))
-        *ppvObject = &This->IXAPO_iface;
-    else if(IsEqualGUID(riid, &IID_IXAPOParameters))
-        *ppvObject = &This->IXAPOParameters_iface;
-    else
-        *ppvObject = NULL;
-
-    if(*ppvObject){
-        IUnknown_AddRef((IUnknown*)*ppvObject);
-        return S_OK;
-    }
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI EQXAPO_AddRef(IXAPO *iface)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
-    TRACE("(%p)->(): Refcount now %u\n", This, ref);
-    return ref;
-}
-
-static ULONG WINAPI EQXAPO_Release(IXAPO *iface)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p)->(): Refcount now %u\n", This, ref);
-
-    if(!ref)
-        HeapFree(GetProcessHeap(), 0, This);
-
-    return ref;
-}
-
-static HRESULT WINAPI EQXAPO_GetRegistrationProperties(IXAPO *iface,
-    XAPO_REGISTRATION_PROPERTIES **props)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p, %p\n", This, props);
-    /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI EQXAPO_IsInputFormatSupported(IXAPO *iface,
-        const WAVEFORMATEX *output_fmt, const WAVEFORMATEX *input_fmt,
-        WAVEFORMATEX **supported_fmt)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %p, %p\n", This, output_fmt, input_fmt, supported_fmt);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI EQXAPO_IsOutputFormatSupported(IXAPO *iface,
-        const WAVEFORMATEX *input_fmt, const WAVEFORMATEX *output_fmt,
-        WAVEFORMATEX **supported_fmt)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %p, %p\n", This, input_fmt, output_fmt, supported_fmt);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI EQXAPO_Initialize(IXAPO *iface, const void *data,
-        UINT32 data_len)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p, %p, %u\n", This, data, data_len);
-    return E_NOTIMPL;
-}
-
-static void WINAPI EQXAPO_Reset(IXAPO *iface)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p\n", This);
-}
-
-static HRESULT WINAPI EQXAPO_LockForProcess(IXAPO *iface, UINT32 in_params_count,
-        const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *in_params,
-        UINT32 out_params_count,
-        const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *out_params)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p, %u, %p, %u, %p\n", This, in_params_count, in_params,
-            out_params_count, out_params);
-    return E_NOTIMPL;
-}
-
-static void WINAPI EQXAPO_UnlockForProcess(IXAPO *iface)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p\n", This);
-}
-
-static void WINAPI EQXAPO_Process(IXAPO *iface, UINT32 in_params_count,
-        const XAPO_PROCESS_BUFFER_PARAMETERS *in_params,
-        UINT32 out_params_count,
-        const XAPO_PROCESS_BUFFER_PARAMETERS *out_params, BOOL enabled)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p, %u, %p, %u, %p, %u\n", This, in_params_count, in_params,
-            out_params_count, out_params, enabled);
-}
-
-static UINT32 WINAPI EQXAPO_CalcInputFrames(IXAPO *iface, UINT32 output_frames)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p, %u\n", This, output_frames);
-    return 0;
-}
-
-static UINT32 WINAPI EQXAPO_CalcOutputFrames(IXAPO *iface, UINT32 input_frames)
-{
-    EQImpl *This = EQImpl_from_IXAPO(iface);
-    TRACE("%p, %u\n", This, input_frames);
-    return 0;
-}
-
-static const IXAPOVtbl EQXAPO_Vtbl = {
-    EQXAPO_QueryInterface,
-    EQXAPO_AddRef,
-    EQXAPO_Release,
-    EQXAPO_GetRegistrationProperties,
-    EQXAPO_IsInputFormatSupported,
-    EQXAPO_IsOutputFormatSupported,
-    EQXAPO_Initialize,
-    EQXAPO_Reset,
-    EQXAPO_LockForProcess,
-    EQXAPO_UnlockForProcess,
-    EQXAPO_Process,
-    EQXAPO_CalcInputFrames,
-    EQXAPO_CalcOutputFrames
-};
-
-static HRESULT WINAPI EQXAPOParams_QueryInterface(IXAPOParameters *iface,
-        REFIID riid, void **ppvObject)
-{
-    EQImpl *This = EQImpl_from_IXAPOParameters(iface);
-    return EQXAPO_QueryInterface(&This->IXAPO_iface, riid, ppvObject);
-}
-
-static ULONG WINAPI EQXAPOParams_AddRef(IXAPOParameters *iface)
-{
-    EQImpl *This = EQImpl_from_IXAPOParameters(iface);
-    return EQXAPO_AddRef(&This->IXAPO_iface);
-}
-
-static ULONG WINAPI EQXAPOParams_Release(IXAPOParameters *iface)
-{
-    EQImpl *This = EQImpl_from_IXAPOParameters(iface);
-    return EQXAPO_Release(&This->IXAPO_iface);
-}
-
-static void WINAPI EQXAPOParams_SetParameters(IXAPOParameters *iface,
-        const void *params, UINT32 params_len)
-{
-    EQImpl *This = EQImpl_from_IXAPOParameters(iface);
-    TRACE("%p, %p, %u\n", This, params, params_len);
-}
-
-static void WINAPI EQXAPOParams_GetParameters(IXAPOParameters *iface, void *params,
-        UINT32 params_len)
-{
-    EQImpl *This = EQImpl_from_IXAPOParameters(iface);
-    TRACE("%p, %p, %u\n", This, params, params_len);
-}
-
-static const IXAPOParametersVtbl EQXAPOParameters_Vtbl = {
-    EQXAPOParams_QueryInterface,
-    EQXAPOParams_AddRef,
-    EQXAPOParams_Release,
-    EQXAPOParams_SetParameters,
-    EQXAPOParams_GetParameters
-};
-
-struct xapo_cf {
-    IClassFactory IClassFactory_iface;
-    LONG ref;
-    const CLSID *class;
-};
-
-static struct xapo_cf *xapo_impl_from_IClassFactory(IClassFactory *iface)
-{
-    return CONTAINING_RECORD(iface, struct xapo_cf, IClassFactory_iface);
-}
-
-static HRESULT WINAPI xapocf_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
-{
-    if(IsEqualGUID(riid, &IID_IUnknown)
-            || IsEqualGUID(riid, &IID_IClassFactory))
-    {
-        IClassFactory_AddRef(iface);
-        *ppobj = iface;
-        return S_OK;
-    }
-
-    *ppobj = NULL;
-    WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj);
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI xapocf_AddRef(IClassFactory *iface)
-{
-    struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
-    TRACE("(%p)->(): Refcount now %u\n", This, ref);
-    return ref;
-}
-
-static ULONG WINAPI xapocf_Release(IClassFactory *iface)
-{
-    struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
-    TRACE("(%p)->(): Refcount now %u\n", This, ref);
-    if (!ref)
-        HeapFree(GetProcessHeap(), 0, This);
-    return ref;
-}
-
-static HRESULT WINAPI xapocf_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
-        REFIID riid, void **ppobj)
-{
-    struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
-    HRESULT hr;
-
-    TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
-
-    *ppobj = NULL;
-
-    if(pOuter)
-        return CLASS_E_NOAGGREGATION;
-
-    if(IsEqualGUID(This->class, &CLSID_AudioVolumeMeter27)){
-        VUMeterImpl *object;
-
-        object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
-        if(!object)
-            return E_OUTOFMEMORY;
-
-        object->IXAPO_iface.lpVtbl = &VUMXAPO_Vtbl;
-        object->IXAPOParameters_iface.lpVtbl = &VUMXAPOParameters_Vtbl;
-
-        hr = IXAPO_QueryInterface(&object->IXAPO_iface, riid, ppobj);
-        if(FAILED(hr)){
-            HeapFree(GetProcessHeap(), 0, object);
-            return hr;
-        }
-    }else if(IsEqualGUID(This->class, &CLSID_FXReverb)){
-        ReverbImpl *object;
-
-        object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
-        if(!object)
-            return E_OUTOFMEMORY;
-
-        object->IXAPO_iface.lpVtbl = &RVBXAPO_Vtbl;
-        object->IXAPOParameters_iface.lpVtbl = &RVBXAPOParameters_Vtbl;
-
-        hr = IXAPO_QueryInterface(&object->IXAPO_iface, riid, ppobj);
-        if(FAILED(hr)){
-            HeapFree(GetProcessHeap(), 0, object);
-            return hr;
-        }
-    }else if(IsEqualGUID(This->class, &CLSID_FXEQ)){
-        EQImpl *object;
-
-        object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
-        if(!object)
-            return E_OUTOFMEMORY;
-
-        object->IXAPO_iface.lpVtbl = &EQXAPO_Vtbl;
-        object->IXAPOParameters_iface.lpVtbl = &EQXAPOParameters_Vtbl;
-
-        hr = IXAPO_QueryInterface(&object->IXAPO_iface, riid, ppobj);
-        if(FAILED(hr)){
-            HeapFree(GetProcessHeap(), 0, object);
-            return hr;
-        }
-    }else
-        /* TODO FXECHO, FXMasteringLimiter, */
-        return E_INVALIDARG;
-
-    return S_OK;
-}
-
-static HRESULT WINAPI xapocf_LockServer(IClassFactory *iface, BOOL dolock)
-{
-    struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
-    FIXME("(%p)->(%d): stub!\n", This, dolock);
-    return S_OK;
-}
-
-static const IClassFactoryVtbl xapo_Vtbl =
-{
-    xapocf_QueryInterface,
-    xapocf_AddRef,
-    xapocf_Release,
-    xapocf_CreateInstance,
-    xapocf_LockServer
-};
-
-HRESULT make_xapo_factory(REFCLSID clsid, REFIID riid, void **ppv)
-{
-    HRESULT hr;
-    struct xapo_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xapo_cf));
-    ret->IClassFactory_iface.lpVtbl = &xapo_Vtbl;
-    ret->class = clsid;
-    ret->ref = 0;
-    hr = IClassFactory_QueryInterface(&ret->IClassFactory_iface, riid, ppv);
-    if(FAILED(hr))
-        HeapFree(GetProcessHeap(), 0, ret);
-    return hr;
-}
-
 #if XAUDIO2_VER >= 8
-HRESULT WINAPI CreateAudioVolumeMeter(IUnknown **out)
-{
-    IClassFactory *cf;
-    HRESULT hr;
-
-    hr = make_xapo_factory(&CLSID_AudioVolumeMeter27, &IID_IClassFactory, (void**)&cf);
-    if(FAILED(hr))
-        return hr;
-
-    hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)out);
-
-    IClassFactory_Release(cf);
-
-    return hr;
-}
-
-HRESULT WINAPI CreateAudioReverb(IUnknown **out)
-{
-    IClassFactory *cf;
-    HRESULT hr;
-
-    hr = make_xapo_factory(&CLSID_FXReverb, &IID_IClassFactory, (void**)&cf);
-    if(FAILED(hr))
-        return hr;
-
-    hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)out);
-
-    IClassFactory_Release(cf);
-
-    return hr;
-}
-
 HRESULT CDECL CreateFX(REFCLSID clsid, IUnknown **out, void *initdata, UINT32 initdata_bytes)
 {
     HRESULT hr;
@@ -836,6 +67,12 @@ HRESULT CDECL CreateFX(REFCLSID clsid, IUnknown **out, void *initdata, UINT32 in
     else if(IsEqualGUID(clsid, &CLSID_FXEQ27) ||
             IsEqualGUID(clsid, &CLSID_FXEQ))
         class = &CLSID_FXEQ;
+    else if(IsEqualGUID(clsid, &CLSID_FXEcho27) ||
+            IsEqualGUID(clsid, &CLSID_FXEcho))
+        class = &CLSID_FXEcho;
+    else if(IsEqualGUID(clsid, &CLSID_FXMasteringLimiter27) ||
+            IsEqualGUID(clsid, &CLSID_FXMasteringLimiter))
+        class = &CLSID_FXMasteringLimiter;
 
     if(class){
         hr = make_xapo_factory(class, &IID_IClassFactory, (void**)&cf);
@@ -895,7 +132,12 @@ HRESULT CDECL CreateFX(REFCLSID clsid, IUnknown **out)
     else if(IsEqualGUID(clsid, &CLSID_FXEQ27) ||
             IsEqualGUID(clsid, &CLSID_FXEQ))
         class = &CLSID_FXEQ;
-    /* TODO FXECHO, FXMasteringLimiter, */
+    else if(IsEqualGUID(clsid, &CLSID_FXEcho27) ||
+            IsEqualGUID(clsid, &CLSID_FXEcho))
+        class = &CLSID_FXEcho;
+    else if(IsEqualGUID(clsid, &CLSID_FXMasteringLimiter27) ||
+            IsEqualGUID(clsid, &CLSID_FXMasteringLimiter))
+        class = &CLSID_FXMasteringLimiter;
 
     if(class){
         hr = make_xapo_factory(class, &IID_IClassFactory, (void**)&cf);
diff --git a/dlls/xaudio2_7/xaudio_allocator.c b/dlls/xaudio2_7/xaudio_allocator.c
new file mode 100644
index 0000000000..41be48a80f
--- /dev/null
+++ b/dlls/xaudio2_7/xaudio_allocator.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Ethan Lee for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#define COBJMACROS
+
+#include "ole2.h"
+
+void* XAudio_Internal_Malloc(size_t size)
+{
+    return CoTaskMemAlloc(size);
+}
+
+void XAudio_Internal_Free(void* ptr)
+{
+    return CoTaskMemFree(ptr);
+}
+
+void* XAudio_Internal_Realloc(void* ptr, size_t size)
+{
+    return CoTaskMemRealloc(ptr, size);
+}
diff --git a/dlls/xaudio2_7/xaudio_classes.idl b/dlls/xaudio2_7/xaudio_classes.idl
index 64e350f8d4..17a59c35cc 100644
--- a/dlls/xaudio2_7/xaudio_classes.idl
+++ b/dlls/xaudio2_7/xaudio_classes.idl
@@ -41,13 +41,6 @@ coclass AudioVolumeMeter { interface IUnknown; }
     uuid(6a93130e-1d53-41d1-a9cf-e758800bb179)
 ]
 coclass AudioReverb { interface IUnknown; }
-
-[
-    helpstring("XACT 31 Class"),
-    threading(both),
-    uuid(962f5027-99be-4692-a468-85802cf8de61)
-]
-coclass XACT31 { interface IUnknown; }
 #endif /* XAUDIO2_VER == 7 */
 
 #if XAUDIO2_VER == 6
diff --git a/dlls/xaudio2_7/xaudio_dll.c b/dlls/xaudio2_7/xaudio_dll.c
index 0bbe943f15..f338b56dc9 100644
--- a/dlls/xaudio2_7/xaudio_dll.c
+++ b/dlls/xaudio2_7/xaudio_dll.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2015 Mark Harmstone
  * Copyright (c) 2015 Andrew Eikum for CodeWeavers
+ * Copyright (c) 2018 Ethan Lee for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -18,38 +19,26 @@
  */
 
 #include "config.h"
+
 #include <stdarg.h>
 
 #define NONAMELESSUNION
 #define COBJMACROS
 
+#include "initguid.h"
 #include "xaudio_private.h"
+#include "xaudio2fx.h"
+#if XAUDIO2_VER >= 8
+#include "xapofx.h"
+#endif
 
 #include "ole2.h"
 #include "rpcproxy.h"
 
-#include "xapofx.h"
-
 #include "wine/debug.h"
+#include "wine/heap.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
-WINE_DECLARE_DEBUG_CHANNEL(winediag);
-
-static ALCdevice *(ALC_APIENTRY *palcLoopbackOpenDeviceSOFT)(const ALCchar*);
-static void (ALC_APIENTRY *palcRenderSamplesSOFT)(ALCdevice*, ALCvoid*, ALCsizei);
-static ALCboolean (ALC_APIENTRY *palcSetThreadContext)(ALCcontext*);
-
-static HINSTANCE instance;
-
-#define IN_AL_PERIODS 4
-
-#if XAUDIO2_VER == 0
-#define COMPAT_E_INVALID_CALL E_INVALIDARG
-#define COMPAT_E_DEVICE_INVALIDATED XAUDIO20_E_DEVICE_INVALIDATED
-#else
-#define COMPAT_E_INVALID_CALL XAUDIO2_E_INVALID_CALL
-#define COMPAT_E_DEVICE_INVALIDATED XAUDIO2_E_DEVICE_INVALIDATED
-#endif
 
 #if XAUDIO2_VER != 0 && defined(__i386__)
 /* EVE Online uses an OnVoiceProcessingPassStart callback which corrupts %esi. */
@@ -82,38 +71,9 @@ __ASM_GLOBAL_FUNC( call_on_voice_processing_pass_start,
                    "ret" )
 #endif
 
-static void dump_fmt(const WAVEFORMATEX *fmt)
-{
-    TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
-    switch(fmt->wFormatTag){
-#define DOCASE(x) case x: TRACE(#x); break;
-    DOCASE(WAVE_FORMAT_PCM)
-    DOCASE(WAVE_FORMAT_IEEE_FLOAT)
-    DOCASE(WAVE_FORMAT_EXTENSIBLE)
-#undef DOCASE
-    default:
-        TRACE("Unknown");
-        break;
-    }
-    TRACE(")\n");
-
-    TRACE("nChannels: %u\n", fmt->nChannels);
-    TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
-    TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
-    TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
-    TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
-    TRACE("cbSize: %u\n", fmt->cbSize);
-
-    if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
-        WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
-        TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
-        TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
-        TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
-    }else if(fmt->wFormatTag == WAVE_FORMAT_ADPCM){
-        ADPCMWAVEFORMAT *fmtadpcm = (void*)fmt;
-        TRACE("wSamplesPerBlock: %u\n", fmtadpcm->wSamplesPerBlock);
-    }
-}
+static HINSTANCE instance;
+
+static XA2VoiceImpl *impl_from_IXAudio2Voice(IXAudio2Voice *iface);
 
 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
 {
@@ -124,20 +84,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
     case DLL_PROCESS_ATTACH:
         instance = hinstDLL;
         DisableThreadLibraryCalls( hinstDLL );
-
-        if(!alcIsExtensionPresent(NULL, "ALC_SOFT_loopback") ||
-                !(palcLoopbackOpenDeviceSOFT = alcGetProcAddress(NULL, "alcLoopbackOpenDeviceSOFT")) ||
-                !(palcRenderSamplesSOFT = alcGetProcAddress(NULL, "alcRenderSamplesSOFT"))){
-            ERR("XAudio2 requires the ALC_SOFT_loopback extension (OpenAL-Soft >= 1.14)\n");
-            return FALSE;
-        }
-
-        if(!alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context") ||
-                !(palcSetThreadContext = alcGetProcAddress(NULL, "alcSetThreadContext"))){
-            ERR("XAudio2 requires the ALC_EXT_thread_local_context extension (OpenAL-Soft >= 1.12)\n");
-            return FALSE;
-        }
-
         break;
     }
     return TRUE;
@@ -160,250 +106,579 @@ HRESULT WINAPI DllUnregisterServer(void)
     return __wine_unregister_resources(instance);
 }
 
-static XA2SourceImpl *impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice *iface)
+/* Effect Wrapping */
+
+static inline XA2XAPOImpl *impl_from_FAPO(FAPO *iface)
 {
-    return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio2SourceVoice_iface);
+    return CONTAINING_RECORD(iface, XA2XAPOImpl, FAPO_vtbl);
 }
 
-static XA2SubmixImpl *impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice *iface)
+static int32_t FAPOCALL XAPO_AddRef(void *iface)
 {
-    return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio2SubmixVoice_iface);
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    return InterlockedIncrement(&This->ref);
 }
 
-static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
+static int32_t FAPOCALL XAPO_Release(void *iface)
 {
-    return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2_iface);
+    int32_t r;
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    r = InterlockedDecrement(&This->ref);
+    if(r == 0){
+        IXAPO_Release(This->xapo);
+        if(This->xapo_params)
+            IXAPOParameters_Release(This->xapo_params);
+        heap_free(This);
+    }
+    return r;
 }
 
-static IXAudio2Impl *impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice *iface)
-{
-    return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2MasteringVoice_iface);
-}
-
-static DWORD get_channel_mask(unsigned int channels)
-{
-    switch(channels){
-    case 0:
-        return 0;
-    case 1:
-        return KSAUDIO_SPEAKER_MONO;
-    case 2:
-        return KSAUDIO_SPEAKER_STEREO;
-    case 3:
-        return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
-    case 4:
-        return KSAUDIO_SPEAKER_QUAD;    /* not _SURROUND */
-    case 5:
-        return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
-    case 6:
-        return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
-    case 7:
-        return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
-    case 8:
-        return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
-    }
-    FIXME("Unknown speaker configuration: %u\n", channels);
+static uint32_t FAPOCALL XAPO_GetRegistrationProperties(void *iface,
+        FAPORegistrationProperties **ppRegistrationProperties)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    XAPO_REGISTRATION_PROPERTIES *xprops;
+    HRESULT hr;
+
+    TRACE("%p\n", This);
+
+    hr = IXAPO_GetRegistrationProperties(This->xapo, &xprops);
+    if(FAILED(hr))
+        return hr;
+
+    /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
+    *ppRegistrationProperties = (FAPORegistrationProperties*) xprops;
     return 0;
 }
 
-static void WINAPI XA2SRC_GetVoiceDetails(IXAudio2SourceVoice *iface,
-        XAUDIO2_VOICE_DETAILS *pVoiceDetails)
+static uint32_t FAPOCALL XAPO_IsInputFormatSupported(void *iface,
+        const FAudioWaveFormatEx *pOutputFormat, const FAudioWaveFormatEx *pRequestedInputFormat,
+        FAudioWaveFormatEx **ppSupportedInputFormat)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    return IXAPO_IsInputFormatSupported(This->xapo, (const WAVEFORMATEX*)pOutputFormat,
+            (const WAVEFORMATEX*)pRequestedInputFormat, (WAVEFORMATEX**)ppSupportedInputFormat);
+}
 
-    TRACE("%p, %p\n", This, pVoiceDetails);
+static uint32_t FAPOCALL XAPO_IsOutputFormatSupported(void *iface,
+        const FAudioWaveFormatEx *pInputFormat, const FAudioWaveFormatEx *pRequestedOutputFormat,
+        FAudioWaveFormatEx **ppSupportedOutputFormat)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    return IXAPO_IsOutputFormatSupported(This->xapo, (const WAVEFORMATEX *)pInputFormat,
+            (const WAVEFORMATEX *)pRequestedOutputFormat, (WAVEFORMATEX**)ppSupportedOutputFormat);
+}
 
-    pVoiceDetails->CreationFlags = 0;
-    pVoiceDetails->ActiveFlags = 0;
-    pVoiceDetails->InputChannels = This->fmt->nChannels;
-    pVoiceDetails->InputSampleRate = This->fmt->nSamplesPerSec;
+static uint32_t FAPOCALL XAPO_Initialize(void *iface, const void *pData,
+        uint32_t DataByteSize)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    return IXAPO_Initialize(This->xapo, pData, DataByteSize);
 }
 
-static HRESULT WINAPI XA2SRC_SetOutputVoices(IXAudio2SourceVoice *iface,
-        const XAUDIO2_VOICE_SENDS *pSendList)
+static void FAPOCALL XAPO_Reset(void *iface)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    IXAPO_Reset(This->xapo);
+}
+
+static uint32_t FAPOCALL XAPO_LockForProcess(void *iface,
+        uint32_t InputLockedParameterCount,
+        const FAPOLockForProcessBufferParameters *pInputLockedParameters,
+        uint32_t OutputLockedParameterCount,
+        const FAPOLockForProcessBufferParameters *pOutputLockedParameters)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    return IXAPO_LockForProcess(This->xapo,
+            InputLockedParameterCount,
+            (const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *)pInputLockedParameters,
+            OutputLockedParameterCount,
+            (const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *)pOutputLockedParameters);
+}
+
+static void FAPOCALL XAPO_UnlockForProcess(void *iface)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    IXAPO_UnlockForProcess(This->xapo);
+}
+
+static void FAPOCALL XAPO_Process(void *iface,
+        uint32_t InputProcessParameterCount,
+        const FAPOProcessBufferParameters* pInputProcessParameters,
+        uint32_t OutputProcessParameterCount,
+        FAPOProcessBufferParameters* pOutputProcessParameters,
+        int32_t IsEnabled)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    IXAPO_Process(This->xapo, InputProcessParameterCount,
+            (const XAPO_PROCESS_BUFFER_PARAMETERS *)pInputProcessParameters,
+            OutputProcessParameterCount,
+            (XAPO_PROCESS_BUFFER_PARAMETERS *)pOutputProcessParameters,
+            IsEnabled);
+}
+
+static uint32_t FAPOCALL XAPO_CalcInputFrames(void *iface,
+        uint32_t OutputFrameCount)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    return IXAPO_CalcInputFrames(This->xapo, OutputFrameCount);
+}
+
+static uint32_t FAPOCALL XAPO_CalcOutputFrames(void *iface,
+        uint32_t InputFrameCount)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    return IXAPO_CalcOutputFrames(This->xapo, InputFrameCount);
+}
+
+static void FAPOCALL XAPO_SetParameters(void *iface,
+        const void *pParameters, uint32_t ParametersByteSize)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    if(This->xapo_params)
+        IXAPOParameters_SetParameters(This->xapo_params, pParameters, ParametersByteSize);
+}
+
+static void FAPOCALL XAPO_GetParameters(void *iface,
+        void *pParameters, uint32_t ParametersByteSize)
+{
+    XA2XAPOImpl *This = impl_from_FAPO(iface);
+    TRACE("%p\n", This);
+    if(This->xapo_params)
+        IXAPOParameters_GetParameters(This->xapo_params, pParameters, ParametersByteSize);
+    else
+        memset(pParameters, 0, ParametersByteSize);
+}
+
+static const FAPO FAPO_Vtbl = {
+    XAPO_AddRef,
+    XAPO_Release,
+    XAPO_GetRegistrationProperties,
+    XAPO_IsInputFormatSupported,
+    XAPO_IsOutputFormatSupported,
+    XAPO_Initialize,
+    XAPO_Reset,
+    XAPO_LockForProcess,
+    XAPO_UnlockForProcess,
+    XAPO_Process,
+    XAPO_CalcInputFrames,
+    XAPO_CalcOutputFrames,
+    XAPO_SetParameters,
+    XAPO_GetParameters,
+};
+
+static XA2XAPOImpl *wrap_xapo(IUnknown *unk)
+{
+    XA2XAPOImpl *ret;
+    IXAPO *xapo;
+    IXAPOParameters *xapo_params;
+    HRESULT hr;
+
+#if XAUDIO2_VER <= 7
+    hr = IUnknown_QueryInterface(unk, &IID_IXAPO27, (void**)&xapo);
+#else
+    hr = IUnknown_QueryInterface(unk, &IID_IXAPO, (void**)&xapo);
+#endif
+    if(FAILED(hr)){
+        WARN("XAPO doesn't support IXAPO? %p\n", unk);
+        return NULL;
+    }
+
+#if XAUDIO2_VER <= 7
+    hr = IUnknown_QueryInterface(unk, &IID_IXAPO27Parameters, (void**)&xapo_params);
+#else
+    hr = IUnknown_QueryInterface(unk, &IID_IXAPOParameters, (void**)&xapo_params);
+#endif
+    if(FAILED(hr)){
+        TRACE("XAPO doesn't support IXAPOParameters %p\n", unk);
+        xapo_params = NULL;
+    }
+
+    ret = heap_alloc(sizeof(*ret));
+
+    ret->xapo = xapo;
+    ret->xapo_params = xapo_params;
+    ret->FAPO_vtbl = FAPO_Vtbl;
+    ret->ref = 1;
+
+    TRACE("wrapped IXAPO %p with %p\n", xapo, ret);
+
+    return ret;
+}
+
+FAudioEffectChain *wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN *pEffectChain)
+{
+    FAudioEffectChain *ret;
     int i;
-    XAUDIO2_VOICE_SENDS def_send;
-    XAUDIO2_SEND_DESCRIPTOR def_desc;
 
-    TRACE("%p, %p\n", This, pSendList);
+    if(!pEffectChain)
+        return NULL;
 
-    if(!pSendList){
-        def_desc.Flags = 0;
-        def_desc.pOutputVoice = (IXAudio2Voice*)&This->xa2->IXAudio2MasteringVoice_iface;
+    ret = heap_alloc(sizeof(*ret) + sizeof(FAudioEffectDescriptor) * pEffectChain->EffectCount);
 
-        def_send.SendCount = 1;
-        def_send.pSends = &def_desc;
+    ret->EffectCount = pEffectChain->EffectCount;
+    ret->pEffectDescriptors = (void*)(ret + 1);
 
-        pSendList = &def_send;
+    for(i = 0; i < ret->EffectCount; ++i){
+        ret->pEffectDescriptors[i].pEffect = &wrap_xapo(pEffectChain->pEffectDescriptors[i].pEffect)->FAPO_vtbl;
+        ret->pEffectDescriptors[i].InitialState = pEffectChain->pEffectDescriptors[i].InitialState;
+        ret->pEffectDescriptors[i].OutputChannels = pEffectChain->pEffectDescriptors[i].OutputChannels;
     }
 
-    if(TRACE_ON(xaudio2)){
-        for(i = 0; i < pSendList->SendCount; ++i){
-            XAUDIO2_SEND_DESCRIPTOR *desc = &pSendList->pSends[i];
-            TRACE("Outputting to: 0x%x, %p\n", desc->Flags, desc->pOutputVoice);
-        }
+    return ret;
+}
+
+static void free_effect_chain(FAudioEffectChain *chain)
+{
+    int i;
+    if(!chain)
+        return;
+    for(i = 0; i < chain->EffectCount; ++i)
+        XAPO_Release(chain->pEffectDescriptors[i].pEffect);
+    heap_free(chain);
+}
+
+/* Send Wrapping */
+
+static FAudioVoiceSends *wrap_voice_sends(const XAUDIO2_VOICE_SENDS *sends)
+{
+    FAudioVoiceSends *ret;
+    int i;
+
+    if(!sends)
+        return NULL;
+
+    ret = heap_alloc(sizeof(*ret) + sends->SendCount * sizeof(FAudioSendDescriptor));
+    ret->SendCount = sends->SendCount;
+    ret->pSends = (FAudioSendDescriptor*)(ret + 1);
+    for(i = 0; i < sends->SendCount; ++i){
+        XA2VoiceImpl *voice = impl_from_IXAudio2Voice(sends->pSends[i].pOutputVoice);
+        ret->pSends[i].pOutputVoice = voice->faudio_voice;
+        ret->pSends[i].Flags = sends->pSends[i].Flags;
     }
+    return ret;
+}
 
-    if(This->nsends < pSendList->SendCount){
-        HeapFree(GetProcessHeap(), 0, This->sends);
-        This->sends = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->sends) * pSendList->SendCount);
-        This->nsends = pSendList->SendCount;
-    }else
-        memset(This->sends, 0, sizeof(*This->sends) * This->nsends);
+static void free_voice_sends(FAudioVoiceSends *sends)
+{
+    if(!sends)
+        return;
+    heap_free(sends);
+}
 
-    memcpy(This->sends, pSendList->pSends, sizeof(*This->sends) * pSendList->SendCount);
+/* Voice Callbacks */
 
-    return S_OK;
+static inline XA2VoiceImpl *impl_from_FAudioVoiceCallback(FAudioVoiceCallback *iface)
+{
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, FAudioVoiceCallback_vtbl);
+}
+
+static void FAUDIOCALL XA2VCB_OnVoiceProcessingPassStart(FAudioVoiceCallback *iface,
+        UINT32 BytesRequired)
+{
+    XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
+    TRACE("%p\n", This);
+    if(This->cb)
+#if XAUDIO2_VER == 0
+        IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback*)This->cb);
+#else
+        IXAudio2VoiceCallback_OnVoiceProcessingPassStart(This->cb, BytesRequired);
+#endif
+}
+
+static void FAUDIOCALL XA2VCB_OnVoiceProcessingPassEnd(FAudioVoiceCallback *iface)
+{
+    XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
+    TRACE("%p\n", This);
+    if(This->cb)
+        IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(This->cb);
+}
+
+static void FAUDIOCALL XA2VCB_OnStreamEnd(FAudioVoiceCallback *iface)
+{
+    XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
+    TRACE("%p\n", This);
+    if(This->cb)
+        IXAudio2VoiceCallback_OnStreamEnd(This->cb);
+}
+
+static void FAUDIOCALL XA2VCB_OnBufferStart(FAudioVoiceCallback *iface,
+        void *pBufferContext)
+{
+    XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
+    TRACE("%p\n", This);
+    if(This->cb)
+        IXAudio2VoiceCallback_OnBufferStart(This->cb, pBufferContext);
+}
+
+static void FAUDIOCALL XA2VCB_OnBufferEnd(FAudioVoiceCallback *iface,
+        void *pBufferContext)
+{
+    XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
+    TRACE("%p\n", This);
+    if(This->cb)
+        IXAudio2VoiceCallback_OnBufferEnd(This->cb, pBufferContext);
+}
+
+static void FAUDIOCALL XA2VCB_OnLoopEnd(FAudioVoiceCallback *iface,
+        void *pBufferContext)
+{
+    XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
+    TRACE("%p\n", This);
+    if(This->cb)
+        IXAudio2VoiceCallback_OnLoopEnd(This->cb, pBufferContext);
+}
+
+static void FAUDIOCALL XA2VCB_OnVoiceError(FAudioVoiceCallback *iface,
+        void *pBufferContext, unsigned int Error)
+{
+    XA2VoiceImpl *This = impl_from_FAudioVoiceCallback(iface);
+    TRACE("%p\n", This);
+    if(This->cb)
+        IXAudio2VoiceCallback_OnVoiceError(This->cb, pBufferContext, (HRESULT)Error);
+}
+
+static const FAudioVoiceCallback FAudioVoiceCallback_Vtbl = {
+    XA2VCB_OnBufferEnd,
+    XA2VCB_OnBufferStart,
+    XA2VCB_OnLoopEnd,
+    XA2VCB_OnStreamEnd,
+    XA2VCB_OnVoiceError,
+    XA2VCB_OnVoiceProcessingPassEnd,
+    XA2VCB_OnVoiceProcessingPassStart
+};
+
+/* Engine Callbacks */
+
+static inline IXAudio2Impl *impl_from_FAudioEngineCallback(FAudioEngineCallback *iface)
+{
+    return CONTAINING_RECORD(iface, IXAudio2Impl, FAudioEngineCallback_vtbl);
+}
+
+static void FAUDIOCALL XA2ECB_OnProcessingPassStart(FAudioEngineCallback *iface)
+{
+    IXAudio2Impl *This = impl_from_FAudioEngineCallback(iface);
+    int i;
+    TRACE("%p\n", This);
+    for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
+        IXAudio2EngineCallback_OnProcessingPassStart(This->cbs[i]);
+}
+
+static void FAUDIOCALL XA2ECB_OnProcessingPassEnd(FAudioEngineCallback *iface)
+{
+    IXAudio2Impl *This = impl_from_FAudioEngineCallback(iface);
+    int i;
+    TRACE("%p\n", This);
+    for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
+        IXAudio2EngineCallback_OnProcessingPassEnd(This->cbs[i]);
+}
+
+static void FAUDIOCALL XA2ECB_OnCriticalError(FAudioEngineCallback *iface,
+        uint32_t error)
+{
+    IXAudio2Impl *This = impl_from_FAudioEngineCallback(iface);
+    int i;
+    TRACE("%p\n", This);
+    for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
+        IXAudio2EngineCallback_OnCriticalError(This->cbs[i], error);
+}
+
+static const FAudioEngineCallback FAudioEngineCallback_Vtbl = {
+    XA2ECB_OnCriticalError,
+    XA2ECB_OnProcessingPassEnd,
+    XA2ECB_OnProcessingPassStart
+};
+
+/* Common Voice Functions */
+
+static inline void destroy_voice(XA2VoiceImpl *This)
+{
+    FAudioVoice_DestroyVoice(This->faudio_voice);
+    free_effect_chain(This->effect_chain);
+    This->effect_chain = NULL;
+    This->in_use = FALSE;
+}
+
+/* Source Voices */
+
+static inline XA2VoiceImpl *impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice *iface)
+{
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio2SourceVoice_iface);
+}
+
+static void WINAPI XA2SRC_GetVoiceDetails(IXAudio2SourceVoice *iface,
+        XAUDIO2_VOICE_DETAILS *pVoiceDetails)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    TRACE("%p, %p\n", This, pVoiceDetails);
+    FAudioVoice_GetVoiceDetails(This->faudio_voice, (FAudioVoiceDetails *)pVoiceDetails);
+}
+
+static HRESULT WINAPI XA2SRC_SetOutputVoices(IXAudio2SourceVoice *iface,
+        const XAUDIO2_VOICE_SENDS *pSendList)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    FAudioVoiceSends *faudio_sends;
+    HRESULT hr;
+
+    TRACE("%p, %p\n", This, pSendList);
+
+    faudio_sends = wrap_voice_sends(pSendList);
+
+    hr = FAudioVoice_SetOutputVoices(This->faudio_voice, faudio_sends);
+
+    free_voice_sends(faudio_sends);
+
+    return hr;
 }
 
 static HRESULT WINAPI XA2SRC_SetEffectChain(IXAudio2SourceVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    HRESULT hr;
+
     TRACE("%p, %p\n", This, pEffectChain);
-    return S_OK;
+
+    free_effect_chain(This->effect_chain);
+    This->effect_chain = wrap_effect_chain(pEffectChain);
+
+    hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
+
+    return hr;
 }
 
-static HRESULT WINAPI XA2SRC_EnableEffect(IXAudio2SourceVoice *iface,
-        UINT32 EffectIndex, UINT32 OperationSet)
+static HRESULT WINAPI XA2SRC_EnableEffect(IXAudio2SourceVoice *iface, UINT32 EffectIndex,
+        UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
-    return S_OK;
+    return FAudioVoice_EnableEffect(This->faudio_voice, EffectIndex, OperationSet);
 }
 
-static HRESULT WINAPI XA2SRC_DisableEffect(IXAudio2SourceVoice *iface,
-        UINT32 EffectIndex, UINT32 OperationSet)
+static HRESULT WINAPI XA2SRC_DisableEffect(IXAudio2SourceVoice *iface, UINT32 EffectIndex,
+        UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
-    return S_OK;
+    return FAudioVoice_DisableEffect(This->faudio_voice, EffectIndex, OperationSet);
 }
 
-static void WINAPI XA2SRC_GetEffectState(IXAudio2SourceVoice *iface,
-        UINT32 EffectIndex, BOOL *pEnabled)
+static void WINAPI XA2SRC_GetEffectState(IXAudio2SourceVoice *iface, UINT32 EffectIndex,
+        BOOL *pEnabled)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
+    FAudioVoice_GetEffectState(This->faudio_voice, EffectIndex, (int32_t*)pEnabled);
 }
 
 static HRESULT WINAPI XA2SRC_SetEffectParameters(IXAudio2SourceVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
             ParametersByteSize, OperationSet);
-    return S_OK;
+    return FAudioVoice_SetEffectParameters(This->faudio_voice, EffectIndex,
+            pParameters, ParametersByteSize, OperationSet);
 }
 
 static HRESULT WINAPI XA2SRC_GetEffectParameters(IXAudio2SourceVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
             ParametersByteSize);
-    return S_OK;
+    return FAudioVoice_GetEffectParameters(This->faudio_voice, EffectIndex,
+            pParameters, ParametersByteSize);
 }
 
 static HRESULT WINAPI XA2SRC_SetFilterParameters(IXAudio2SourceVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
-    return S_OK;
+    return FAudioVoice_SetFilterParameters(This->faudio_voice,
+            (const FAudioFilterParameters *)pParameters, OperationSet);
 }
 
 static void WINAPI XA2SRC_GetFilterParameters(IXAudio2SourceVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %p\n", This, pParameters);
+    FAudioVoice_GetFilterParameters(This->faudio_voice, (FAudioFilterParameters *)pParameters);
 }
 
 static HRESULT WINAPI XA2SRC_SetOutputFilterParameters(IXAudio2SourceVoice *iface,
         IXAudio2Voice *pDestinationVoice,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
     TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
-    return S_OK;
+
+    return FAudioVoice_SetOutputFilterParameters(This->faudio_voice,
+            dst ? dst->faudio_voice : NULL, (const FAudioFilterParameters *)pParameters, OperationSet);
 }
 
 static void WINAPI XA2SRC_GetOutputFilterParameters(IXAudio2SourceVoice *iface,
         IXAudio2Voice *pDestinationVoice,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
     TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
+
+    FAudioVoice_GetOutputFilterParameters(This->faudio_voice,
+            dst ? dst->faudio_voice : NULL, (FAudioFilterParameters *)pParameters);
 }
 
 static HRESULT WINAPI XA2SRC_SetVolume(IXAudio2SourceVoice *iface, float Volume,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
-    ALfloat al_gain;
-
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
-
-    al_gain = Volume;
-
-    palcSetThreadContext(This->xa2->al_ctx);
-
-    alSourcef(This->al_src, AL_GAIN, al_gain);
-
-    return S_OK;
+    return FAudioVoice_SetVolume(This->faudio_voice, Volume, OperationSet);
 }
 
 static void WINAPI XA2SRC_GetVolume(IXAudio2SourceVoice *iface, float *pVolume)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %p\n", This, pVolume);
+    return FAudioVoice_GetVolume(This->faudio_voice, pVolume);
 }
 
-static HRESULT WINAPI XA2SRC_SetChannelVolumes(IXAudio2SourceVoice *iface,
-        UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
+static HRESULT WINAPI XA2SRC_SetChannelVolumes(IXAudio2SourceVoice *iface, UINT32 Channels,
+        const float *pVolumes, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
-    ALfloat al_gain;
-    UINT32 i;
-    BOOL same_volumes_given = TRUE;
-
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
-
-#if XAUDIO2_VER > 7
-    if(Channels != This->fmt->nChannels || !pVolumes)
-        return COMPAT_E_INVALID_CALL;
-#endif
-
-    al_gain = *pVolumes;
-
-    /* check whether all volumes are the same */
-    for(i = 1; i < Channels; ++i){
-        if(al_gain != *(pVolumes + i)){
-            same_volumes_given = FALSE;
-            break;
-        }
-    }
-    if(!same_volumes_given){
-        WARN("Different volumes for channels unsupported, setting the highest volume.\n");
-        for(; i < Channels; ++i)
-            al_gain = max(al_gain, *(pVolumes + i));
-    }
-
-    palcSetThreadContext(This->xa2->al_ctx);
-    alSourcef(This->al_src, AL_GAIN, al_gain);
-
-    return S_OK;
+    return FAudioVoice_SetChannelVolumes(This->faudio_voice, Channels,
+            pVolumes, OperationSet);
 }
 
-static void WINAPI XA2SRC_GetChannelVolumes(IXAudio2SourceVoice *iface,
-        UINT32 Channels, float *pVolumes)
+static void WINAPI XA2SRC_GetChannelVolumes(IXAudio2SourceVoice *iface, UINT32 Channels,
+        float *pVolumes)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
     TRACE("%p, %u, %p\n", This, Channels, pVolumes);
+    return FAudioVoice_GetChannelVolumes(This->faudio_voice, Channels,
+            pVolumes);
 }
 
 static HRESULT WINAPI XA2SRC_SetOutputMatrix(IXAudio2SourceVoice *iface,
@@ -411,68 +686,39 @@ static HRESULT WINAPI XA2SRC_SetOutputMatrix(IXAudio2SourceVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
     TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
             SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
-    return S_OK;
+
+    return FAudioVoice_SetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
+            SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
 }
 
 static void WINAPI XA2SRC_GetOutputMatrix(IXAudio2SourceVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
     TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
             SourceChannels, DestinationChannels, pLevelMatrix);
-}
+
+    FAudioVoice_GetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
+            SourceChannels, DestinationChannels, pLevelMatrix);
+}
 
 static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
-    ALint processed;
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p\n", This);
 
-    palcSetThreadContext(This->xa2->al_ctx);
-
     EnterCriticalSection(&This->lock);
 
-    if(!This->in_use){
-        LeaveCriticalSection(&This->lock);
-        return;
-    }
-
-    This->in_use = FALSE;
-
-    This->running = FALSE;
-
-    IXAudio2SourceVoice_Stop(iface, 0, 0);
-
-    alSourceStop(This->al_src);
-
-    /* unqueue all buffers */
-    alSourcei(This->al_src, AL_BUFFER, AL_NONE);
-
-    alGetSourcei(This->al_src, AL_BUFFERS_PROCESSED, &processed);
-
-    if(processed > 0){
-        ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
-
-        alSourceUnqueueBuffers(This->al_src, processed, al_buffers);
-    }
-
-    HeapFree(GetProcessHeap(), 0, This->fmt);
-
-    alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, This->al_bufs);
-    alDeleteSources(1, &This->al_src);
-
-    This->in_al_bytes = 0;
-    This->al_bufs_used = 0;
-    This->played_frames = 0;
-    This->nbufs = 0;
-    This->first_buf = 0;
-    This->cur_buf = 0;
-    This->abandoned_albufs = 0;
+    destroy_voice(This);
 
     LeaveCriticalSection(&This->lock);
 }
@@ -480,380 +726,98 @@ static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface)
 static HRESULT WINAPI XA2SRC_Start(IXAudio2SourceVoice *iface, UINT32 Flags,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
 
-    EnterCriticalSection(&This->lock);
-
-    This->running = TRUE;
-
-    LeaveCriticalSection(&This->lock);
-
-    return S_OK;
+    return FAudioSourceVoice_Start(This->faudio_voice, Flags, OperationSet);
 }
 
 static HRESULT WINAPI XA2SRC_Stop(IXAudio2SourceVoice *iface, UINT32 Flags,
         UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
-    ALint bufs;
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
 
-    palcSetThreadContext(This->xa2->al_ctx);
-
-    EnterCriticalSection(&This->lock);
-
-    alGetSourcei(This->al_src, AL_BUFFERS_QUEUED, &bufs);
-
-    This->abandoned_albufs = bufs;
-
-    This->running = FALSE;
-
-    LeaveCriticalSection(&This->lock);
-
-    return S_OK;
-}
-
-static ALenum get_al_format(const WAVEFORMATEX *fmt)
-{
-    WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
-    if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
-            (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-             IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
-        switch(fmt->wBitsPerSample){
-        case 8:
-            switch(fmt->nChannels){
-            case 1:
-                return AL_FORMAT_MONO8;
-            case 2:
-                return AL_FORMAT_STEREO8;
-            case 4:
-                return AL_FORMAT_QUAD8;
-            case 6:
-                return AL_FORMAT_51CHN8;
-            case 7:
-                return AL_FORMAT_61CHN8;
-            case 8:
-                return AL_FORMAT_71CHN8;
-            }
-            break;
-        case 16:
-            switch(fmt->nChannels){
-            case 1:
-                return AL_FORMAT_MONO16;
-            case 2:
-                return AL_FORMAT_STEREO16;
-            case 4:
-                return AL_FORMAT_QUAD16;
-            case 6:
-                return AL_FORMAT_51CHN16;
-            case 7:
-                return AL_FORMAT_61CHN16;
-            case 8:
-                return AL_FORMAT_71CHN16;
-            }
-            break;
-        }
-    }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
-            (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-             IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
-        if(fmt->wBitsPerSample == 32){
-            switch(fmt->nChannels){
-            case 1:
-                return AL_FORMAT_MONO_FLOAT32;
-            case 2:
-                return AL_FORMAT_STEREO_FLOAT32;
-            case 4:
-                return AL_FORMAT_QUAD32;
-            case 6:
-                return AL_FORMAT_51CHN32;
-            case 7:
-                return AL_FORMAT_61CHN32;
-            case 8:
-                return AL_FORMAT_71CHN32;
-            }
-        }
-    }
-    return 0;
+    return FAudioSourceVoice_Stop(This->faudio_voice, Flags, OperationSet);
 }
 
 static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface,
         const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
-    XA2Buffer *buf;
-    UINT32 buf_idx;
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p, %p, %p\n", This, pBuffer, pBufferWMA);
 
-    if(TRACE_ON(xaudio2)){
-        TRACE("Flags: 0x%x\n", pBuffer->Flags);
-        TRACE("AudioBytes: %u\n", pBuffer->AudioBytes);
-        TRACE("pAudioData: %p\n", pBuffer->pAudioData);
-        TRACE("PlayBegin: %u\n", pBuffer->PlayBegin);
-        TRACE("PlayLength: %u\n", pBuffer->PlayLength);
-        TRACE("LoopBegin: %u\n", pBuffer->LoopBegin);
-        TRACE("LoopLength: %u\n", pBuffer->LoopLength);
-        TRACE("LoopCount: %u\n", pBuffer->LoopCount);
-        TRACE("pContext: %p\n", pBuffer->pContext);
-    }
-
-    EnterCriticalSection(&This->lock);
-
-    if(This->nbufs >= XAUDIO2_MAX_QUEUED_BUFFERS){
-        TRACE("Too many buffers queued!\n");
-        LeaveCriticalSection(&This->lock);
-        return COMPAT_E_INVALID_CALL;
-    }
-
-    buf_idx = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
-    buf = &This->buffers[buf_idx];
-    memset(buf, 0, sizeof(*buf));
-
-    /* API contract: pAudioData must remain valid until this buffer is played,
-     * but pBuffer itself may be reused immediately */
-    memcpy(&buf->xa2buffer, pBuffer, sizeof(*pBuffer));
-
-#if XAUDIO2_VER == 0
-    if(buf->xa2buffer.LoopCount == XAUDIO20_LOOP_INFINITE)
-        buf->xa2buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
-#endif
-
-    /* convert samples offsets to bytes */
-    if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){
-        /* ADPCM gives us a number of samples per block, so round down to
-         * nearest block and convert to bytes */
-        buf->xa2buffer.PlayBegin = buf->xa2buffer.PlayBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
-        buf->xa2buffer.PlayLength = buf->xa2buffer.PlayLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
-        buf->xa2buffer.LoopBegin = buf->xa2buffer.LoopBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
-        buf->xa2buffer.LoopLength = buf->xa2buffer.LoopLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
-    }else{
-        buf->xa2buffer.PlayBegin *= This->fmt->nBlockAlign;
-        buf->xa2buffer.PlayLength *= This->fmt->nBlockAlign;
-        buf->xa2buffer.LoopBegin *= This->fmt->nBlockAlign;
-        buf->xa2buffer.LoopLength *= This->fmt->nBlockAlign;
-    }
-
-    if(buf->xa2buffer.PlayLength == 0)
-        /* set to end of buffer */
-        buf->xa2buffer.PlayLength = buf->xa2buffer.AudioBytes - buf->xa2buffer.PlayBegin;
-
-    buf->play_end_bytes = buf->xa2buffer.PlayBegin + buf->xa2buffer.PlayLength;
-
-    if(buf->xa2buffer.LoopCount){
-        if(buf->xa2buffer.LoopLength == 0)
-            /* set to end of play range */
-            buf->xa2buffer.LoopLength = buf->play_end_bytes - buf->xa2buffer.LoopBegin;
-
-        if(buf->xa2buffer.LoopBegin >= buf->play_end_bytes){
-            /* this actually crashes on native xaudio 2.7 */
-            LeaveCriticalSection(&This->lock);
-            return COMPAT_E_INVALID_CALL;
-        }
-
-        buf->loop_end_bytes = buf->xa2buffer.LoopBegin + buf->xa2buffer.LoopLength;
-
-        /* xaudio 2.7 allows some invalid looping setups, but later versions
-         * return an error */
-#if XAUDIO2_VER > 7
-        if(buf->loop_end_bytes > buf->play_end_bytes){
-            LeaveCriticalSection(&This->lock);
-            return COMPAT_E_INVALID_CALL;
-        }
-
-        if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
-            LeaveCriticalSection(&This->lock);
-            return COMPAT_E_INVALID_CALL;
-        }
-#else
-        if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
-            buf->xa2buffer.LoopCount = 0;
-            buf->loop_end_bytes = buf->play_end_bytes;
-        }
-#endif
-    }else{
-        buf->xa2buffer.LoopLength = buf->xa2buffer.PlayLength;
-        buf->xa2buffer.LoopBegin = buf->xa2buffer.PlayBegin;
-        buf->loop_end_bytes = buf->play_end_bytes;
-    }
-
-    buf->offs_bytes = buf->xa2buffer.PlayBegin;
-    buf->cur_end_bytes = buf->loop_end_bytes;
-
-    buf->latest_al_buf = -1;
-
-    ++This->nbufs;
-
-    TRACE("%p: queued buffer %u (%u bytes), now %u buffers held\n",
-            This, buf_idx, buf->xa2buffer.AudioBytes, This->nbufs);
-
-    LeaveCriticalSection(&This->lock);
-
-    return S_OK;
+    return FAudioSourceVoice_SubmitSourceBuffer(This->faudio_voice, (FAudioBuffer*)pBuffer, (FAudioBufferWMA*)pBufferWMA);
 }
 
 static HRESULT WINAPI XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice *iface)
 {
-    UINT i, first, last, to_flush;
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p\n", This);
 
-    EnterCriticalSection(&This->lock);
-
-    if(This->running && This->nbufs > 0){
-        /* when running, flush only completely unused buffers; the rest remain
-         * in queue */
-        last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
-        first = (This->cur_buf + 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
-        if(This->cur_buf == last)
-            /* nothing to do */
-            to_flush = 0;
-        else if(last >= first)
-            to_flush = last - first;
-        else
-            to_flush = last + XAUDIO2_MAX_QUEUED_BUFFERS - first;
-    }else{
-        /* when stopped, flush all buffers */
-        first = This->first_buf;
-        last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
-        to_flush = This->nbufs;
-    }
-
-
-    for(i = first;
-            i < (first + to_flush) % XAUDIO2_MAX_QUEUED_BUFFERS;
-            i = (i + 1) % XAUDIO2_MAX_QUEUED_BUFFERS){
-        if(This->cb)
-            IXAudio2VoiceCallback_OnBufferEnd(This->cb,
-                    This->buffers[i].xa2buffer.pContext);
-    }
-
-    This->nbufs -= to_flush;
-    This->cur_buf = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
-
-    LeaveCriticalSection(&This->lock);
-
-    return S_OK;
+    return FAudioSourceVoice_FlushSourceBuffers(This->faudio_voice);
 }
 
 static HRESULT WINAPI XA2SRC_Discontinuity(IXAudio2SourceVoice *iface)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p\n", This);
 
-    EnterCriticalSection(&This->lock);
-
-    if(This->nbufs > 0){
-        DWORD last = (This->first_buf + This->nbufs - 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
-        This->buffers[last].xa2buffer.Flags |= XAUDIO2_END_OF_STREAM;
-    }
-
-    LeaveCriticalSection(&This->lock);
-
-    return S_OK;
+    return FAudioSourceVoice_Discontinuity(This->faudio_voice);
 }
 
 static HRESULT WINAPI XA2SRC_ExitLoop(IXAudio2SourceVoice *iface, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p, 0x%x\n", This, OperationSet);
 
-    EnterCriticalSection(&This->lock);
-
-    This->buffers[This->cur_buf].looped = XAUDIO2_LOOP_INFINITE;
-
-    LeaveCriticalSection(&This->lock);
-
-    return S_OK;
+    return FAudioSourceVoice_ExitLoop(This->faudio_voice, OperationSet);
 }
 
 static void WINAPI XA2SRC_GetState(IXAudio2SourceVoice *iface,
         XAUDIO2_VOICE_STATE *pVoiceState, UINT32 Flags)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p, %p, 0x%x\n", This, pVoiceState, Flags);
 
-    EnterCriticalSection(&This->lock);
-
-    if(!(Flags & XAUDIO2_VOICE_NOSAMPLESPLAYED))
-        pVoiceState->SamplesPlayed = This->played_frames;
-    else
-        pVoiceState->SamplesPlayed = 0;
-
-    if(This->nbufs)
-        pVoiceState->pCurrentBufferContext = This->buffers[This->first_buf].xa2buffer.pContext;
-    else
-        pVoiceState->pCurrentBufferContext = NULL;
-
-    pVoiceState->BuffersQueued = This->nbufs;
-
-    LeaveCriticalSection(&This->lock);
-
-    TRACE("returning %s, queued: %u\n", wine_dbgstr_longlong(pVoiceState->SamplesPlayed), This->nbufs);
+    return FAudioSourceVoice_GetState(This->faudio_voice, (FAudioVoiceState*)pVoiceState, Flags);
 }
 
 static HRESULT WINAPI XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice *iface,
         float Ratio, UINT32 OperationSet)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
-    ALfloat r;
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p, %f, 0x%x\n", This, Ratio, OperationSet);
 
-    if(Ratio < XAUDIO2_MIN_FREQ_RATIO)
-        r = XAUDIO2_MIN_FREQ_RATIO;
-    else if (Ratio > XAUDIO2_MAX_FREQ_RATIO)
-        r = XAUDIO2_MAX_FREQ_RATIO;
-    else
-        r = Ratio;
-
-    palcSetThreadContext(This->xa2->al_ctx);
-
-    alSourcef(This->al_src, AL_PITCH, r);
-
-    return S_OK;
+    return FAudioSourceVoice_SetFrequencyRatio(This->faudio_voice, Ratio, OperationSet);
 }
 
 static void WINAPI XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice *iface, float *pRatio)
 {
-    ALfloat ratio;
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p, %p\n", This, pRatio);
 
-    palcSetThreadContext(This->xa2->al_ctx);
-
-    alGetSourcef(This->al_src, AL_PITCH, &ratio);
-
-    *pRatio = ratio;
+    return FAudioSourceVoice_GetFrequencyRatio(This->faudio_voice, pRatio);
 }
 
 static HRESULT WINAPI XA2SRC_SetSourceSampleRate(
     IXAudio2SourceVoice *iface,
     UINT32 NewSourceSampleRate)
 {
-    XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2SourceVoice(iface);
 
     TRACE("%p, %u\n", This, NewSourceSampleRate);
 
-    EnterCriticalSection(&This->lock);
-
-    if(This->nbufs){
-        LeaveCriticalSection(&This->lock);
-        return COMPAT_E_INVALID_CALL;
-    }
-
-    This->fmt->nSamplesPerSec = NewSourceSampleRate;
-
-    LeaveCriticalSection(&This->lock);
-
-    return S_OK;
+    return FAudioSourceVoice_SetSourceSampleRate(This->faudio_voice, NewSourceSampleRate);
 }
 
 static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl = {
@@ -888,134 +852,408 @@ static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl = {
     XA2SRC_SetSourceSampleRate
 };
 
+/* Submix Voices */
+
+static inline XA2VoiceImpl *impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice *iface)
+{
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio2SubmixVoice_iface);
+}
+
+static void WINAPI XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice *iface,
+        XAUDIO2_VOICE_DETAILS *pVoiceDetails)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %p\n", This, pVoiceDetails);
+    FAudioVoice_GetVoiceDetails(This->faudio_voice, (FAudioVoiceDetails *)pVoiceDetails);
+}
+
+static HRESULT WINAPI XA2SUB_SetOutputVoices(IXAudio2SubmixVoice *iface,
+        const XAUDIO2_VOICE_SENDS *pSendList)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    FAudioVoiceSends *faudio_sends;
+    HRESULT hr;
+
+    TRACE("%p, %p\n", This, pSendList);
+
+    faudio_sends = wrap_voice_sends(pSendList);
+
+    hr = FAudioVoice_SetOutputVoices(This->faudio_voice, faudio_sends);
+
+    free_voice_sends(faudio_sends);
+
+    return hr;
+}
+
+static HRESULT WINAPI XA2SUB_SetEffectChain(IXAudio2SubmixVoice *iface,
+        const XAUDIO2_EFFECT_CHAIN *pEffectChain)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    HRESULT hr;
+
+    TRACE("%p, %p\n", This, pEffectChain);
+
+    free_effect_chain(This->effect_chain);
+    This->effect_chain = wrap_effect_chain(pEffectChain);
+
+    hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
+
+    return hr;
+}
+
+static HRESULT WINAPI XA2SUB_EnableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
+        UINT32 OperationSet)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
+    return FAudioVoice_EnableEffect(This->faudio_voice, EffectIndex, OperationSet);
+}
+
+static HRESULT WINAPI XA2SUB_DisableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
+        UINT32 OperationSet)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
+    return FAudioVoice_DisableEffect(This->faudio_voice, EffectIndex, OperationSet);
+}
+
+static void WINAPI XA2SUB_GetEffectState(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
+        BOOL *pEnabled)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
+    FAudioVoice_GetEffectState(This->faudio_voice, EffectIndex, (int32_t*)pEnabled);
+}
+
+static HRESULT WINAPI XA2SUB_SetEffectParameters(IXAudio2SubmixVoice *iface,
+        UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
+        UINT32 OperationSet)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
+            ParametersByteSize, OperationSet);
+    return FAudioVoice_SetEffectParameters(This->faudio_voice, EffectIndex,
+            pParameters, ParametersByteSize, OperationSet);
+}
+
+static HRESULT WINAPI XA2SUB_GetEffectParameters(IXAudio2SubmixVoice *iface,
+        UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
+            ParametersByteSize);
+    return FAudioVoice_GetEffectParameters(This->faudio_voice, EffectIndex,
+            pParameters, ParametersByteSize);
+}
+
+static HRESULT WINAPI XA2SUB_SetFilterParameters(IXAudio2SubmixVoice *iface,
+        const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
+    return FAudioVoice_SetFilterParameters(This->faudio_voice, (const FAudioFilterParameters *)pParameters,
+            OperationSet);
+}
+
+static void WINAPI XA2SUB_GetFilterParameters(IXAudio2SubmixVoice *iface,
+        XAUDIO2_FILTER_PARAMETERS *pParameters)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %p\n", This, pParameters);
+    FAudioVoice_GetFilterParameters(This->faudio_voice, (FAudioFilterParameters *)pParameters);
+}
+
+static HRESULT WINAPI XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice *iface,
+        IXAudio2Voice *pDestinationVoice,
+        const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
+    TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
+
+    return FAudioVoice_SetOutputFilterParameters(This->faudio_voice,
+            dst ? dst->faudio_voice : NULL, (const FAudioFilterParameters *)pParameters, OperationSet);
+}
+
+static void WINAPI XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice *iface,
+        IXAudio2Voice *pDestinationVoice,
+        XAUDIO2_FILTER_PARAMETERS *pParameters)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
+    TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
+
+    FAudioVoice_GetOutputFilterParameters(This->faudio_voice,
+            dst ? dst->faudio_voice : NULL, (FAudioFilterParameters *)pParameters);
+}
+
+static HRESULT WINAPI XA2SUB_SetVolume(IXAudio2SubmixVoice *iface, float Volume,
+        UINT32 OperationSet)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
+    return FAudioVoice_SetVolume(This->faudio_voice, Volume, OperationSet);
+}
+
+static void WINAPI XA2SUB_GetVolume(IXAudio2SubmixVoice *iface, float *pVolume)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %p\n", This, pVolume);
+    return FAudioVoice_GetVolume(This->faudio_voice, pVolume);
+}
+
+static HRESULT WINAPI XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
+        const float *pVolumes, UINT32 OperationSet)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
+    return FAudioVoice_SetChannelVolumes(This->faudio_voice, Channels,
+            pVolumes, OperationSet);
+}
+
+static void WINAPI XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
+        float *pVolumes)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    TRACE("%p, %u, %p\n", This, Channels, pVolumes);
+    return FAudioVoice_GetChannelVolumes(This->faudio_voice, Channels,
+            pVolumes);
+}
+
+static HRESULT WINAPI XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice *iface,
+        IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
+        UINT32 DestinationChannels, const float *pLevelMatrix,
+        UINT32 OperationSet)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
+    TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
+            SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
+
+    return FAudioVoice_SetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
+            SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
+}
+
+static void WINAPI XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice *iface,
+        IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
+        UINT32 DestinationChannels, float *pLevelMatrix)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
+    TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
+            SourceChannels, DestinationChannels, pLevelMatrix);
+
+    FAudioVoice_GetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
+            SourceChannels, DestinationChannels, pLevelMatrix);
+}
+
+static void WINAPI XA2SUB_DestroyVoice(IXAudio2SubmixVoice *iface)
+{
+    XA2VoiceImpl *This = impl_from_IXAudio2SubmixVoice(iface);
+
+    TRACE("%p\n", This);
+
+    EnterCriticalSection(&This->lock);
+
+    destroy_voice(This);
+
+    LeaveCriticalSection(&This->lock);
+}
+
+static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl = {
+    XA2SUB_GetVoiceDetails,
+    XA2SUB_SetOutputVoices,
+    XA2SUB_SetEffectChain,
+    XA2SUB_EnableEffect,
+    XA2SUB_DisableEffect,
+    XA2SUB_GetEffectState,
+    XA2SUB_SetEffectParameters,
+    XA2SUB_GetEffectParameters,
+    XA2SUB_SetFilterParameters,
+    XA2SUB_GetFilterParameters,
+    XA2SUB_SetOutputFilterParameters,
+    XA2SUB_GetOutputFilterParameters,
+    XA2SUB_SetVolume,
+    XA2SUB_GetVolume,
+    XA2SUB_SetChannelVolumes,
+    XA2SUB_GetChannelVolumes,
+    XA2SUB_SetOutputMatrix,
+    XA2SUB_GetOutputMatrix,
+    XA2SUB_DestroyVoice
+};
+
+/* Mastering Voices */
+
+static inline XA2VoiceImpl *impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice *iface)
+{
+    return CONTAINING_RECORD(iface, XA2VoiceImpl, IXAudio2MasteringVoice_iface);
+}
+
 static void WINAPI XA2M_GetVoiceDetails(IXAudio2MasteringVoice *iface,
         XAUDIO2_VOICE_DETAILS *pVoiceDetails)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %p\n", This, pVoiceDetails);
-    pVoiceDetails->CreationFlags = 0;
-    pVoiceDetails->ActiveFlags = 0;
-    pVoiceDetails->InputChannels = This->fmt.Format.nChannels;
-    pVoiceDetails->InputSampleRate = This->fmt.Format.nSamplesPerSec;
+    FAudioVoice_GetVoiceDetails(This->faudio_voice, (FAudioVoiceDetails *)pVoiceDetails);
 }
 
 static HRESULT WINAPI XA2M_SetOutputVoices(IXAudio2MasteringVoice *iface,
         const XAUDIO2_VOICE_SENDS *pSendList)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
+    FAudioVoiceSends *faudio_sends;
+    HRESULT hr;
+
     TRACE("%p, %p\n", This, pSendList);
-    return S_OK;
+
+    faudio_sends = wrap_voice_sends(pSendList);
+
+    hr = FAudioVoice_SetOutputVoices(This->faudio_voice, faudio_sends);
+
+    free_voice_sends(faudio_sends);
+
+    return hr;
 }
 
 static HRESULT WINAPI XA2M_SetEffectChain(IXAudio2MasteringVoice *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
+    HRESULT hr;
+
     TRACE("%p, %p\n", This, pEffectChain);
-    return S_OK;
+
+    free_effect_chain(This->effect_chain);
+    This->effect_chain = wrap_effect_chain(pEffectChain);
+
+    hr = FAudioVoice_SetEffectChain(This->faudio_voice, This->effect_chain);
+
+    return hr;
 }
 
 static HRESULT WINAPI XA2M_EnableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
-    return S_OK;
+    return FAudioVoice_EnableEffect(This->faudio_voice, EffectIndex, OperationSet);
 }
 
 static HRESULT WINAPI XA2M_DisableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
-    return S_OK;
+    return FAudioVoice_DisableEffect(This->faudio_voice, EffectIndex, OperationSet);
 }
 
 static void WINAPI XA2M_GetEffectState(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
         BOOL *pEnabled)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
+    FAudioVoice_GetEffectState(This->faudio_voice, EffectIndex, (int32_t*)pEnabled);
 }
 
 static HRESULT WINAPI XA2M_SetEffectParameters(IXAudio2MasteringVoice *iface,
         UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
             ParametersByteSize, OperationSet);
-    return S_OK;
+    return FAudioVoice_SetEffectParameters(This->faudio_voice, EffectIndex,
+            pParameters, ParametersByteSize, OperationSet);
 }
 
 static HRESULT WINAPI XA2M_GetEffectParameters(IXAudio2MasteringVoice *iface,
         UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
             ParametersByteSize);
-    return S_OK;
+    return FAudioVoice_GetEffectParameters(This->faudio_voice, EffectIndex,
+            pParameters, ParametersByteSize);
 }
 
 static HRESULT WINAPI XA2M_SetFilterParameters(IXAudio2MasteringVoice *iface,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
-    return S_OK;
+    return FAudioVoice_SetFilterParameters(This->faudio_voice, (const FAudioFilterParameters *)pParameters,
+            OperationSet);
 }
 
 static void WINAPI XA2M_GetFilterParameters(IXAudio2MasteringVoice *iface,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %p\n", This, pParameters);
+    FAudioVoice_GetFilterParameters(This->faudio_voice, (FAudioFilterParameters *)pParameters);
 }
 
 static HRESULT WINAPI XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice *iface,
         IXAudio2Voice *pDestinationVoice,
         const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
     TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
-    return S_OK;
+
+    return FAudioVoice_SetOutputFilterParameters(This->faudio_voice,
+            dst ? dst->faudio_voice : NULL, (const FAudioFilterParameters *)pParameters, OperationSet);
 }
 
 static void WINAPI XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice *iface,
         IXAudio2Voice *pDestinationVoice,
         XAUDIO2_FILTER_PARAMETERS *pParameters)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
     TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
+
+    FAudioVoice_GetOutputFilterParameters(This->faudio_voice,
+            dst ? dst->faudio_voice : NULL, (FAudioFilterParameters *)pParameters);
 }
 
 static HRESULT WINAPI XA2M_SetVolume(IXAudio2MasteringVoice *iface, float Volume,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
-    return S_OK;
+    return FAudioVoice_SetVolume(This->faudio_voice, Volume, OperationSet);
 }
 
 static void WINAPI XA2M_GetVolume(IXAudio2MasteringVoice *iface, float *pVolume)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %p\n", This, pVolume);
+    return FAudioVoice_GetVolume(This->faudio_voice, pVolume);
 }
 
 static HRESULT WINAPI XA2M_SetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
         const float *pVolumes, UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
-    return S_OK;
+    return FAudioVoice_SetChannelVolumes(This->faudio_voice, Channels,
+            pVolumes, OperationSet);
 }
 
 static void WINAPI XA2M_GetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
         float *pVolumes)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
     TRACE("%p, %u, %p\n", This, Channels, pVolumes);
+    return FAudioVoice_GetChannelVolumes(This->faudio_voice, Channels,
+            pVolumes);
 }
 
 static HRESULT WINAPI XA2M_SetOutputMatrix(IXAudio2MasteringVoice *iface,
@@ -1023,60 +1261,58 @@ static HRESULT WINAPI XA2M_SetOutputMatrix(IXAudio2MasteringVoice *iface,
         UINT32 DestinationChannels, const float *pLevelMatrix,
         UINT32 OperationSet)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
     TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
             SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
-    return S_OK;
+
+    return FAudioVoice_SetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
+            SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
 }
 
 static void WINAPI XA2M_GetOutputMatrix(IXAudio2MasteringVoice *iface,
         IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
         UINT32 DestinationChannels, float *pLevelMatrix)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *dst = pDestinationVoice ? impl_from_IXAudio2Voice(pDestinationVoice) : NULL;
+
     TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
             SourceChannels, DestinationChannels, pLevelMatrix);
+
+    FAudioVoice_GetOutputMatrix(This->faudio_voice, dst ? dst->faudio_voice : NULL,
+            SourceChannels, DestinationChannels, pLevelMatrix);
 }
 
 static void WINAPI XA2M_DestroyVoice(IXAudio2MasteringVoice *iface)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
 
     TRACE("%p\n", This);
 
     EnterCriticalSection(&This->lock);
 
-    if(!This->aclient){
-        LeaveCriticalSection(&This->lock);
-        return;
-    }
-
-    This->running = FALSE;
-
-    IAudioRenderClient_Release(This->render);
-    This->render = NULL;
-
-    IAudioClient_Release(This->aclient);
-    This->aclient = NULL;
+    destroy_voice(This);
+    pthread_mutex_lock(&This->engine_lock);
+    This->engine_params.proc = NULL;
+    pthread_cond_broadcast(&This->engine_ready);
+    pthread_mutex_unlock(&This->engine_lock);
 
-    alcDestroyContext(This->al_ctx);
-    This->al_ctx = NULL;
-
-    alcCloseDevice(This->al_device);
-    This->al_device = NULL;
+    WaitForSingleObject(This->engine_thread, INFINITE);
+    This->engine_thread = NULL;
 
     LeaveCriticalSection(&This->lock);
 }
 
-/* not present in XAudio2 2.7 */
 static void WINAPI XA2M_GetChannelMask(IXAudio2MasteringVoice *iface,
         DWORD *pChannelMask)
 {
-    IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
+    XA2VoiceImpl *This = impl_from_IXAudio2MasteringVoice(iface);
 
-    TRACE("%p %p\n", This, pChannelMask);
+    TRACE("%p, %p\n", This, pChannelMask);
 
-    *pChannelMask = This->fmt.dwChannelMask;
+    FAudioMasteringVoice_GetChannelMask(This->faudio_voice, pChannelMask);
 }
 
 static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl = {
@@ -1102,190 +1338,49 @@ static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl = {
     XA2M_GetChannelMask
 };
 
-static void WINAPI XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice *iface,
-        XAUDIO2_VOICE_DETAILS *pVoiceDetails)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-
-    TRACE("%p, %p\n", This, pVoiceDetails);
-
-    *pVoiceDetails = This->details;
-}
-
-static HRESULT WINAPI XA2SUB_SetOutputVoices(IXAudio2SubmixVoice *iface,
-        const XAUDIO2_VOICE_SENDS *pSendList)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p\n", This, pSendList);
-    return S_OK;
-}
-
-static HRESULT WINAPI XA2SUB_SetEffectChain(IXAudio2SubmixVoice *iface,
-        const XAUDIO2_EFFECT_CHAIN *pEffectChain)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p\n", This, pEffectChain);
-    return S_OK;
-}
-
-static HRESULT WINAPI XA2SUB_EnableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
-        UINT32 OperationSet)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
-    return S_OK;
-}
-
-static HRESULT WINAPI XA2SUB_DisableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
-        UINT32 OperationSet)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
-    return S_OK;
-}
-
-static void WINAPI XA2SUB_GetEffectState(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
-        BOOL *pEnabled)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
-}
-
-static HRESULT WINAPI XA2SUB_SetEffectParameters(IXAudio2SubmixVoice *iface,
-        UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
-        UINT32 OperationSet)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
-            ParametersByteSize, OperationSet);
-    return S_OK;
-}
-
-static HRESULT WINAPI XA2SUB_GetEffectParameters(IXAudio2SubmixVoice *iface,
-        UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
-            ParametersByteSize);
-    return S_OK;
-}
-
-static HRESULT WINAPI XA2SUB_SetFilterParameters(IXAudio2SubmixVoice *iface,
-        const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
-    return S_OK;
-}
-
-static void WINAPI XA2SUB_GetFilterParameters(IXAudio2SubmixVoice *iface,
-        XAUDIO2_FILTER_PARAMETERS *pParameters)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p\n", This, pParameters);
-}
-
-static HRESULT WINAPI XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice *iface,
-        IXAudio2Voice *pDestinationVoice,
-        const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
-    return S_OK;
-}
-
-static void WINAPI XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice *iface,
-        IXAudio2Voice *pDestinationVoice,
-        XAUDIO2_FILTER_PARAMETERS *pParameters)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
-}
-
-static HRESULT WINAPI XA2SUB_SetVolume(IXAudio2SubmixVoice *iface, float Volume,
-        UINT32 OperationSet)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
-    return S_OK;
-}
-
-static void WINAPI XA2SUB_GetVolume(IXAudio2SubmixVoice *iface, float *pVolume)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p\n", This, pVolume);
-}
-
-static HRESULT WINAPI XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
-        const float *pVolumes, UINT32 OperationSet)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
-    return S_OK;
-}
-
-static void WINAPI XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
-        float *pVolumes)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %u, %p\n", This, Channels, pVolumes);
-}
+/* More Common Voice Functions */
 
-static HRESULT WINAPI XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice *iface,
-        IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
-        UINT32 DestinationChannels, const float *pLevelMatrix,
-        UINT32 OperationSet)
+static XA2VoiceImpl *impl_from_IXAudio2Voice(IXAudio2Voice *iface)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
-            SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
-    return S_OK;
+    if(iface->lpVtbl == (void*)&XAudio2SourceVoice_Vtbl)
+        return impl_from_IXAudio2SourceVoice((IXAudio2SourceVoice*)iface);
+    if(iface->lpVtbl == (void*)&XAudio2MasteringVoice_Vtbl)
+        return impl_from_IXAudio2MasteringVoice((IXAudio2MasteringVoice*)iface);
+    if(iface->lpVtbl == (void*)&XAudio2SubmixVoice_Vtbl)
+        return impl_from_IXAudio2SubmixVoice((IXAudio2SubmixVoice*)iface);
+#if XAUDIO2_VER == 0
+    if(iface->lpVtbl == (void*)&XAudio20SourceVoice_Vtbl)
+        return impl_from_IXAudio20SourceVoice((IXAudio20SourceVoice*)iface);
+    if(iface->lpVtbl == (void*)&XAudio20SubmixVoice_Vtbl)
+        return impl_from_IXAudio20SubmixVoice((IXAudio20SubmixVoice*)iface);
+    if(iface->lpVtbl == (void*)&XAudio20MasteringVoice_Vtbl)
+        return impl_from_IXAudio20MasteringVoice((IXAudio20MasteringVoice*)iface);
+#elif XAUDIO2_VER <= 3
+    if(iface->lpVtbl == (void*)&XAudio23SourceVoice_Vtbl)
+        return impl_from_IXAudio23SourceVoice((IXAudio23SourceVoice*)iface);
+    if(iface->lpVtbl == (void*)&XAudio23SubmixVoice_Vtbl)
+        return impl_from_IXAudio23SubmixVoice((IXAudio23SubmixVoice*)iface);
+    if(iface->lpVtbl == (void*)&XAudio23MasteringVoice_Vtbl)
+        return impl_from_IXAudio23MasteringVoice((IXAudio23MasteringVoice*)iface);
+#elif XAUDIO2_VER <= 7
+    if(iface->lpVtbl == (void*)&XAudio27SourceVoice_Vtbl)
+        return impl_from_IXAudio27SourceVoice((IXAudio27SourceVoice*)iface);
+    if(iface->lpVtbl == (void*)&XAudio27SubmixVoice_Vtbl)
+        return impl_from_IXAudio27SubmixVoice((IXAudio27SubmixVoice*)iface);
+    if(iface->lpVtbl == (void*)&XAudio27MasteringVoice_Vtbl)
+        return impl_from_IXAudio27MasteringVoice((IXAudio27MasteringVoice*)iface);
+#endif
+    ERR("invalid IXAudio2Voice pointer: %p\n", iface);
+    return NULL;
 }
 
-static void WINAPI XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice *iface,
-        IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
-        UINT32 DestinationChannels, float *pLevelMatrix)
-{
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-    TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
-            SourceChannels, DestinationChannels, pLevelMatrix);
-}
+/* XAudio2 Engine Implementation */
 
-static void WINAPI XA2SUB_DestroyVoice(IXAudio2SubmixVoice *iface)
+static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
 {
-    XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
-
-    TRACE("%p\n", This);
-
-    EnterCriticalSection(&This->lock);
-
-    This->in_use = FALSE;
-
-    LeaveCriticalSection(&This->lock);
+    return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2_iface);
 }
 
-static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl = {
-    XA2SUB_GetVoiceDetails,
-    XA2SUB_SetOutputVoices,
-    XA2SUB_SetEffectChain,
-    XA2SUB_EnableEffect,
-    XA2SUB_DisableEffect,
-    XA2SUB_GetEffectState,
-    XA2SUB_SetEffectParameters,
-    XA2SUB_GetEffectParameters,
-    XA2SUB_SetFilterParameters,
-    XA2SUB_GetFilterParameters,
-    XA2SUB_SetOutputFilterParameters,
-    XA2SUB_GetOutputFilterParameters,
-    XA2SUB_SetVolume,
-    XA2SUB_GetVolume,
-    XA2SUB_SetChannelVolumes,
-    XA2SUB_GetChannelVolumes,
-    XA2SUB_SetOutputMatrix,
-    XA2SUB_GetOutputMatrix,
-    XA2SUB_DestroyVoice
-};
-
 static HRESULT WINAPI IXAudio2Impl_QueryInterface(IXAudio2 *iface, REFIID riid,
         void **ppvObject)
 {
@@ -1326,7 +1421,7 @@ static HRESULT WINAPI IXAudio2Impl_QueryInterface(IXAudio2 *iface, REFIID riid,
 static ULONG WINAPI IXAudio2Impl_AddRef(IXAudio2 *iface)
 {
     IXAudio2Impl *This = impl_from_IXAudio2(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    ULONG ref = FAudio_AddRef(This->faudio);
     TRACE("(%p)->(): Refcount now %u\n", This, ref);
     return ref;
 }
@@ -1334,48 +1429,21 @@ static ULONG WINAPI IXAudio2Impl_AddRef(IXAudio2 *iface)
 static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
 {
     IXAudio2Impl *This = impl_from_IXAudio2(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    ULONG ref = FAudio_Release(This->faudio);
 
     TRACE("(%p)->(): Refcount now %u\n", This, ref);
 
     if (!ref) {
-        int i;
-        XA2SourceImpl *src, *src2;
-        XA2SubmixImpl *sub, *sub2;
-
-        if(This->engine){
-            This->stop_engine = TRUE;
-            SetEvent(This->mmevt);
-            WaitForSingleObject(This->engine, INFINITE);
-            CloseHandle(This->engine);
-        }
-
-        LIST_FOR_EACH_ENTRY_SAFE(src, src2, &This->source_voices, XA2SourceImpl, entry){
-            HeapFree(GetProcessHeap(), 0, src->sends);
-            IXAudio2SourceVoice_DestroyVoice(&src->IXAudio2SourceVoice_iface);
-            src->lock.DebugInfo->Spare[0] = 0;
-            DeleteCriticalSection(&src->lock);
-            HeapFree(GetProcessHeap(), 0, src);
-        }
+        XA2VoiceImpl *v, *v2;
 
-        LIST_FOR_EACH_ENTRY_SAFE(sub, sub2, &This->submix_voices, XA2SubmixImpl, entry){
-            IXAudio2SubmixVoice_DestroyVoice(&sub->IXAudio2SubmixVoice_iface);
-            sub->lock.DebugInfo->Spare[0] = 0;
-            DeleteCriticalSection(&sub->lock);
-            HeapFree(GetProcessHeap(), 0, sub);
+        LIST_FOR_EACH_ENTRY_SAFE(v, v2, &This->voices, XA2VoiceImpl, entry){
+            v->lock.DebugInfo->Spare[0] = 0;
+            DeleteCriticalSection(&v->lock);
+            HeapFree(GetProcessHeap(), 0, v);
         }
 
-        IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
-
-        if(This->devenum)
-            IMMDeviceEnumerator_Release(This->devenum);
-        for(i = 0; i < This->ndevs; ++i)
-            CoTaskMemFree(This->devids[i]);
-        HeapFree(GetProcessHeap(), 0, This->devids);
         HeapFree(GetProcessHeap(), 0, This->cbs);
 
-        CloseHandle(This->mmevt);
-
         This->lock.DebugInfo->Spare[0] = 0;
         DeleteCriticalSection(&This->lock);
 
@@ -1402,8 +1470,8 @@ static HRESULT WINAPI IXAudio2Impl_RegisterForCallbacks(IXAudio2 *iface,
         }
     }
 
-    This->ncbs *= 2;
-    This->cbs = HeapReAlloc(GetProcessHeap(), 0, This->cbs, This->ncbs * sizeof(*This->cbs));
+    This->ncbs++;
+    This->cbs = heap_realloc(This->cbs, This->ncbs * sizeof(*This->cbs));
 
     This->cbs[i] = pCallback;
 
@@ -1422,6 +1490,11 @@ static void WINAPI IXAudio2Impl_UnregisterForCallbacks(IXAudio2 *iface,
 
     EnterCriticalSection(&This->lock);
 
+    if(This->ncbs == 0){
+        LeaveCriticalSection(&This->lock);
+        return;
+    }
+
     for(i = 0; i < This->ncbs; ++i){
         if(This->cbs[i] == pCallback)
             break;
@@ -1436,20 +1509,40 @@ static void WINAPI IXAudio2Impl_UnregisterForCallbacks(IXAudio2 *iface,
     LeaveCriticalSection(&This->lock);
 }
 
-static WAVEFORMATEX *copy_waveformat(const WAVEFORMATEX *wfex)
+static inline XA2VoiceImpl *create_voice(IXAudio2Impl *This)
 {
-    WAVEFORMATEX *pwfx;
+    XA2VoiceImpl *voice;
 
-    if(wfex->wFormatTag == WAVE_FORMAT_PCM){
-        pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX));
-        CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
-        pwfx->cbSize = 0;
-    }else{
-        pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX) + wfex->cbSize);
-        CopyMemory(pwfx, wfex, sizeof(WAVEFORMATEX) + wfex->cbSize);
-    }
+    voice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*voice));
+    if(!voice)
+        return NULL;
+
+    list_add_head(&This->voices, &voice->entry);
+
+    voice->IXAudio2SourceVoice_iface.lpVtbl = &XAudio2SourceVoice_Vtbl;
+#if XAUDIO2_VER == 0
+    voice->IXAudio20SourceVoice_iface.lpVtbl = &XAudio20SourceVoice_Vtbl;
+#elif XAUDIO2_VER <= 3
+    voice->IXAudio23SourceVoice_iface.lpVtbl = &XAudio23SourceVoice_Vtbl;
+#elif XAUDIO2_VER <= 7
+    voice->IXAudio27SourceVoice_iface.lpVtbl = &XAudio27SourceVoice_Vtbl;
+#endif
+
+    voice->IXAudio2SubmixVoice_iface.lpVtbl = &XAudio2SubmixVoice_Vtbl;
+#if XAUDIO2_VER == 0
+    voice->IXAudio20SubmixVoice_iface.lpVtbl = &XAudio20SubmixVoice_Vtbl;
+#elif XAUDIO2_VER <= 3
+    voice->IXAudio23SubmixVoice_iface.lpVtbl = &XAudio23SubmixVoice_Vtbl;
+#elif XAUDIO2_VER <= 7
+    voice->IXAudio27SubmixVoice_iface.lpVtbl = &XAudio27SubmixVoice_Vtbl;
+#endif
+
+    voice->FAudioVoiceCallback_vtbl = FAudioVoiceCallback_Vtbl;
+
+    InitializeCriticalSection(&voice->lock);
+    voice->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2VoiceImpl.lock");
 
-    return pwfx;
+    return voice;
 }
 
 static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
@@ -1459,94 +1552,44 @@ static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
     IXAudio2Impl *This = impl_from_IXAudio2(iface);
-    XA2SourceImpl *src;
+    XA2VoiceImpl *src;
     HRESULT hr;
+    FAudioVoiceSends *faudio_sends;
 
     TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This, ppSourceVoice,
             pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList,
             pEffectChain);
 
-    dump_fmt(pSourceFormat);
-
-    palcSetThreadContext(This->al_ctx);
-
     EnterCriticalSection(&This->lock);
 
-    LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
+    LIST_FOR_EACH_ENTRY(src, &This->voices, XA2VoiceImpl, entry){
         EnterCriticalSection(&src->lock);
         if(!src->in_use)
             break;
         LeaveCriticalSection(&src->lock);
     }
 
-    if(&src->entry == &This->source_voices){
-        src = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*src));
-        if(!src){
-            LeaveCriticalSection(&This->lock);
-            return E_OUTOFMEMORY;
-        }
-
-        list_add_head(&This->source_voices, &src->entry);
-
-        src->IXAudio2SourceVoice_iface.lpVtbl = &XAudio2SourceVoice_Vtbl;
-
-#if XAUDIO2_VER == 0
-        src->IXAudio20SourceVoice_iface.lpVtbl = &XAudio20SourceVoice_Vtbl;
-#elif XAUDIO2_VER <= 3
-        src->IXAudio23SourceVoice_iface.lpVtbl = &XAudio23SourceVoice_Vtbl;
-#elif XAUDIO2_VER <= 7
-        src->IXAudio27SourceVoice_iface.lpVtbl = &XAudio27SourceVoice_Vtbl;
-#endif
-
-        InitializeCriticalSection(&src->lock);
-        src->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SourceImpl.lock");
-
-        src->xa2 = This;
-
+    if(&src->entry == &This->voices){
+        src = create_voice(This);
         EnterCriticalSection(&src->lock);
     }
 
-    src->in_use = TRUE;
-    src->running = FALSE;
-
     LeaveCriticalSection(&This->lock);
 
-    src->cb = pCallback;
-
-    src->al_fmt = get_al_format(pSourceFormat);
-    if(!src->al_fmt){
-        src->in_use = FALSE;
-        LeaveCriticalSection(&src->lock);
-        WARN("OpenAL can't convert this format!\n");
-        return AUDCLNT_E_UNSUPPORTED_FORMAT;
-    }
+    src->effect_chain = wrap_effect_chain(pEffectChain);
+    faudio_sends = wrap_voice_sends(pSendList);
 
-    src->submit_blocksize = pSourceFormat->nBlockAlign;
-
-    src->fmt = copy_waveformat(pSourceFormat);
-
-    hr = XA2SRC_SetOutputVoices(&src->IXAudio2SourceVoice_iface, pSendList);
+    hr = FAudio_CreateSourceVoice(This->faudio, &src->faudio_voice,
+            (FAudioWaveFormatEx*)pSourceFormat, flags, maxFrequencyRatio,
+            &src->FAudioVoiceCallback_vtbl, faudio_sends,
+            src->effect_chain);
+    free_voice_sends(faudio_sends);
     if(FAILED(hr)){
-        HeapFree(GetProcessHeap(), 0, src->fmt);
-        src->in_use = FALSE;
-        LeaveCriticalSection(&src->lock);
+        LeaveCriticalSection(&This->lock);
         return hr;
     }
-
-    alGenSources(1, &src->al_src);
-    if(!src->al_src){
-        static int once = 0;
-        if(!once++)
-            ERR_(winediag)("OpenAL ran out of sources, consider increasing its source limit.\n");
-        HeapFree(GetProcessHeap(), 0, src->fmt);
-        src->in_use = FALSE;
-        LeaveCriticalSection(&src->lock);
-        return E_OUTOFMEMORY;
-    }
-
-    alGenBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, src->al_bufs);
-
-    alSourcePlay(src->al_src);
+    src->in_use = TRUE;
+    src->cb = pCallback;
 
     LeaveCriticalSection(&src->lock);
 
@@ -1571,8 +1614,10 @@ static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
         const XAUDIO2_VOICE_SENDS *pSendList,
         const XAUDIO2_EFFECT_CHAIN *pEffectChain)
 {
+    HRESULT hr;
     IXAudio2Impl *This = impl_from_IXAudio2(iface);
-    XA2SubmixImpl *sub;
+    XA2VoiceImpl *sub;
+    FAudioVoiceSends *faudio_sends;
 
     TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This, ppSubmixVoice,
             inputChannels, inputSampleRate, flags, processingStage, pSendList,
@@ -1580,46 +1625,33 @@ static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
 
     EnterCriticalSection(&This->lock);
 
-    LIST_FOR_EACH_ENTRY(sub, &This->submix_voices, XA2SubmixImpl, entry){
+    LIST_FOR_EACH_ENTRY(sub, &This->voices, XA2VoiceImpl, entry){
         EnterCriticalSection(&sub->lock);
         if(!sub->in_use)
             break;
         LeaveCriticalSection(&sub->lock);
     }
 
-    if(&sub->entry == &This->submix_voices){
-        sub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*sub));
-        if(!sub){
-            LeaveCriticalSection(&This->lock);
-            return E_OUTOFMEMORY;
-        }
-
-        list_add_head(&This->submix_voices, &sub->entry);
-
-        sub->IXAudio2SubmixVoice_iface.lpVtbl = &XAudio2SubmixVoice_Vtbl;
+    if(&sub->entry == &This->voices){
+        sub = create_voice(This);
+        EnterCriticalSection(&sub->lock);
+    }
 
-#if XAUDIO2_VER == 0
-        sub->IXAudio20SubmixVoice_iface.lpVtbl = &XAudio20SubmixVoice_Vtbl;
-#elif XAUDIO2_VER <= 3
-        sub->IXAudio23SubmixVoice_iface.lpVtbl = &XAudio23SubmixVoice_Vtbl;
-#elif XAUDIO2_VER <= 7
-        sub->IXAudio27SubmixVoice_iface.lpVtbl = &XAudio27SubmixVoice_Vtbl;
-#endif
+    LeaveCriticalSection(&This->lock);
 
-        InitializeCriticalSection(&sub->lock);
-        sub->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SubmixImpl.lock");
+    sub->effect_chain = wrap_effect_chain(pEffectChain);
+    faudio_sends = wrap_voice_sends(pSendList);
 
-        EnterCriticalSection(&sub->lock);
+    hr = FAudio_CreateSubmixVoice(This->faudio, &sub->faudio_voice, inputChannels,
+            inputSampleRate, flags, processingStage, faudio_sends,
+            sub->effect_chain);
+    free_voice_sends(faudio_sends);
+    if(FAILED(hr)){
+        LeaveCriticalSection(&sub->lock);
+        return hr;
     }
-
     sub->in_use = TRUE;
 
-    sub->details.CreationFlags = flags;
-    sub->details.ActiveFlags = flags;
-    sub->details.InputChannels = inputChannels;
-    sub->details.InputSampleRate = inputSampleRate;
-
-    LeaveCriticalSection(&This->lock);
     LeaveCriticalSection(&sub->lock);
 
 #if XAUDIO2_VER == 0
@@ -1637,25 +1669,46 @@ static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
     return S_OK;
 }
 
-static ALenum al_get_loopback_format(const WAVEFORMATEXTENSIBLE *fmt)
+/* called thread created by SDL, must not access Wine TEB */
+void engine_cb(FAudioEngineCallEXT proc, FAudio *faudio, float *stream, void *user)
+{
+    XA2VoiceImpl *This = user;
+
+    pthread_mutex_lock(&This->engine_lock);
+
+    This->engine_params.proc = proc;
+    This->engine_params.stream = stream;
+    This->engine_params.faudio = faudio;
+
+    pthread_cond_broadcast(&This->engine_ready);
+
+    while(This->engine_params.proc)
+        pthread_cond_wait(&This->engine_done, &This->engine_lock);
+
+    pthread_mutex_unlock(&This->engine_lock);
+}
+
+/* wine thread, OK to access TEB, invoke client code, etc */
+DWORD WINAPI engine_thread(void *user)
 {
-    if(fmt->Format.wFormatTag == WAVE_FORMAT_PCM ||
-            (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-             IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
-        switch(fmt->Format.wBitsPerSample){
-        case 8:
-            return ALC_UNSIGNED_BYTE_SOFT;
-        case 16:
-            return ALC_SHORT_SOFT;
-        case 32:
-            return ALC_INT_SOFT;
+    XA2VoiceImpl *This = user;
+
+    pthread_mutex_lock(&This->engine_lock);
+
+    pthread_cond_broadcast(&This->engine_done);
+
+    do{
+        pthread_cond_wait(&This->engine_ready, &This->engine_lock);
+
+        if(This->engine_params.proc){
+            This->engine_params.proc(This->engine_params.faudio, This->engine_params.stream);
+            This->engine_params.proc = NULL;
+            pthread_cond_broadcast(&This->engine_done);
         }
-    }else if(fmt->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
-            (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-             IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
-        if(fmt->Format.wBitsPerSample == 32)
-            return ALC_FLOAT_SOFT;
-    }
+    }while(This->in_use);
+
+    pthread_mutex_unlock(&This->engine_lock);
+
     return 0;
 }
 
@@ -1666,251 +1719,60 @@ static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
         AUDIO_STREAM_CATEGORY streamCategory)
 {
     IXAudio2Impl *This = impl_from_IXAudio2(iface);
-    IMMDevice *dev;
-    HRESULT hr;
-    WAVEFORMATEX *fmt;
-    ALCint attrs[11];
-    REFERENCE_TIME period, bufdur;
 
     TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This,
             ppMasteringVoice, inputChannels, inputSampleRate, flags,
             wine_dbgstr_w(deviceId), pEffectChain, streamCategory);
 
-    if(flags != 0)
-        WARN("Unknown flags set: 0x%x\n", flags);
-
-    if(pEffectChain)
-        WARN("Effect chain is unimplemented\n");
-
     EnterCriticalSection(&This->lock);
 
-    /* there can only be one Mastering Voice, so just build it into XA2 */
-    if(This->aclient){
-        LeaveCriticalSection(&This->lock);
-        return COMPAT_E_INVALID_CALL;
-    }
-
-    if(!deviceId){
-        if(This->ndevs == 0){
-            LeaveCriticalSection(&This->lock);
-            return E_NOTFOUND;
-        }
-        deviceId = This->devids[0];
-    }
-
-    hr = IMMDeviceEnumerator_GetDevice(This->devenum, deviceId, &dev);
-    if(FAILED(hr)){
-        WARN("GetDevice failed: %08x\n", hr);
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
-
-    hr = IMMDevice_Activate(dev, &IID_IAudioClient,
-            CLSCTX_INPROC_SERVER, NULL, (void**)&This->aclient);
-    if(FAILED(hr)){
-        WARN("Activate(IAudioClient) failed: %08x\n", hr);
-        IMMDevice_Release(dev);
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
-
-    IMMDevice_Release(dev);
-
-    hr = IAudioClient_GetMixFormat(This->aclient, &fmt);
-    if(FAILED(hr)){
-        WARN("GetMixFormat failed: %08x\n", hr);
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
-
-    if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
-        FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
-
-    if(inputChannels == XAUDIO2_DEFAULT_CHANNELS)
-        inputChannels = fmt->nChannels;
-    if(inputSampleRate == XAUDIO2_DEFAULT_SAMPLERATE)
-        inputSampleRate = fmt->nSamplesPerSec;
-
-    memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
-    This->fmt.Format.nChannels = inputChannels;
-    This->fmt.Format.nSamplesPerSec = inputSampleRate;
-    This->fmt.Format.nBlockAlign = This->fmt.Format.nChannels * This->fmt.Format.wBitsPerSample / 8;
-    This->fmt.Format.nAvgBytesPerSec = This->fmt.Format.nSamplesPerSec * This->fmt.Format.nBlockAlign;
-    This->fmt.dwChannelMask = get_channel_mask(This->fmt.Format.nChannels);
-
-    CoTaskMemFree(fmt);
-    fmt = NULL;
-
-    hr = IAudioClient_IsFormatSupported(This->aclient,
-            AUDCLNT_SHAREMODE_SHARED, &This->fmt.Format, &fmt);
-    if(hr == S_FALSE){
-        if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
-            FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
-            hr = COMPAT_E_DEVICE_INVALIDATED;
-            goto exit;
-        }
-        memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
-    }
-
-    CoTaskMemFree(fmt);
-
-    hr = IAudioClient_GetDevicePeriod(This->aclient, &period, NULL);
-    if(FAILED(hr)){
-        WARN("GetDevicePeriod failed: %08x\n", hr);
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
-
-    /* 3 periods or 0.1 seconds */
-    bufdur = max(3 * period, 1000000);
+    /* Note that we don't have paths for each XAUDIO2_VER here.
+     * All versions < 8 have a very different CreateMasteringVoice, so we
+     * implement those separately in compat.c.
+     * -flibit
+     */
+    *ppMasteringVoice = &This->mst.IXAudio2MasteringVoice_iface;
 
-    hr = IAudioClient_Initialize(This->aclient, AUDCLNT_SHAREMODE_SHARED,
-            AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufdur,
-            0, &This->fmt.Format, NULL);
-    if(FAILED(hr)){
-        WARN("Initialize failed: %08x\n", hr);
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
-
-    This->period_frames = MulDiv(period, inputSampleRate, 10000000);
-
-    hr = IAudioClient_SetEventHandle(This->aclient, This->mmevt);
-    if(FAILED(hr)){
-        WARN("Initialize failed: %08x\n", hr);
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
-
-    hr = IAudioClient_GetService(This->aclient, &IID_IAudioRenderClient,
-            (void**)&This->render);
-    if(FAILED(hr)){
-        WARN("GetService(IAudioRenderClient) failed: %08x\n", hr);
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
+    EnterCriticalSection(&This->mst.lock);
 
-    /* setup openal context */
-    attrs[0] = ALC_FORMAT_CHANNELS_SOFT;
-    switch(inputChannels){
-    case 1:
-        attrs[1] = ALC_MONO_SOFT;
-        break;
-    case 2:
-        attrs[1] = ALC_STEREO_SOFT;
-        break;
-    case 4:
-        attrs[1] = ALC_QUAD_SOFT;
-        break;
-    case 6:
-        attrs[1] = ALC_5POINT1_SOFT;
-        break;
-    case 7:
-        attrs[1] = ALC_6POINT1_SOFT;
-        break;
-    case 8:
-        attrs[1] = ALC_7POINT1_SOFT;
-        break;
-    default:
-        WARN("OpenAL doesn't support %u channels\n", inputChannels);
+    if(This->mst.in_use){
+        LeaveCriticalSection(&This->mst.lock);
         LeaveCriticalSection(&This->lock);
-        return AUDCLNT_E_UNSUPPORTED_FORMAT;
+        return COMPAT_E_INVALID_CALL;
     }
 
-    attrs[2] = ALC_FREQUENCY;
-    attrs[3] = inputSampleRate;
-
-    attrs[4] = ALC_FORMAT_TYPE_SOFT;
-    attrs[5] = al_get_loopback_format(&This->fmt);
+    LeaveCriticalSection(&This->lock);
 
-    /* some games create very many sources */
-    attrs[6] = ALC_STEREO_SOURCES;
-    attrs[7] = 1024;
-    attrs[8] = ALC_MONO_SOURCES;
-    attrs[9] = 1024;
+    This->mst.effect_chain = wrap_effect_chain(pEffectChain);
 
-    attrs[10] = 0;
+    pthread_mutex_lock(&This->mst.engine_lock);
 
-    if(!attrs[5]){
-        WARN("OpenAL can't output samples in this format\n");
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
+    This->mst.engine_thread = CreateThread(NULL, 0, &engine_thread, &This->mst, 0, NULL);
 
-    This->al_device = palcLoopbackOpenDeviceSOFT(NULL);
-    if(!This->al_device){
-        WARN("alcLoopbackOpenDeviceSOFT failed\n");
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
+    pthread_cond_wait(&This->mst.engine_done, &This->mst.engine_lock);
 
-    This->al_ctx = alcCreateContext(This->al_device, attrs);
-    if(!This->al_ctx){
-        WARN("alcCreateContext failed\n");
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
+    pthread_mutex_unlock(&This->mst.engine_lock);
 
-    hr = IAudioClient_Start(This->aclient);
-    if (FAILED(hr))
-    {
-        WARN("Start(IAudioClient) failed: %08x\n", hr);
-        hr = COMPAT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
+    FAudio_SetEngineProcedureEXT(This->faudio, &engine_cb, &This->mst);
 
-#if XAUDIO2_VER == 0
-    *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio20MasteringVoice_iface;
-#elif XAUDIO2_VER <= 3
-    *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio23MasteringVoice_iface;
-#elif XAUDIO2_VER <= 7
-    *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio27MasteringVoice_iface;
-#else
-    *ppMasteringVoice = &This->IXAudio2MasteringVoice_iface;
-#endif
+    FAudio_CreateMasteringVoice8(This->faudio, &This->mst.faudio_voice, inputChannels,
+            inputSampleRate, flags, NULL /* TODO: (uint16_t*)deviceId */,
+            This->mst.effect_chain, (FAudioStreamCategory)streamCategory);
 
-exit:
-    if(FAILED(hr)){
-        if(This->render){
-            IAudioRenderClient_Release(This->render);
-            This->render = NULL;
-        }
-        if(This->aclient){
-            IAudioClient_Release(This->aclient);
-            This->aclient = NULL;
-        }
-        if(This->al_ctx){
-            alcDestroyContext(This->al_ctx);
-            This->al_ctx = NULL;
-        }
-        if(This->al_device){
-            alcCloseDevice(This->al_device);
-            This->al_device = NULL;
-        }
-    }
+    This->mst.in_use = TRUE;
 
-    LeaveCriticalSection(&This->lock);
+    LeaveCriticalSection(&This->mst.lock);
 
-    return hr;
+    return S_OK;
 }
 
-static DWORD WINAPI engine_threadproc(void *arg);
-
 static HRESULT WINAPI IXAudio2Impl_StartEngine(IXAudio2 *iface)
 {
     IXAudio2Impl *This = impl_from_IXAudio2(iface);
 
     TRACE("(%p)->()\n", This);
 
-    This->running = TRUE;
-
-    if(!This->engine)
-        This->engine = CreateThread(NULL, 0, engine_threadproc, This, 0, NULL);
-
-    return S_OK;
+    return FAudio_StartEngine(This->faudio);
 }
 
 static void WINAPI IXAudio2Impl_StopEngine(IXAudio2 *iface)
@@ -1919,7 +1781,7 @@ static void WINAPI IXAudio2Impl_StopEngine(IXAudio2 *iface)
 
     TRACE("(%p)->()\n", This);
 
-    This->running = FALSE;
+    FAudio_StopEngine(This->faudio);
 }
 
 static HRESULT WINAPI IXAudio2Impl_CommitChanges(IXAudio2 *iface,
@@ -1929,7 +1791,7 @@ static HRESULT WINAPI IXAudio2Impl_CommitChanges(IXAudio2 *iface,
 
     TRACE("(%p)->(0x%x): stub!\n", This, operationSet);
 
-    return E_NOTIMPL;
+    return FAudio_CommitChanges(This->faudio);
 }
 
 static void WINAPI IXAudio2Impl_GetPerformanceData(IXAudio2 *iface,
@@ -1939,7 +1801,7 @@ static void WINAPI IXAudio2Impl_GetPerformanceData(IXAudio2 *iface,
 
     TRACE("(%p)->(%p): stub!\n", This, pPerfData);
 
-    memset(pPerfData, 0, sizeof(*pPerfData));
+    FAudio_GetPerformanceData(This->faudio, (FAudioPerformanceData *)pPerfData);
 }
 
 static void WINAPI IXAudio2Impl_SetDebugConfiguration(IXAudio2 *iface,
@@ -1948,7 +1810,9 @@ static void WINAPI IXAudio2Impl_SetDebugConfiguration(IXAudio2 *iface,
 {
     IXAudio2Impl *This = impl_from_IXAudio2(iface);
 
-    FIXME("(%p)->(%p, %p): stub!\n", This, pDebugConfiguration, pReserved);
+    TRACE("(%p)->(%p, %p): stub!\n", This, pDebugConfiguration, pReserved);
+
+    FAudio_SetDebugConfiguration(This->faudio, (FAudioDebugConfiguration *)pDebugConfiguration, pReserved);
 }
 
 /* XAudio2 2.8 */
@@ -1969,6 +1833,8 @@ static const IXAudio2Vtbl XAudio2_Vtbl =
     IXAudio2Impl_SetDebugConfiguration
 };
 
+/* XAudio2 ClassFactory */
+
 struct xaudio2_cf {
     IClassFactory IClassFactory_iface;
     LONG ref;
@@ -2012,79 +1878,6 @@ static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
     return ref;
 }
 
-static HRESULT initialize_mmdevices(IXAudio2Impl *This)
-{
-    IMMDeviceCollection *devcoll;
-    UINT devcount;
-    HRESULT hr;
-
-    if(!This->devenum){
-        hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
-                CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&This->devenum);
-        if(FAILED(hr))
-            return hr;
-    }
-
-    hr = IMMDeviceEnumerator_EnumAudioEndpoints(This->devenum, eRender,
-            DEVICE_STATE_ACTIVE, &devcoll);
-    if(FAILED(hr)){
-        return hr;
-    }
-
-    hr = IMMDeviceCollection_GetCount(devcoll, &devcount);
-    if(FAILED(hr)){
-        IMMDeviceCollection_Release(devcoll);
-        return hr;
-    }
-
-    if(devcount > 0){
-        UINT i, count = 1;
-        IMMDevice *dev, *def_dev;
-
-        /* make sure that device 0 is the default device */
-        IMMDeviceEnumerator_GetDefaultAudioEndpoint(This->devenum, eRender, eConsole, &def_dev);
-
-        This->devids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * devcount);
-
-        for(i = 0; i < devcount; ++i){
-            hr = IMMDeviceCollection_Item(devcoll, i, &dev);
-            if(SUCCEEDED(hr)){
-                UINT idx;
-
-                if(dev == def_dev)
-                    idx = 0;
-                else{
-                    idx = count;
-                    ++count;
-                }
-
-                hr = IMMDevice_GetId(dev, &This->devids[idx]);
-                if(FAILED(hr)){
-                    WARN("GetId failed: %08x\n", hr);
-                    HeapFree(GetProcessHeap(), 0, This->devids);
-                    This->devids = NULL;
-                    IMMDevice_Release(dev);
-                    return hr;
-                }
-
-                IMMDevice_Release(dev);
-            }else{
-                WARN("Item failed: %08x\n", hr);
-                HeapFree(GetProcessHeap(), 0, This->devids);
-                This->devids = NULL;
-                IMMDeviceCollection_Release(devcoll);
-                return hr;
-            }
-        }
-    }
-
-    IMMDeviceCollection_Release(devcoll);
-
-    This->ndevs = devcount;
-
-    return S_OK;
-}
-
 static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
                                                REFIID riid, void **ppobj)
 {
@@ -2104,7 +1897,6 @@ static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *p
         return E_OUTOFMEMORY;
 
     object->IXAudio2_iface.lpVtbl = &XAudio2_Vtbl;
-    object->IXAudio2MasteringVoice_iface.lpVtbl = &XAudio2MasteringVoice_Vtbl;
 
 #if XAUDIO2_VER == 0
     object->IXAudio20_iface.lpVtbl = &XAudio20_Vtbl;
@@ -2114,38 +1906,48 @@ static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *p
     object->IXAudio27_iface.lpVtbl = &XAudio27_Vtbl;
 #endif
 
+    object->mst.IXAudio2MasteringVoice_iface.lpVtbl = &XAudio2MasteringVoice_Vtbl;
+
 #if XAUDIO2_VER == 0
-    object->IXAudio20MasteringVoice_iface.lpVtbl = &XAudio20MasteringVoice_Vtbl;
+    object->mst.IXAudio20MasteringVoice_iface.lpVtbl = &XAudio20MasteringVoice_Vtbl;
 #elif XAUDIO2_VER <= 3
-    object->IXAudio23MasteringVoice_iface.lpVtbl = &XAudio23MasteringVoice_Vtbl;
+    object->mst.IXAudio23MasteringVoice_iface.lpVtbl = &XAudio23MasteringVoice_Vtbl;
 #elif XAUDIO2_VER <= 7
-    object->IXAudio27MasteringVoice_iface.lpVtbl = &XAudio27MasteringVoice_Vtbl;
+    object->mst.IXAudio27MasteringVoice_iface.lpVtbl = &XAudio27MasteringVoice_Vtbl;
 #endif
 
-    list_init(&object->source_voices);
-    list_init(&object->submix_voices);
+    object->FAudioEngineCallback_vtbl = FAudioEngineCallback_Vtbl;
+
+    list_init(&object->voices);
 
-    object->mmevt = CreateEventW(NULL, FALSE, FALSE, NULL);
     InitializeCriticalSection(&object->lock);
     object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock");
 
+    InitializeCriticalSection(&object->mst.lock);
+    object->mst.lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2MasteringVoice.lock");
+
+    pthread_mutex_init(&object->mst.engine_lock, NULL);
+    pthread_cond_init(&object->mst.engine_done, NULL);
+    pthread_cond_init(&object->mst.engine_ready, NULL);
+
+    FAudioCOMConstructWithCustomAllocatorEXT(
+        &object->faudio,
+        XAUDIO2_VER,
+        XAudio_Internal_Malloc,
+        XAudio_Internal_Free,
+        XAudio_Internal_Realloc
+    );
+
+    FAudio_RegisterForCallbacks(object->faudio, &object->FAudioEngineCallback_vtbl);
+
     hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj);
     if(FAILED(hr)){
+        object->lock.DebugInfo->Spare[0] = 0;
+        DeleteCriticalSection(&object->lock);
         HeapFree(GetProcessHeap(), 0, object);
         return hr;
     }
 
-    hr = initialize_mmdevices(object);
-    if(FAILED(hr)){
-        IUnknown_Release((IUnknown*)*ppobj);
-        return hr;
-    }
-
-    object->ncbs = 4;
-    object->cbs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->ncbs * sizeof(*object->cbs));
-
-    IXAudio2_StartEngine(&object->IXAudio2_iface);
-
     TRACE("Created XAudio version %u: %p\n", 20 + XAUDIO2_VER, object);
 
     return hr;
@@ -2167,7 +1969,9 @@ static const IClassFactoryVtbl XAudio2CF_Vtbl =
     XAudio2CF_LockServer
 };
 
-static HRESULT make_xaudio2_factory(REFIID riid, void **ppv)
+/* Engine Generators */
+
+static inline HRESULT make_xaudio2_factory(REFIID riid, void **ppv)
 {
     HRESULT hr;
     struct xaudio2_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf));
@@ -2179,6 +1983,13 @@ static HRESULT make_xaudio2_factory(REFIID riid, void **ppv)
     return hr;
 }
 
+HRESULT xaudio2_initialize(IXAudio2Impl *This, UINT32 flags, XAUDIO2_PROCESSOR proc)
+{
+    if(proc != XAUDIO2_ANY_PROCESSOR)
+        WARN("Processor affinity not implemented in FAudio\n");
+    return FAudio_Initialize(This->faudio, flags, FAUDIO_DEFAULT_PROCESSOR);
+}
+
 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
 {
     TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
@@ -2211,18 +2022,11 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
                 IsEqualGUID(rclsid, &CLSID_AudioReverb25) ||
                 IsEqualGUID(rclsid, &CLSID_AudioReverb26) ||
                 IsEqualGUID(rclsid, &CLSID_AudioReverb27))
-        return make_xapo_factory(&CLSID_FXReverb, riid, ppv);
+        return make_xapo_factory(&CLSID_AudioReverb27, riid, ppv);
 
     return CLASS_E_CLASSNOTAVAILABLE;
 }
 
-HRESULT xaudio2_initialize(IXAudio2Impl *This, UINT32 flags, XAUDIO2_PROCESSOR proc)
-{
-    if(flags)
-        FIXME("Unimplemented flags: 0x%x\n", flags);
-    return S_OK;
-}
-
 #if XAUDIO2_VER >= 8
 HRESULT WINAPI XAudio2Create(IXAudio2 **ppxa2, UINT32 flags, XAUDIO2_PROCESSOR proc)
 {
@@ -2251,284 +2055,36 @@ HRESULT WINAPI XAudio2Create(IXAudio2 **ppxa2, UINT32 flags, XAUDIO2_PROCESSOR p
 
     return S_OK;
 }
-#endif /* XAUDIO2_VER >= 8 */
-
-/* returns TRUE if there is more data available in the buffer, FALSE if the
- * buffer's data has all been queued */
-static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al_buf)
-{
-    UINT32 submit_bytes;
-    const BYTE *submit_buf = NULL;
-
-    if(buf->offs_bytes >= buf->cur_end_bytes){
-        WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
-        return FALSE;
-    }
-
-    submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes);
-    submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes;
-    buf->offs_bytes += submit_bytes;
-
-    alBufferData(al_buf, src->al_fmt, submit_buf, submit_bytes,
-            src->fmt->nSamplesPerSec);
-
-    alSourceQueueBuffers(src->al_src, 1, &al_buf);
-
-    src->in_al_bytes += submit_bytes;
-    src->al_bufs_used++;
-
-    buf->latest_al_buf = al_buf;
-
-    TRACE("queueing %u bytes, now %u in AL\n", submit_bytes, src->in_al_bytes);
-
-    return buf->offs_bytes < buf->cur_end_bytes;
-}
-
-#if XAUDIO2_VER > 0
-static UINT32 get_underrun_warning(XA2SourceImpl *src)
-{
-    UINT32 period_bytes = src->xa2->period_frames * src->submit_blocksize;
-    UINT32 total = 0, i;
-
-    for(i = 0; i < src->nbufs && total < IN_AL_PERIODS * period_bytes; ++i){
-        XA2Buffer *buf = &src->buffers[(src->first_buf + i) % XAUDIO2_MAX_QUEUED_BUFFERS];
-        total += buf->cur_end_bytes - buf->offs_bytes;
-        if(buf->xa2buffer.LoopCount == XAUDIO2_LOOP_INFINITE)
-            return 0;
-        if(buf->xa2buffer.LoopCount > 0){
-            total += (buf->loop_end_bytes - buf->xa2buffer.LoopBegin) * (buf->xa2buffer.LoopCount - buf->looped);
-            total += buf->play_end_bytes - buf->loop_end_bytes;
-        }
-    }
-
-    if(total >= IN_AL_PERIODS * period_bytes)
-        return 0;
-
-    return ((IN_AL_PERIODS * period_bytes - total) / period_bytes + 1) * period_bytes;
-}
-#endif
-
-/* Looping:
- *
- * The looped section of a buffer is a subset of the play area which is looped
- * LoopCount times.
- *
- *       v PlayBegin
- *       vvvvvvvvvvvvvvvvvv PlayLength
- *                        v (PlayEnd)
- * [-----PPPLLLLLLLLPPPPPPP------]
- *          ^ LoopBegin
- *          ^^^^^^^^ LoopLength
- *                 ^ (LoopEnd)
- *
- * In the simple case, playback will start at PlayBegin. At LoopEnd, playback
- * will move to LoopBegin and repeat that loop LoopCount times. Then, playback
- * will cease at PlayEnd.
- *
- * If PlayLength is zero, then PlayEnd is the end of the buffer.
- *
- * If LoopLength is zero, then LoopEnd is PlayEnd.
- *
- * For corner cases and version differences, see tests.
- */
-static void update_source_state(XA2SourceImpl *src)
-{
-    int i;
-    ALint processed;
-    ALint bufpos;
-
-    alGetSourcei(src->al_src, AL_BUFFERS_PROCESSED, &processed);
-
-    if(processed > 0){
-        ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
-
-        alSourceUnqueueBuffers(src->al_src, processed, al_buffers);
-
-        src->first_al_buf += processed;
-        src->first_al_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
-        src->al_bufs_used -= processed;
-
-        for(i = 0; i < processed; ++i){
-            ALint bufsize;
-
-            alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
-
-            src->in_al_bytes -= bufsize;
-
-            if(src->abandoned_albufs == 0){
-                src->played_frames += bufsize / src->submit_blocksize;
-
-                if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
-                    DWORD old_buf = src->first_buf;
-
-                    src->first_buf++;
-                    src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
-                    src->nbufs--;
-
-                    TRACE("%p: done with buffer %u\n", src, old_buf);
-
-                    if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
-                        src->played_frames = 0;
-
-                    if(src->cb){
-                        IXAudio2VoiceCallback_OnBufferEnd(src->cb,
-                                src->buffers[old_buf].xa2buffer.pContext);
-                        if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
-                            IXAudio2VoiceCallback_OnStreamEnd(src->cb);
-
-                        if(src->nbufs > 0)
-                            IXAudio2VoiceCallback_OnBufferStart(src->cb,
-                                    src->buffers[src->first_buf].xa2buffer.pContext);
-                    }
-                }
-            }else{
-                src->abandoned_albufs--;
-            }
-        }
-    }
-
-    if(!src->running)
-        return;
-
-    alGetSourcei(src->al_src, AL_BYTE_OFFSET, &bufpos);
-
-    /* maintain IN_AL_PERIODS periods in AL */
-    while(src->cur_buf != (src->first_buf + src->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS &&
-            src->in_al_bytes - bufpos < IN_AL_PERIODS * src->xa2->period_frames * src->submit_blocksize){
-        TRACE("%p: going to queue a period from buffer %u\n", src, src->cur_buf);
-
-        /* starting from an empty buffer */
-        if(src->cb && src->cur_buf == src->first_buf && src->buffers[src->cur_buf].offs_bytes == 0 && !src->buffers[src->cur_buf].looped)
-            IXAudio2VoiceCallback_OnBufferStart(src->cb,
-                    src->buffers[src->first_buf].xa2buffer.pContext);
-
-        if(!xa2buffer_queue_period(src, &src->buffers[src->cur_buf],
-                    src->al_bufs[(src->first_al_buf + src->al_bufs_used) % XAUDIO2_MAX_QUEUED_BUFFERS])){
-            XA2Buffer *cur = &src->buffers[src->cur_buf];
-
-            if(cur->looped < cur->xa2buffer.LoopCount){
-                if(cur->xa2buffer.LoopCount != XAUDIO2_LOOP_INFINITE)
-                    ++cur->looped;
-                else
-                    cur->looped = 1; /* indicate that we are executing a loop */
-
-                cur->offs_bytes = cur->xa2buffer.LoopBegin;
-                if(cur->looped == cur->xa2buffer.LoopCount)
-                    cur->cur_end_bytes = cur->play_end_bytes;
-                else
-                    cur->cur_end_bytes = cur->loop_end_bytes;
-
-                if(src->cb)
-                    IXAudio2VoiceCallback_OnLoopEnd(src->cb,
-                            src->buffers[src->cur_buf].xa2buffer.pContext);
-
-            }else{
-                /* buffer is spent, move on */
-                src->cur_buf++;
-                src->cur_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
-            }
-        }
-    }
-}
 
-static void do_engine_tick(IXAudio2Impl *This)
+HRESULT WINAPI CreateAudioVolumeMeter(IUnknown **out)
 {
-    BYTE *buf;
-    XA2SourceImpl *src;
+    IClassFactory *cf;
     HRESULT hr;
-    UINT32 nframes, i, pad;
-
-    /* maintain up to 3 periods in mmdevapi */
-    hr = IAudioClient_GetCurrentPadding(This->aclient, &pad);
-    if(FAILED(hr)){
-        WARN("GetCurrentPadding failed: 0x%x\n", hr);
-        return;
-    }
-
-    nframes = This->period_frames * 3 - pad;
-
-    TRACE("frames available: %u\n", nframes);
-
-    if(nframes < This->period_frames)
-        return;
-
-    if(!nframes)
-        return;
-
-    for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
-        IXAudio2EngineCallback_OnProcessingPassStart(This->cbs[i]);
-
-    LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
-        ALint st = 0;
-
-        EnterCriticalSection(&src->lock);
-
-        if(!src->in_use){
-            LeaveCriticalSection(&src->lock);
-            continue;
-        }
-
-        if(src->cb && This->running){
-#if XAUDIO2_VER == 0
-            IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback*)src->cb);
-#else
-            UINT32 underrun;
-            underrun = get_underrun_warning(src);
-            if(underrun > 0)
-                TRACE("Calling OnVoiceProcessingPassStart with BytesRequired: %u\n", underrun);
-            IXAudio2VoiceCallback_OnVoiceProcessingPassStart(src->cb, underrun);
-#endif
-        }
-
-        update_source_state(src);
-
-        if(This->running){
-            alGetSourcei(src->al_src, AL_SOURCE_STATE, &st);
-            if(st != AL_PLAYING)
-                alSourcePlay(src->al_src);
-
-            if(src->cb)
-                IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src->cb);
-        }
 
-        LeaveCriticalSection(&src->lock);
-    }
-
-    hr = IAudioRenderClient_GetBuffer(This->render, nframes, &buf);
+    hr = make_xapo_factory(&CLSID_AudioVolumeMeter27, &IID_IClassFactory, (void**)&cf);
     if(FAILED(hr))
-        WARN("GetBuffer failed: %08x\n", hr);
+        return hr;
 
-    palcRenderSamplesSOFT(This->al_device, buf, nframes);
+    hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)out);
 
-    hr = IAudioRenderClient_ReleaseBuffer(This->render, nframes, 0);
-    if(FAILED(hr))
-        WARN("ReleaseBuffer failed: %08x\n", hr);
+    IClassFactory_Release(cf);
 
-    for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
-        IXAudio2EngineCallback_OnProcessingPassEnd(This->cbs[i]);
+    return hr;
 }
 
-static DWORD WINAPI engine_threadproc(void *arg)
+HRESULT WINAPI CreateAudioReverb(IUnknown **out)
 {
-    IXAudio2Impl *This = arg;
-    while(1){
-        WaitForSingleObject(This->mmevt, INFINITE);
-
-        if(This->stop_engine)
-            break;
-
-        EnterCriticalSection(&This->lock);
+    IClassFactory *cf;
+    HRESULT hr;
 
-        if(!This->running || !This->aclient){
-            LeaveCriticalSection(&This->lock);
-            continue;
-        }
+    hr = make_xapo_factory(&CLSID_AudioReverb27, &IID_IClassFactory, (void**)&cf);
+    if(FAILED(hr))
+        return hr;
 
-        palcSetThreadContext(This->al_ctx);
+    hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)out);
 
-        do_engine_tick(This);
+    IClassFactory_Release(cf);
 
-        LeaveCriticalSection(&This->lock);
-    }
-    return 0;
+    return hr;
 }
+#endif /* XAUDIO2_VER >= 8 */
diff --git a/dlls/xaudio2_7/xaudio_private.h b/dlls/xaudio2_7/xaudio_private.h
index 5d3814fb9e..84bab8257d 100644
--- a/dlls/xaudio2_7/xaudio_private.h
+++ b/dlls/xaudio2_7/xaudio_private.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015 Andrew Eikum for CodeWeavers
+ * Copyright (c) 2018 Ethan Lee for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -17,33 +18,42 @@
  */
 
 #include "windef.h"
-#include "winbase.h"
-#include "winuser.h"
 #include "wine/list.h"
 
-#include "mmsystem.h"
 #include "xaudio2.h"
-#include "xaudio2fx.h"
 #include "xapo.h"
-#include "devpkey.h"
-#include "mmdeviceapi.h"
-#include "audioclient.h"
 
-#include <AL/al.h>
-#include <AL/alc.h>
-#include <AL/alext.h>
+#include <FAudio.h>
+#include <FAPO.h>
 
-typedef struct _XA2Buffer {
-    XAUDIO2_BUFFER xa2buffer;
-    DWORD offs_bytes;
-    UINT32 latest_al_buf, looped, loop_end_bytes, play_end_bytes, cur_end_bytes;
-} XA2Buffer;
+#include <pthread.h>
 
-typedef struct _IXAudio2Impl IXAudio2Impl;
+#if XAUDIO2_VER == 0
+#define COMPAT_E_INVALID_CALL E_INVALIDARG
+#define COMPAT_E_DEVICE_INVALIDATED XAUDIO20_E_DEVICE_INVALIDATED
+#else
+#define COMPAT_E_INVALID_CALL XAUDIO2_E_INVALID_CALL
+#define COMPAT_E_DEVICE_INVALIDATED XAUDIO2_E_DEVICE_INVALIDATED
+#endif
 
-typedef struct _XA2SourceImpl {
-    IXAudio2SourceVoice IXAudio2SourceVoice_iface;
+typedef struct _XA2XAPOImpl {
+    IXAPO *xapo;
+    IXAPOParameters *xapo_params;
+
+    LONG ref;
+
+    FAPO FAPO_vtbl;
+} XA2XAPOImpl;
+
+typedef struct _XA2XAPOFXImpl {
+    IXAPO IXAPO_iface;
+    IXAPOParameters IXAPOParameters_iface;
+
+    FAPO *fapo;
+} XA2XAPOFXImpl;
 
+typedef struct _XA2VoiceImpl {
+    IXAudio2SourceVoice IXAudio2SourceVoice_iface;
 #if XAUDIO2_VER == 0
     IXAudio20SourceVoice IXAudio20SourceVoice_iface;
 #elif XAUDIO2_VER <= 3
@@ -52,43 +62,7 @@ typedef struct _XA2SourceImpl {
     IXAudio27SourceVoice IXAudio27SourceVoice_iface;
 #endif
 
-    IXAudio2Impl *xa2;
-
-    BOOL in_use;
-
-    CRITICAL_SECTION lock;
-
-    WAVEFORMATEX *fmt;
-    ALenum al_fmt;
-    UINT32 submit_blocksize;
-
-    IXAudio2VoiceCallback *cb;
-
-    DWORD nsends;
-    XAUDIO2_SEND_DESCRIPTOR *sends;
-
-    BOOL running;
-
-    UINT64 played_frames;
-
-    XA2Buffer buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
-    UINT32 first_buf, cur_buf, nbufs, in_al_bytes;
-
-    UINT32 scratch_bytes, convert_bytes;
-    BYTE *scratch_buf, *convert_buf;
-
-    ALuint al_src;
-    /* most cases will only need about 4 AL buffers, but some corner cases
-     * could require up to MAX_QUEUED_BUFFERS */
-    ALuint al_bufs[XAUDIO2_MAX_QUEUED_BUFFERS];
-    DWORD first_al_buf, al_bufs_used, abandoned_albufs;
-
-    struct list entry;
-} XA2SourceImpl;
-
-typedef struct _XA2SubmixImpl {
     IXAudio2SubmixVoice IXAudio2SubmixVoice_iface;
-
 #if XAUDIO2_VER == 0
     IXAudio20SubmixVoice IXAudio20SubmixVoice_iface;
 #elif XAUDIO2_VER <= 3
@@ -97,18 +71,41 @@ typedef struct _XA2SubmixImpl {
     IXAudio27SubmixVoice IXAudio27SubmixVoice_iface;
 #endif
 
-    BOOL in_use;
+    IXAudio2MasteringVoice IXAudio2MasteringVoice_iface;
+#if XAUDIO2_VER == 0
+    IXAudio20MasteringVoice IXAudio20MasteringVoice_iface;
+#elif XAUDIO2_VER <= 3
+    IXAudio23MasteringVoice IXAudio23MasteringVoice_iface;
+#elif XAUDIO2_VER <= 7
+    IXAudio27MasteringVoice IXAudio27MasteringVoice_iface;
+#endif
 
-    XAUDIO2_VOICE_DETAILS details;
+    FAudioVoiceCallback FAudioVoiceCallback_vtbl;
+    FAudioEffectChain *effect_chain;
+
+    BOOL in_use;
 
     CRITICAL_SECTION lock;
 
+    IXAudio2VoiceCallback *cb;
+
+    FAudioVoice *faudio_voice;
+
+    struct {
+        FAudioEngineCallEXT proc;
+        FAudio *faudio;
+        float *stream;
+    } engine_params;
+
+    HANDLE engine_thread;
+    pthread_cond_t engine_done, engine_ready;
+    pthread_mutex_t engine_lock;
+
     struct list entry;
-} XA2SubmixImpl;
+} XA2VoiceImpl;
 
-struct _IXAudio2Impl {
+typedef struct _IXAudio2Impl {
     IXAudio2 IXAudio2_iface;
-    IXAudio2MasteringVoice IXAudio2MasteringVoice_iface;
 
 #if XAUDIO2_VER == 0
     IXAudio20 IXAudio20_iface;
@@ -118,59 +115,43 @@ struct _IXAudio2Impl {
     IXAudio27 IXAudio27_iface;
 #endif
 
-#if XAUDIO2_VER == 0
-    IXAudio20MasteringVoice IXAudio20MasteringVoice_iface;
-#elif XAUDIO2_VER <= 3
-    IXAudio23MasteringVoice IXAudio23MasteringVoice_iface;
-#elif XAUDIO2_VER <= 7
-    IXAudio27MasteringVoice IXAudio27MasteringVoice_iface;
-#endif
-
-    LONG ref;
-
     CRITICAL_SECTION lock;
 
-    HANDLE engine, mmevt;
-    BOOL stop_engine;
-
-    struct list source_voices;
-    struct list submix_voices;
-
-    IMMDeviceEnumerator *devenum;
+    struct list voices;
 
-    WCHAR **devids;
-    UINT32 ndevs;
+    FAudio *faudio;
 
-    UINT32 last_query_glitches;
+    FAudioEngineCallback FAudioEngineCallback_vtbl;
 
-    IAudioClient *aclient;
-    IAudioRenderClient *render;
+    XA2VoiceImpl mst;
 
-    UINT32 period_frames;
-
-    WAVEFORMATEXTENSIBLE fmt;
-
-    ALCdevice *al_device;
-    ALCcontext *al_ctx;
+    DWORD last_query_glitches;
 
     UINT32 ncbs;
     IXAudio2EngineCallback **cbs;
-
-    BOOL running;
-};
+} IXAudio2Impl;
 
 #if XAUDIO2_VER == 0
 extern const IXAudio20SourceVoiceVtbl XAudio20SourceVoice_Vtbl DECLSPEC_HIDDEN;
 extern const IXAudio20SubmixVoiceVtbl XAudio20SubmixVoice_Vtbl DECLSPEC_HIDDEN;
 extern const IXAudio20MasteringVoiceVtbl XAudio20MasteringVoice_Vtbl DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio20SourceVoice(IXAudio20SourceVoice *iface) DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio20SubmixVoice(IXAudio20SubmixVoice *iface) DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio20MasteringVoice(IXAudio20MasteringVoice *iface) DECLSPEC_HIDDEN;
 #elif XAUDIO2_VER <= 3
 extern const IXAudio23SourceVoiceVtbl XAudio23SourceVoice_Vtbl DECLSPEC_HIDDEN;
 extern const IXAudio23SubmixVoiceVtbl XAudio23SubmixVoice_Vtbl DECLSPEC_HIDDEN;
 extern const IXAudio23MasteringVoiceVtbl XAudio23MasteringVoice_Vtbl DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio23SourceVoice(IXAudio23SourceVoice *iface) DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio23SubmixVoice(IXAudio23SubmixVoice *iface) DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio23MasteringVoice(IXAudio23MasteringVoice *iface) DECLSPEC_HIDDEN;
 #elif XAUDIO2_VER <= 7
 extern const IXAudio27SourceVoiceVtbl XAudio27SourceVoice_Vtbl DECLSPEC_HIDDEN;
 extern const IXAudio27SubmixVoiceVtbl XAudio27SubmixVoice_Vtbl DECLSPEC_HIDDEN;
 extern const IXAudio27MasteringVoiceVtbl XAudio27MasteringVoice_Vtbl DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio27SourceVoice(IXAudio27SourceVoice *iface) DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio27SubmixVoice(IXAudio27SubmixVoice *iface) DECLSPEC_HIDDEN;
+extern XA2VoiceImpl *impl_from_IXAudio27MasteringVoice(IXAudio27MasteringVoice *iface) DECLSPEC_HIDDEN;
 #endif
 
 #if XAUDIO2_VER == 0
@@ -181,5 +162,16 @@ extern const IXAudio22Vtbl XAudio22_Vtbl DECLSPEC_HIDDEN;
 extern const IXAudio27Vtbl XAudio27_Vtbl DECLSPEC_HIDDEN;
 #endif
 
-extern HRESULT make_xapo_factory(REFCLSID clsid, REFIID riid, void **ppv) DECLSPEC_HIDDEN;
+/* xaudio_dll.c */
 extern HRESULT xaudio2_initialize(IXAudio2Impl *This, UINT32 flags, XAUDIO2_PROCESSOR proc) DECLSPEC_HIDDEN;
+extern FAudioEffectChain *wrap_effect_chain(const XAUDIO2_EFFECT_CHAIN *pEffectChain) DECLSPEC_HIDDEN;
+extern void engine_cb(FAudioEngineCallEXT proc, FAudio *faudio, float *stream, void *user) DECLSPEC_HIDDEN;
+extern DWORD WINAPI engine_thread(void *user) DECLSPEC_HIDDEN;
+
+/* xapo.c */
+extern HRESULT make_xapo_factory(REFCLSID clsid, REFIID riid, void **ppv) DECLSPEC_HIDDEN;
+
+/* xaudio_allocator.c */
+extern void* XAudio_Internal_Malloc(size_t size) DECLSPEC_HIDDEN;
+extern void XAudio_Internal_Free(void* ptr) DECLSPEC_HIDDEN;
+extern void* XAudio_Internal_Realloc(void* ptr, size_t size) DECLSPEC_HIDDEN;
diff --git a/dlls/xaudio2_8/Makefile.in b/dlls/xaudio2_8/Makefile.in
index d4efc41d5c..b591b1141b 100644
--- a/dlls/xaudio2_8/Makefile.in
+++ b/dlls/xaudio2_8/Makefile.in
@@ -1,13 +1,16 @@
 EXTRADEFS = -DXAUDIO2_VER=8
 MODULE    = xaudio2_8.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	x3daudio.c \
 	xapofx.c \
-	xaudio_dll.c
+	x3daudio.c \
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
diff --git a/dlls/xaudio2_9/Makefile.in b/dlls/xaudio2_9/Makefile.in
index ceb2216f5a..99f1bd0deb 100644
--- a/dlls/xaudio2_9/Makefile.in
+++ b/dlls/xaudio2_9/Makefile.in
@@ -1,13 +1,16 @@
 EXTRADEFS = -DXAUDIO2_VER=9
 MODULE    = xaudio2_9.dll
 IMPORTS   = advapi32 ole32 user32 uuid
-EXTRALIBS = $(OPENAL_LIBS)
 PARENTSRC = ../xaudio2_7
+EXTRALIBS = $(FAUDIO_LIBS)
+EXTRAINCL = $(FAUDIO_CFLAGS)
 
 C_SRCS = \
+	xaudio_allocator.c \
 	compat.c \
-	x3daudio.c \
 	xapofx.c \
-	xaudio_dll.c
+	x3daudio.c \
+	xaudio_dll.c \
+	xapo.c
 
 IDL_SRCS = xaudio_classes.idl
-- 
2.17.2




More information about the wine-devel mailing list