ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

mixer.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:     ReactOS Sound System
00003  * LICENSE:     GPL - See COPYING in the top level directory
00004  * FILE:        dll/win32/wdmaud.drv/mixer.c
00005  *
00006  * PURPOSE:     WDM Audio Driver (User-mode part)
00007  * PROGRAMMERS: Johannes Anderwald
00008  */
00009 
00010 #include "wdmaud.h"
00011 
00012 extern HANDLE KernelHandle;
00013 
00014 DWORD
00015 PerformSampleRateConversion(
00016     PUCHAR Buffer,
00017     ULONG BufferLength,
00018     ULONG OldRate,
00019     ULONG NewRate,
00020     ULONG BytesPerSample,
00021     ULONG NumChannels,
00022     PVOID * Result,
00023     PULONG ResultLength)
00024 {
00025     ULONG Index;
00026     SRC_STATE * State;
00027     SRC_DATA Data;
00028     PUCHAR ResultOut;
00029     int error;
00030     PFLOAT FloatIn, FloatOut;
00031     ULONG NumSamples;
00032     ULONG NewSamples;
00033 
00034     //SND_TRACE(L"PerformSampleRateConversion OldRate %u NewRate %u BytesPerSample %u NumChannels %u\n", OldRate, NewRate, BytesPerSample, NumChannels);
00035 
00036     ASSERT(BytesPerSample == 1 || BytesPerSample == 2 || BytesPerSample == 4);
00037 
00038     NumSamples = BufferLength / (BytesPerSample * NumChannels);
00039 
00040     FloatIn = HeapAlloc(GetProcessHeap(), 0, NumSamples * NumChannels * sizeof(FLOAT));
00041     if (!FloatIn)
00042     {
00043         return ERROR_NOT_ENOUGH_MEMORY;
00044     }
00045 
00046     NewSamples = lrintf(((FLOAT)NumSamples * ((FLOAT)NewRate / (FLOAT)OldRate))) + 2;
00047 
00048     FloatOut = HeapAlloc(GetProcessHeap(), 0, NewSamples * NumChannels * sizeof(FLOAT));
00049     if (!FloatOut)
00050     {
00051         HeapFree(GetProcessHeap(), 0,FloatIn);
00052         return ERROR_NOT_ENOUGH_MEMORY;
00053     }
00054 
00055     ResultOut = HeapAlloc(GetProcessHeap(), 0, NewSamples * NumChannels * BytesPerSample);
00056     if (!ResultOut)
00057     {
00058         HeapFree(GetProcessHeap(), 0,FloatIn);
00059         HeapFree(GetProcessHeap(), 0,FloatOut);
00060         return ERROR_NOT_ENOUGH_MEMORY;
00061     }
00062 
00063     State = src_new(SRC_SINC_FASTEST, NumChannels, &error);
00064     if (!State)
00065     {
00066         HeapFree(GetProcessHeap(), 0,FloatIn);
00067         HeapFree(GetProcessHeap(), 0,FloatOut);
00068         HeapFree(GetProcessHeap(), 0,ResultOut);
00069         return ERROR_NOT_ENOUGH_MEMORY;
00070     }
00071 
00072     /* fixme use asm */
00073     if (BytesPerSample == 1)
00074     {
00075         for(Index = 0; Index < NumSamples * NumChannels; Index++)
00076             FloatIn[Index] = (float)(Buffer[Index] / (1.0 * 0x80));
00077     }
00078     else if (BytesPerSample == 2)
00079     {
00080         src_short_to_float_array((short*)Buffer, FloatIn, NumSamples * NumChannels);
00081     }
00082     else if (BytesPerSample == 4)
00083     {
00084         src_int_to_float_array((int*)Buffer, FloatIn, NumSamples * NumChannels);
00085     }
00086 
00087     Data.data_in = FloatIn;
00088     Data.data_out = FloatOut;
00089     Data.input_frames = NumSamples;
00090     Data.output_frames = NewSamples;
00091     Data.src_ratio = (double)NewRate / (double)OldRate;
00092 
00093     error = src_process(State, &Data);
00094     if (error)
00095     {
00096         DPRINT1("src_process failed with %x\n", error);
00097         HeapFree(GetProcessHeap(), 0,FloatIn);
00098         HeapFree(GetProcessHeap(), 0,FloatOut);
00099         HeapFree(GetProcessHeap(), 0,ResultOut);
00100         return ERROR_INVALID_DATA;
00101     }
00102 
00103     if (BytesPerSample == 1)
00104     {
00105         /* FIXME perform over/under clipping */
00106 
00107         for(Index = 0; Index < Data.output_frames_gen * NumChannels; Index++)
00108             ResultOut[Index] = (lrintf(FloatOut[Index]) >> 24);
00109     }
00110     else if (BytesPerSample == 2)
00111     {
00112         PUSHORT Res = (PUSHORT)ResultOut;
00113 
00114         src_float_to_short_array(FloatOut, (short*)Res, Data.output_frames_gen * NumChannels);
00115     }
00116     else if (BytesPerSample == 4)
00117     {
00118         PULONG Res = (PULONG)ResultOut;
00119 
00120         src_float_to_int_array(FloatOut, (int*)Res, Data.output_frames_gen * NumChannels);
00121     }
00122 
00123 
00124     *Result = ResultOut;
00125     *ResultLength = Data.output_frames_gen * BytesPerSample * NumChannels;
00126     HeapFree(GetProcessHeap(), 0,FloatIn);
00127     HeapFree(GetProcessHeap(), 0,FloatOut);
00128     src_delete(State);
00129     return ERROR_SUCCESS;
00130 }
00131 
00132 DWORD
00133 PerformChannelConversion(
00134     PUCHAR Buffer,
00135     ULONG BufferLength,
00136     ULONG OldChannels,
00137     ULONG NewChannels,
00138     ULONG BitsPerSample,
00139     PVOID * Result,
00140     PULONG ResultLength)
00141 {
00142     ULONG Samples;
00143     ULONG NewIndex, OldIndex;
00144 
00145     Samples = BufferLength / (BitsPerSample / 8) / OldChannels;
00146 
00147     SND_TRACE(L"PerformChannelConversion OldChannels %u NewChannels %u\n", OldChannels, NewChannels);
00148 
00149     if (NewChannels > OldChannels)
00150     {
00151         if (BitsPerSample == 8)
00152         {
00153             PUCHAR BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
00154             if (!BufferOut)
00155                 return ERROR_NOT_ENOUGH_MEMORY;
00156 
00157             for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
00158             {
00159                 ULONG SubIndex = 0;
00160 
00161                 RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], OldChannels * sizeof(UCHAR));
00162 
00163                 do
00164                 {
00165                     /* 2 channel stretched to 4 looks like LRLR */
00166                      BufferOut[NewIndex+OldChannels + SubIndex] = Buffer[OldIndex + (SubIndex % OldChannels)];
00167                 }while(SubIndex++ < NewChannels - OldChannels);
00168             }
00169             *Result = BufferOut;
00170             *ResultLength = Samples * NewChannels;
00171         }
00172         else if (BitsPerSample == 16)
00173         {
00174             PUSHORT BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
00175             if (!BufferOut)
00176                 return ERROR_NOT_ENOUGH_MEMORY;
00177 
00178             for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
00179             {
00180                 ULONG SubIndex = 0;
00181 
00182                 RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], OldChannels * sizeof(USHORT));
00183 
00184                 do
00185                 {
00186                      BufferOut[NewIndex+OldChannels + SubIndex] = Buffer[OldIndex + (SubIndex % OldChannels)];
00187                 }while(SubIndex++ < NewChannels - OldChannels);
00188             }
00189             *Result = BufferOut;
00190             *ResultLength = Samples * NewChannels;
00191         }
00192         else if (BitsPerSample == 24)
00193         {
00194             PUCHAR BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
00195             if (!BufferOut)
00196                 return ERROR_NOT_ENOUGH_MEMORY;
00197 
00198             for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
00199             {
00200                 ULONG SubIndex = 0;
00201 
00202                 RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], OldChannels * 3);
00203 
00204                 do
00205                 {
00206                      RtlMoveMemory(&BufferOut[(NewIndex+OldChannels + SubIndex) * 3], &Buffer[(OldIndex + (SubIndex % OldChannels)) * 3], 3);
00207                 }while(SubIndex++ < NewChannels - OldChannels);
00208             }
00209             *Result = BufferOut;
00210             *ResultLength = Samples * NewChannels;
00211         }
00212         else if (BitsPerSample == 32)
00213         {
00214             PULONG BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
00215             if (!BufferOut)
00216                 return ERROR_NOT_ENOUGH_MEMORY;
00217 
00218             for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
00219             {
00220                 ULONG SubIndex = 0;
00221 
00222                 RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], OldChannels * sizeof(ULONG));
00223 
00224                 do
00225                 {
00226                      BufferOut[NewIndex+OldChannels + SubIndex] = Buffer[OldIndex + (SubIndex % OldChannels)];
00227                 }while(SubIndex++ < NewChannels - OldChannels);
00228             }
00229             *Result = BufferOut;
00230             *ResultLength = Samples * NewChannels;
00231         }
00232 
00233     }
00234     else
00235     {
00236         PUSHORT BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * NewChannels);
00237         if (!BufferOut)
00238             return ERROR_NOT_ENOUGH_MEMORY;
00239 
00240         for(NewIndex = 0, OldIndex = 0; OldIndex < Samples * OldChannels; NewIndex += NewChannels, OldIndex += OldChannels)
00241         {
00242             /* TODO
00243              * mix stream instead of just dumping part of it ;)
00244              */
00245             RtlMoveMemory(&BufferOut[NewIndex], &Buffer[OldIndex], NewChannels * (BitsPerSample/8));
00246         }
00247 
00248         *Result = BufferOut;
00249         *ResultLength = Samples * NewChannels;
00250     }
00251     return ERROR_SUCCESS;
00252 }
00253 
00254 
00255 DWORD
00256 PerformQualityConversion(
00257     PUCHAR Buffer,
00258     ULONG BufferLength,
00259     ULONG OldWidth,
00260     ULONG NewWidth,
00261     PVOID * Result,
00262     PULONG ResultLength)
00263 {
00264     ULONG Samples;
00265     ULONG Index;
00266 
00267     ASSERT(OldWidth != NewWidth);
00268 
00269     Samples = BufferLength / (OldWidth / 8);
00270     //DPRINT("Samples %u BufferLength %u\n", Samples, BufferLength);
00271 
00272     //SND_TRACE(L"PerformQualityConversion OldWidth %u NewWidth %u\n", OldWidth, NewWidth);
00273 
00274     if (OldWidth == 8 && NewWidth == 16)
00275     {
00276          USHORT Sample;
00277          PUSHORT BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(USHORT));
00278          if (!BufferOut)
00279              return ERROR_NOT_ENOUGH_MEMORY;
00280 
00281           for(Index = 0; Index < Samples; Index++)
00282           {
00283               Sample = Buffer[Index];// & 0xFF);
00284               Sample *= 2;
00285 #ifdef _X86_
00286               Sample = _byteswap_ushort(Sample);
00287 #endif
00288               BufferOut[Index] = Sample;
00289           }
00290           *Result = BufferOut;
00291           *ResultLength = Samples * sizeof(USHORT);
00292     }
00293     else if (OldWidth == 8 && NewWidth == 32)
00294     {
00295          ULONG Sample;
00296          PULONG BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(ULONG));
00297          if (!BufferOut)
00298              return ERROR_NOT_ENOUGH_MEMORY;
00299 
00300           for(Index = 0; Index < Samples; Index++)
00301           {
00302               Sample = Buffer[Index];
00303               Sample *= 16777216;
00304 #ifdef _X86_
00305               Sample = _byteswap_ulong(Sample);
00306 #endif
00307               BufferOut[Index] = Sample;
00308           }
00309           *Result = BufferOut;
00310           *ResultLength = Samples * sizeof(ULONG);
00311     }
00312     else if (OldWidth == 16 && NewWidth == 32)
00313     {
00314          ULONG Sample;
00315          PUSHORT BufferIn = (PUSHORT)Buffer;
00316          PULONG BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(ULONG));
00317          if (!BufferOut)
00318              return ERROR_NOT_ENOUGH_MEMORY;
00319 
00320           for(Index = 0; Index < Samples; Index++)
00321           {
00322               Sample = BufferIn[Index];
00323               Sample *= 65536;
00324 #ifdef _X86_
00325               Sample = _byteswap_ulong(Sample);
00326 #endif
00327               BufferOut[Index] = Sample;
00328           }
00329           *Result = BufferOut;
00330           *ResultLength = Samples * sizeof(ULONG);
00331     }
00332 
00333     else if (OldWidth == 16 && NewWidth == 8)
00334     {
00335          USHORT Sample;
00336          PUSHORT BufferIn = (PUSHORT)Buffer;
00337          PUCHAR BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(UCHAR));
00338          if (!BufferOut)
00339              return ERROR_NOT_ENOUGH_MEMORY;
00340 
00341           for(Index = 0; Index < Samples; Index++)
00342           {
00343               Sample = BufferIn[Index];
00344 #ifdef _X86_
00345               Sample = _byteswap_ushort(Sample);
00346 #endif
00347               Sample /= 256;
00348               BufferOut[Index] = (Sample & 0xFF);
00349           }
00350           *Result = BufferOut;
00351           *ResultLength = Samples * sizeof(UCHAR);
00352     }
00353     else if (OldWidth == 32 && NewWidth == 8)
00354     {
00355          ULONG Sample;
00356          PULONG BufferIn = (PULONG)Buffer;
00357          PUCHAR BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(UCHAR));
00358          if (!BufferOut)
00359              return ERROR_NOT_ENOUGH_MEMORY;
00360 
00361           for(Index = 0; Index < Samples; Index++)
00362           {
00363               Sample = BufferIn[Index];
00364 #ifdef _X86_
00365               Sample = _byteswap_ulong(Sample);
00366 #endif
00367               Sample /= 16777216;
00368               BufferOut[Index] = (Sample & 0xFF);
00369           }
00370           *Result = BufferOut;
00371           *ResultLength = Samples * sizeof(UCHAR);
00372     }
00373     else if (OldWidth == 32 && NewWidth == 16)
00374     {
00375          USHORT Sample;
00376          PULONG BufferIn = (PULONG)Buffer;
00377          PUSHORT BufferOut = HeapAlloc(GetProcessHeap(), 0, Samples * sizeof(USHORT));
00378          if (!BufferOut)
00379              return ERROR_NOT_ENOUGH_MEMORY;
00380 
00381           for(Index = 0; Index < Samples; Index++)
00382           {
00383               Sample = BufferIn[Index];
00384 #ifdef _X86_
00385               Sample = _byteswap_ulong(Sample);
00386 #endif
00387               Sample /= 65536;
00388               BufferOut[Index] = (Sample & 0xFFFF);
00389           }
00390           *Result = BufferOut;
00391           *ResultLength = Samples * sizeof(USHORT);
00392     }
00393     else
00394     {
00395         DPRINT1("Not implemented conversion OldWidth %u NewWidth %u\n", OldWidth, NewWidth);
00396         return ERROR_NOT_SUPPORTED;
00397     }
00398 
00399     return ERROR_SUCCESS;
00400 }
00401 
00402 VOID
00403 CALLBACK
00404 MixerCompletionRoutine(
00405     IN  DWORD dwErrorCode,
00406     IN  DWORD dwNumberOfBytesTransferred,
00407     IN  LPOVERLAPPED lpOverlapped)
00408 {
00409     PSOUND_OVERLAPPED Overlap = (PSOUND_OVERLAPPED)lpOverlapped;
00410 
00411     /* Call mmebuddy overlap routine */
00412     Overlap->OriginalCompletionRoutine(dwErrorCode, PtrToUlong(Overlap->CompletionContext), lpOverlapped);
00413 }
00414 
00415 MMRESULT
00416 WriteFileEx_Remixer(
00417     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
00418     IN  PVOID OffsetPtr,
00419     IN  DWORD Length,
00420     IN  PSOUND_OVERLAPPED Overlap,
00421     IN  LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
00422 {
00423     HANDLE Handle;
00424     WDMAUD_DEVICE_INFO DeviceInfo;
00425     DWORD BufferLength, BufferLengthTemp;
00426     PVOID BufferOut, BufferOutTemp;
00427     DWORD Status;
00428     BOOL Result;
00429 
00430     VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
00431     VALIDATE_MMSYS_PARAMETER( OffsetPtr );
00432     VALIDATE_MMSYS_PARAMETER( Overlap );
00433     VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
00434 
00435     GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
00436 
00437     SND_ASSERT(Handle);
00438 
00439     BufferOut = OffsetPtr;
00440     BufferLength = Length;
00441 
00442     if (SoundDeviceInstance->WaveFormatEx.wBitsPerSample != 16)
00443     {
00444         Status = PerformQualityConversion(OffsetPtr,
00445                                           Length,
00446                                           SoundDeviceInstance->WaveFormatEx.wBitsPerSample,
00447                                           16,
00448                                           &BufferOut,
00449                                           &BufferLength);
00450         if (Status)
00451         {
00452             SND_TRACE(L"PerformQualityConversion failed\n");
00453             return MMSYSERR_NOERROR;
00454         }
00455     }
00456 
00457     if (SoundDeviceInstance->WaveFormatEx.nChannels != 2)
00458     {
00459         Status = PerformChannelConversion(BufferOut,
00460                                           BufferLength,
00461                                           SoundDeviceInstance->WaveFormatEx.nChannels,
00462                                           2,
00463                                           16,
00464                                           &BufferOutTemp,
00465                                           &BufferLengthTemp);
00466 
00467         if (BufferOut != OffsetPtr)
00468         {
00469             HeapFree(GetProcessHeap(), 0, BufferOut);
00470         }
00471 
00472         if (Status)
00473         {
00474             SND_TRACE(L"PerformChannelConversion failed\n");
00475             return MMSYSERR_NOERROR;
00476         }
00477 
00478         BufferOut = BufferOutTemp;
00479         BufferLength = BufferLengthTemp;
00480     }
00481 
00482     if (SoundDeviceInstance->WaveFormatEx.nSamplesPerSec != 44100)
00483     {
00484         Status = PerformSampleRateConversion(BufferOut,
00485                                              BufferLength,
00486                                              SoundDeviceInstance->WaveFormatEx.nSamplesPerSec,
00487                                              44100,
00488                                              2,
00489                                              2,
00490                                              &BufferOutTemp,
00491                                              &BufferLengthTemp);
00492 
00493         if (BufferOut != OffsetPtr)
00494         {
00495             HeapFree(GetProcessHeap(), 0, BufferOut);
00496         }
00497 
00498         if (Status)
00499         {
00500             SND_TRACE(L"PerformSampleRateConversion failed\n");
00501             return MMSYSERR_NOERROR;
00502         }
00503 
00504         BufferOut = BufferOutTemp;
00505         BufferLength = BufferLengthTemp;
00506     }
00507 
00508     ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
00509     DeviceInfo.hDevice = Handle;
00510     DeviceInfo.DeviceType = WAVE_OUT_DEVICE_TYPE; //FIXME
00511     DeviceInfo.Header.FrameExtent = BufferLength;
00512     DeviceInfo.Header.DataUsed = BufferLength;
00513     DeviceInfo.Header.Data = BufferOut;
00514     DeviceInfo.Header.Size = sizeof(KSSTREAM_HEADER);
00515     DeviceInfo.Header.PresentationTime.Numerator = 1;
00516     DeviceInfo.Header.PresentationTime.Denominator = 1;
00517 
00518     Overlap->CompletionContext = UlongToPtr(Length);
00519     Overlap->OriginalCompletionRoutine = CompletionRoutine;
00520 
00521     Overlap->Standard.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
00522 
00523     //SND_TRACE(L"OriginalLength %u NewLength %u\n", Length, BufferLength);
00524 
00525 #if 0
00526     Result = WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine);
00527 #else
00528     Result = WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, MixerCompletionRoutine);
00529 #endif
00530 
00531     if ( ! Result )
00532     {
00533         SND_TRACE(L"WriteFileEx failed with %x\n", GetLastError());
00534         return MMSYSERR_NOERROR;
00535     }
00536 
00537     WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
00538 
00539 #ifdef USERMODE_MIXER
00540        // if (BufferOut != OffsetPtr)
00541        //     HeapFree(GetProcessHeap(), 0, BufferOut);
00542 #endif
00543 
00544 
00545     return MMSYSERR_NOERROR;
00546 }
00547 

Generated on Sun May 27 2012 04:17:44 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.