- Implement usermode mixing support
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 17 Aug 2009 13:49:19 +0000 (13:49 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 17 Aug 2009 13:49:19 +0000 (13:49 +0000)
- To enable, see wdmaud rbuild

svn path=/trunk/; revision=42757

reactos/dll/win32/wdmaud.drv/mixer.c [new file with mode: 0644]
reactos/dll/win32/wdmaud.drv/wdmaud.c
reactos/dll/win32/wdmaud.drv/wdmaud.rbuild

diff --git a/reactos/dll/win32/wdmaud.drv/mixer.c b/reactos/dll/win32/wdmaud.drv/mixer.c
new file mode 100644 (file)
index 0000000..65fdb16
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * PROJECT:     ReactOS Sound System
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        dll/win32/wdmaud.drv/mixer.c
+ *
+ * PURPOSE:     WDM Audio Driver (User-mode part)
+ * PROGRAMMERS: Johannes Anderwald
+ */
+
+#include <windows.h>
+#include <ntddsnd.h>
+#include <sndtypes.h>
+#include <mmddk.h>
+#include <mmebuddy.h>
+
+#include <ks.h>
+#include <ksmedia.h>
+#include <samplerate.h>
+#include <float_cast.h>
+#include <debug.h>
+#include "interface.h"
+
+
+extern HANDLE KernelHandle;
+
+DWORD
+PerformSampleRateConversion(
+    PUCHAR Buffer,
+    ULONG BufferLength,
+    ULONG OldRate,
+    ULONG NewRate,
+    ULONG BytesPerSample,
+    ULONG NumChannels,
+    PVOID * Result,
+    PULONG ResultLength)
+{
+    ULONG Index;
+    SRC_STATE * State;
+    SRC_DATA Data;
+    PUCHAR ResultOut;
+    int error;
+    PFLOAT FloatIn, FloatOut;
+    ULONG NumSamples;
+    ULONG NewSamples;
+
+    SND_TRACE(L"PerformSampleRateConversion OldRate %u NewRate %u BytesPerSample %u NumChannels %u\n", OldRate, NewRate, BytesPerSample, NumChannels);
+
+    ASSERT(BytesPerSample == 1 || BytesPerSample == 2 || BytesPerSample == 4);
+
+    NumSamples = BufferLength / (BytesPerSample * NumChannels);
+
+    FloatIn = HeapAlloc(GetProcessHeap(), 0, NumSamples * NumChannels * sizeof(FLOAT));
+    if (!FloatIn)
+    {
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+
+    NewSamples = lrintf(((FLOAT)NumSamples * ((FLOAT)NewRate / (FLOAT)OldRate))) + 2;
+
+    FloatOut = HeapAlloc(GetProcessHeap(), 0, NewSamples * NumChannels * sizeof(FLOAT));
+    if (!FloatOut)
+    {
+        HeapFree(GetProcessHeap(), 0,FloatIn);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+
+    ResultOut = HeapAlloc(GetProcessHeap(), 0, NewSamples * NumChannels * BytesPerSample);
+    if (!ResultOut)
+    {
+        HeapFree(GetProcessHeap(), 0,FloatIn);
+        HeapFree(GetProcessHeap(), 0,FloatOut);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+
+    State = src_new(SRC_SINC_FASTEST, NumChannels, &error);
+    if (!State)
+    {
+        HeapFree(GetProcessHeap(), 0,FloatIn);
+        HeapFree(GetProcessHeap(), 0,FloatOut);
+        HeapFree(GetProcessHeap(), 0,ResultOut);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+
+    /* fixme use asm */
+    if (BytesPerSample == 1)
+    {
+        for(Index = 0; Index < NumSamples * NumChannels; Index++)
+            FloatIn[Index] = (float)(Buffer[Index] / (1.0 * 0x80));
+    }
+    else if (BytesPerSample == 2)
+    {
+        src_short_to_float_array((short*)Buffer, FloatIn, NumSamples * NumChannels);
+    }
+    else if (BytesPerSample == 4)
+    {
+        src_int_to_float_array((int*)Buffer, FloatIn, NumSamples * NumChannels);
+    }
+
+    Data.data_in = FloatIn;
+    Data.data_out = FloatOut;
+    Data.input_frames = NumSamples;
+    Data.output_frames = NewSamples;
+    Data.src_ratio = (double)NewRate / (double)OldRate;
+
+    error = src_process(State, &Data);
+    if (error)
+    {
+        DPRINT1("src_process failed with %x\n", error);
+        HeapFree(GetProcessHeap(), 0,FloatIn);
+        HeapFree(GetProcessHeap(), 0,FloatOut);
+        HeapFree(GetProcessHeap(), 0,ResultOut);
+        return ERROR_INVALID_DATA;
+    }
+
+    if (BytesPerSample == 1)
+    {
+        /* FIXME perform over/under clipping */
+
+        for(Index = 0; Index < Data.output_frames_gen * NumChannels; Index++)
+            ResultOut[Index] = (lrintf(FloatOut[Index]) >> 24);
+    }
+    else if (BytesPerSample == 2)
+    {
+        PUSHORT Res = (PUSHORT)ResultOut;
+
+        src_float_to_short_array(FloatOut, (short*)Res, Data.output_frames_gen * NumChannels);
+    }
+    else if (BytesPerSample == 4)
+    {
+        PULONG Res = (PULONG)ResultOut;
+
+        src_float_to_int_array(FloatOut, (int*)Res, Data.output_frames_gen * NumChannels);
+    }
+
+
+    *Result = ResultOut;
+    *ResultLength = Data.output_frames_gen * BytesPerSample * NumChannels;
+    HeapFree(GetProcessHeap(), 0,FloatIn);
+    HeapFree(GetProcessHeap(), 0,FloatOut);
+    src_delete(State);
+    return ERROR_SUCCESS;
+}
+
+DWORD
+PerformChannelConversion(
+    PUCHAR Buffer,
+    ULONG BufferLength,
+    ULONG OldChannels,
+    ULONG NewChannels,
+    ULONG BitsPerSample,
+    PVOID * Result,
+    PULONG ResultLength)
+{
+    ULONG Samples;
+    ULONG NewIndex, OldIndex;
+
+    Samples = BufferLength / (BitsPerSample / 8) / OldChannels;
+
+    SND_TRACE(L"PerformChannelConversion OldChannels %u NewChannels %u\n", OldChannels, NewChannels);
+
+    if (NewChannels > OldChannels)
+    {
+        if (BitsPerSample == 8)
+        {
+            PUCHAR BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
+            if (!BufferOut)
+                return ERROR_NOT_ENOUGH_MEMORY;
+
+            for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
+            {
+                ULONG SubIndex = 0;
+
+                RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], OldChannels * sizeof(UCHAR));
+
+                do
+                {
+                    /* 2 channel stretched to 4 looks like LRLR */
+                     BufferOut[NewIndex+OldChannels + SubIndex] = Buffer[OldIndex + (SubIndex % OldChannels)];
+                }while(SubIndex++ < NewChannels - OldChannels);
+            }
+            *Result = BufferOut;
+            *ResultLength = Samples * NewChannels;
+        }
+        else if (BitsPerSample == 16)
+        {
+            PUSHORT BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
+            if (!BufferOut)
+                return ERROR_NOT_ENOUGH_MEMORY;
+
+            for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
+            {
+                ULONG SubIndex = 0;
+
+                RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], OldChannels * sizeof(USHORT));
+
+                do
+                {
+                     BufferOut[NewIndex+OldChannels + SubIndex] = Buffer[OldIndex + (SubIndex % OldChannels)];
+                }while(SubIndex++ < NewChannels - OldChannels);
+            }
+            *Result = BufferOut;
+            *ResultLength = Samples * NewChannels;
+        }
+        else if (BitsPerSample == 24)
+        {
+            PUCHAR BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
+            if (!BufferOut)
+                return ERROR_NOT_ENOUGH_MEMORY;
+
+            for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
+            {
+                ULONG SubIndex = 0;
+
+                RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], OldChannels * 3);
+
+                do
+                {
+                     RtlMoveMemory(&BufferOut[(NewIndex+OldChannels + SubIndex) * 3], &Buffer[(OldIndex + (SubIndex % OldChannels)) * 3], 3);
+                }while(SubIndex++ < NewChannels - OldChannels);
+            }
+            *Result = BufferOut;
+            *ResultLength = Samples * NewChannels;
+        }
+        else if (BitsPerSample == 32)
+        {
+            PULONG BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
+            if (!BufferOut)
+                return ERROR_NOT_ENOUGH_MEMORY;
+
+            for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
+            {
+                ULONG SubIndex = 0;
+
+                RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], OldChannels * sizeof(ULONG));
+
+                do
+                {
+                     BufferOut[NewIndex+OldChannels + SubIndex] = Buffer[OldIndex + (SubIndex % OldChannels)];
+                }while(SubIndex++ < NewChannels - OldChannels);
+            }
+            *Result = BufferOut;
+            *ResultLength = Samples * NewChannels;
+        }
+
+    }
+    else
+    {
+        PUSHORT BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
+        if (!BufferOut)
+            return ERROR_NOT_ENOUGH_MEMORY;
+
+        for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
+        {
+            /* TODO
+             * mix stream instead of just dumping part of it ;)
+             */
+            RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], NewChannels * (BitsPerSample/8));
+        }
+
+        *Result = BufferOut;
+        *ResultLength = Samples * NewChannels;
+    }
+    return ERROR_SUCCESS;
+}
+
+
+DWORD
+PerformQualityConversion(
+    PUCHAR Buffer,
+    ULONG BufferLength,
+    ULONG OldWidth,
+    ULONG NewWidth,
+    PVOID * Result,
+    PULONG ResultLength)
+{
+    ULONG Samples;
+    ULONG Index;
+
+    ASSERT(OldWidth != NewWidth);
+
+    Samples = BufferLength / (OldWidth / 8);
+    //DPRINT("Samples %u BufferLength %u\n", Samples, BufferLength);
+
+    SND_TRACE(L"PerformQualityConversion OldWidth %u NewWidth %u\n", OldWidth, NewWidth);
+
+    if (OldWidth == 8 && NewWidth == 16)
+    {
+         USHORT Sample;
+         PUSHORT BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(USHORT));
+         if (!BufferOut)
+             return ERROR_NOT_ENOUGH_MEMORY;
+
+          for(Index = 0; Index < Samples; Index++)
+          {
+              Sample = Buffer[Index];
+              Sample *= 2;
+#ifdef _X86_
+              Sample = _byteswap_ushort(Sample);
+#endif
+              BufferOut[Index] = Sample;
+          }
+          *Result = BufferOut;
+          *ResultLength = Samples * sizeof(USHORT);
+    }
+    else if (OldWidth == 8 && NewWidth == 32)
+    {
+         ULONG Sample;
+         PULONG BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(ULONG));
+         if (!BufferOut)
+             return ERROR_NOT_ENOUGH_MEMORY;
+
+          for(Index = 0; Index < Samples; Index++)
+          {
+              Sample = Buffer[Index];
+              Sample *= 16777216;
+#ifdef _X86_
+              Sample = _byteswap_ulong(Sample);
+#endif
+              BufferOut[Index] = Sample;
+          }
+          *Result = BufferOut;
+          *ResultLength = Samples * sizeof(ULONG);
+    }
+    else if (OldWidth == 16 && NewWidth == 32)
+    {
+         ULONG Sample;
+         PUSHORT BufferIn = (PUSHORT)Buffer;
+         PULONG BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(ULONG));
+         if (!BufferOut)
+             return ERROR_NOT_ENOUGH_MEMORY;
+
+          for(Index = 0; Index < Samples; Index++)
+          {
+              Sample = BufferIn[Index];
+              Sample *= 65536;
+#ifdef _X86_
+              Sample = _byteswap_ulong(Sample);
+#endif
+              BufferOut[Index] = Sample;
+          }
+          *Result = BufferOut;
+          *ResultLength = Samples * sizeof(ULONG);
+    }
+
+    else if (OldWidth == 16 && NewWidth == 8)
+    {
+         USHORT Sample;
+         PUSHORT BufferIn = (PUSHORT)Buffer;
+         PUCHAR BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(UCHAR));
+         if (!BufferOut)
+             return ERROR_NOT_ENOUGH_MEMORY;
+
+          for(Index = 0; Index < Samples; Index++)
+          {
+              Sample = BufferIn[Index];
+#ifdef _X86_
+              Sample = _byteswap_ushort(Sample);
+#endif
+              Sample /= 256;
+              BufferOut[Index] = (Sample & 0xFF);
+          }
+          *Result = BufferOut;
+          *ResultLength = Samples * sizeof(UCHAR);
+    }
+    else if (OldWidth == 32 && NewWidth == 8)
+    {
+         ULONG Sample;
+         PULONG BufferIn = (PULONG)Buffer;
+         PUCHAR BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(UCHAR));
+         if (!BufferOut)
+             return ERROR_NOT_ENOUGH_MEMORY;
+
+          for(Index = 0; Index < Samples; Index++)
+          {
+              Sample = BufferIn[Index];
+#ifdef _X86_
+              Sample = _byteswap_ulong(Sample);
+#endif
+              Sample /= 16777216;
+              BufferOut[Index] = (Sample & 0xFF);
+          }
+          *Result = BufferOut;
+          *ResultLength = Samples * sizeof(UCHAR);
+    }
+    else if (OldWidth == 32 && NewWidth == 16)
+    {
+         USHORT Sample;
+         PULONG BufferIn = (PULONG)Buffer;
+         PUSHORT BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(USHORT));
+         if (!BufferOut)
+             return ERROR_NOT_ENOUGH_MEMORY;
+
+          for(Index = 0; Index < Samples; Index++)
+          {
+              Sample = BufferIn[Index];
+#ifdef _X86_
+              Sample = _byteswap_ulong(Sample);
+#endif
+              Sample /= 65536;
+              BufferOut[Index] = (Sample & 0xFFFF);
+          }
+          *Result = BufferOut;
+          *ResultLength = Samples * sizeof(USHORT);
+    }
+    else
+    {
+        DPRINT1("Not implemented conversion OldWidth %u NewWidth %u\n", OldWidth, NewWidth);
+        return ERROR_NOT_SUPPORTED;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+VOID
+CALLBACK
+MixerCompletionRoutine(
+    IN  DWORD dwErrorCode,
+    IN  DWORD dwNumberOfBytesTransferred,
+    IN  LPOVERLAPPED lpOverlapped)
+{
+    PSOUND_OVERLAPPED Overlap = (PSOUND_OVERLAPPED)lpOverlapped;
+
+    /* Call mmebuddy overlap routine */
+    Overlap->OriginalCompletionRoutine(dwErrorCode, Overlap->OriginalBufferSize, lpOverlapped);
+}
+
+MMRESULT
+WriteFileEx_Remixer(
+    IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+    IN  PVOID OffsetPtr,
+    IN  DWORD Length,
+    IN  PSOUND_OVERLAPPED Overlap,
+    IN  LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
+{
+    HANDLE Handle;
+    WDMAUD_DEVICE_INFO DeviceInfo;
+    DWORD BufferLength, BufferLengthTemp;
+    PVOID BufferOut, BufferOutTemp;
+    DWORD Status;
+    BOOL Result;
+
+    VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
+    VALIDATE_MMSYS_PARAMETER( OffsetPtr );
+    VALIDATE_MMSYS_PARAMETER( Overlap );
+    VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
+
+    GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
+
+    SND_ASSERT(Handle);
+
+    BufferOut = OffsetPtr;
+    BufferLength = Length;
+
+    if (SoundDeviceInstance->WaveFormatEx.wBitsPerSample != 16)
+    {
+        Status = PerformQualityConversion(OffsetPtr,
+                                          Length,
+                                          SoundDeviceInstance->WaveFormatEx.wBitsPerSample,
+                                          16,
+                                          &BufferOut,
+                                          &BufferLength);
+        if (Status)
+        {
+            SND_TRACE(L"PerformQualityConversion failed\n");
+            return MMSYSERR_NOERROR;
+        }
+    }
+
+    if (SoundDeviceInstance->WaveFormatEx.nChannels != 2)
+    {
+        Status = PerformChannelConversion(BufferOut,
+                                          BufferLength,
+                                          SoundDeviceInstance->WaveFormatEx.nChannels,
+                                          2,
+                                          16,
+                                          &BufferOutTemp,
+                                          &BufferLengthTemp);
+
+        if (BufferOut != OffsetPtr)
+        {
+            HeapFree(GetProcessHeap(), 0, BufferOut);
+        }
+
+        if (Status)
+        {
+            SND_TRACE(L"PerformChannelConversion failed\n");
+            return MMSYSERR_NOERROR;
+        }
+
+        BufferOut = BufferOutTemp;
+        BufferLength = BufferLengthTemp;
+    }
+
+    if (SoundDeviceInstance->WaveFormatEx.nSamplesPerSec != 44100)
+    {
+        Status = PerformSampleRateConversion(BufferOut,
+                                             BufferLength,
+                                             SoundDeviceInstance->WaveFormatEx.nSamplesPerSec,
+                                             44100,
+                                             2,
+                                             2,
+                                             &BufferOutTemp,
+                                             &BufferLengthTemp);
+
+        if (BufferOut != OffsetPtr)
+        {
+            HeapFree(GetProcessHeap(), 0, BufferOut);
+        }
+
+        if (Status)
+        {
+            SND_TRACE(L"PerformSampleRateConversion failed\n");
+            return MMSYSERR_NOERROR;
+        }
+
+        BufferOut = BufferOutTemp;
+        BufferLength = BufferLengthTemp;
+    }
+
+    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
+    DeviceInfo.hDevice = Handle;
+    DeviceInfo.DeviceType = WAVE_OUT_DEVICE_TYPE; //FIXME
+    DeviceInfo.Buffer = BufferOut;
+    DeviceInfo.BufferSize = BufferLength;
+
+    Overlap->OriginalBufferSize = Length;
+    Overlap->OriginalCompletionRoutine = CompletionRoutine;
+
+    Overlap->Standard.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+    //SND_TRACE(L"OriginalLength %u NewLength %u\n", Length, BufferLength);
+
+#if 0
+    Result = WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine);
+#else
+    Result = WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, MixerCompletionRoutine);
+#endif
+
+    if ( ! Result )
+    {
+        SND_TRACE(L"WriteFileEx failed with %x\n", GetLastError());
+        return MMSYSERR_NOERROR;
+    }
+
+    WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
+
+#ifdef USERMODE_MIXER
+       // if (BufferOut != OffsetPtr)
+       //     HeapFree(GetProcessHeap(), 0, BufferOut);
+#endif
+
+
+    return MMSYSERR_NOERROR;
+}
index 94f0c76..a2566e5 100644 (file)
@@ -32,6 +32,15 @@ PWSTR UnknownMidiOut = L"Midi Output";
 HANDLE KernelHandle = INVALID_HANDLE_VALUE;
 DWORD OpenCount = 0;
 
+MMRESULT
+WriteFileEx_Remixer(
+    IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+    IN  PVOID OffsetPtr,
+    IN  DWORD Length,
+    IN  PSOUND_OVERLAPPED Overlap,
+    IN  LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine);
+
+
 
 MMRESULT
 GetNumWdmDevs(
@@ -288,11 +297,19 @@ SetWdmWaveDeviceFormat(
     DeviceInfo.DeviceIndex = DeviceId;
     DeviceInfo.u.WaveFormatEx.cbSize = WaveFormat->cbSize;
     DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
+#ifdef USERMODE_MIXER
+    DeviceInfo.u.WaveFormatEx.nChannels = 2;
+    DeviceInfo.u.WaveFormatEx.nSamplesPerSec = 44100;
+    DeviceInfo.u.WaveFormatEx.nBlockAlign = 4;
+    DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = 176400;
+    DeviceInfo.u.WaveFormatEx.wBitsPerSample = 16;
+#else
     DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
     DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
     DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
     DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
     DeviceInfo.u.WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
+#endif
 
     Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                            IOCTL_OPEN_WDMAUD,
@@ -307,6 +324,16 @@ SetWdmWaveDeviceFormat(
         return TranslateInternalMmResult(Result);
     }
 
+    /* Store format */
+    Instance->WaveFormatEx.cbSize = WaveFormat->cbSize;
+    Instance->WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
+    Instance->WaveFormatEx.nChannels = WaveFormat->nChannels;
+    Instance->WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
+    Instance->WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
+    Instance->WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
+    Instance->WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
+
+    /* Store sound device handle instance handle */
     Instance->Handle = (PVOID)DeviceInfo.hDevice;
 
     /* Now determine framing requirements */
@@ -473,7 +500,11 @@ PopulateWdmDeviceList(
         FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
         FuncTable.Open = OpenWdmSoundDevice;
         FuncTable.Close = CloseWdmSoundDevice;
+#ifndef USERMODE_MIXER
         FuncTable.CommitWaveBuffer = WriteFileEx_Committer2;
+#else
+        FuncTable.CommitWaveBuffer = WriteFileEx_Remixer;
+#endif
         FuncTable.GetPos = GetWdmPosition;
 
         SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
index 31a636f..eb32ff2 100644 (file)
@@ -3,13 +3,18 @@
        <include base="wdmaud.drv">.</include>
        <include base="ReactOS">include/reactos/libs/sound</include>
        <include base="wdmaud_kernel">.</include>
+       <include base="libsamplerate">.</include>
        <define name="DEBUG_NT4" /><!-- Use custom debug routines -->
+       <!-- <define name="USERMODE_MIXER" /> Enable this line to for usermode mixing support -->
        <library>mmebuddy</library>
        <library>ntdll</library>
        <library>kernel32</library>
        <library>user32</library>
        <library>winmm</library>
        <library>advapi32</library>
+       <library>libsamplerate</library>
+       <library>msvcrt</library>
        <file>wdmaud.c</file>
+       <file>mixer.c</file>
        <file>wdmaud.rc</file>
 </module>