Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmixer.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
1.7.6.1
|