From 27c2bd90ebcc282a1b3a174b9f7ce47f7644b36f Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Wed, 15 Apr 2009 10:41:41 +0000 Subject: [PATCH] - Plug in sample rate conversion library, doesnt work yet - Implement calloc, memset, memcpy as calling their Rtl* wrapper doesnt work- Add define for AC97 hacks svn path=/trunk/; revision=40524 --- .../drivers/wdm/audio/filters/kmixer/pin.c | 188 ++++++++++++++++-- reactos/drivers/wdm/audio/sysaudio/control.c | 34 +++- 2 files changed, 193 insertions(+), 29 deletions(-) diff --git a/reactos/drivers/wdm/audio/filters/kmixer/pin.c b/reactos/drivers/wdm/audio/filters/kmixer/pin.c index c76326ea8da..2a5b0aaea25 100644 --- a/reactos/drivers/wdm/audio/filters/kmixer/pin.c +++ b/reactos/drivers/wdm/audio/filters/kmixer/pin.c @@ -10,6 +10,140 @@ const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; +NTSTATUS +PerformSampleRateConversion( + PUCHAR Buffer, + ULONG BufferLength, + ULONG OldRate, + ULONG NewRate, + ULONG BytesPerSample, + ULONG NumChannels, + PVOID * Result, + PULONG ResultLength) +{ + KFLOATING_SAVE FloatSave; + NTSTATUS Status; + ULONG Index; + SRC_STATE * State; + SRC_DATA Data; + PUCHAR ResultOut; + int error; + PFLOAT FloatIn, FloatOut; + ULONG NumSamples; + ULONG NewSamples; + + DPRINT("PerformSampleRateConversion OldRate %u NewRate %u BytesPerSample %u NumChannels %u Irql %u\n", OldRate, NewRate, BytesPerSample, NumChannels, KeGetCurrentIrql()); + + /* first acquire float save context */ + Status = KeSaveFloatingPointState(&FloatSave); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("KeSaveFloatingPointState failed with %x\n", Status); + return Status; + } + + NumSamples = BufferLength / BytesPerSample; + + FloatIn = ExAllocatePool(NonPagedPool, NumSamples * sizeof(FLOAT)); + if (!FloatIn) + { + KeRestoreFloatingPointState(&FloatSave); + return STATUS_INSUFFICIENT_RESOURCES; + } + + NewSamples = lrintf(((FLOAT)NumSamples * ((FLOAT)NewRate / (FLOAT)OldRate))) + 2; + + FloatOut = ExAllocatePool(NonPagedPool, NewSamples * sizeof(FLOAT)); + if (!FloatOut) + { + ExFreePool(FloatIn); + KeRestoreFloatingPointState(&FloatSave); + return STATUS_INSUFFICIENT_RESOURCES; + } + + ResultOut = ExAllocatePool(NonPagedPool, NewSamples * (BytesPerSample/8)); + if (!FloatOut) + { + ExFreePool(FloatIn); + ExFreePool(FloatOut); + KeRestoreFloatingPointState(&FloatSave); + return STATUS_INSUFFICIENT_RESOURCES; + } + + State = src_new(SRC_SINC_FASTEST, NumChannels, &error); + if (!State) + { + DPRINT1("KeSaveFloatingPointState failed with %x\n", Status); + KeRestoreFloatingPointState(&FloatSave); + ExFreePool(FloatIn); + ExFreePool(FloatOut); + ExFreePool(ResultOut); + return STATUS_UNSUCCESSFUL; + } + + /* fixme use asm */ + if (BytesPerSample == 8) + { + for(Index = 0; Index < NumSamples; Index++) + FloatIn[Index] = (float)Buffer[Index]; + } + else if (BytesPerSample == 16) + { + PUSHORT Res = (PUSHORT)ResultOut; + for(Index = 0; Index < NumSamples; Index++) + FloatIn[Index] = (float)_byteswap_ushort(Res[Index]); + } + else + { + UNIMPLEMENTED + KeRestoreFloatingPointState(&FloatSave); + ExFreePool(FloatIn); + ExFreePool(FloatOut); + ExFreePool(ResultOut); + return STATUS_UNSUCCESSFUL; + } + + Data.data_in = FloatIn; + Data.data_out = FloatOut; + Data.input_frames = NumSamples / NumChannels; + Data.output_frames = NewSamples / NumChannels; + Data.src_ratio = (double)NewRate / (double)OldRate; + + error = src_process(State, &Data); + if (error) + { + DPRINT1("src_process failed with %x\n", error); + KeRestoreFloatingPointState(&FloatSave); + ExFreePool(FloatIn); + ExFreePool(FloatOut); + ExFreePool(ResultOut); + return STATUS_UNSUCCESSFUL; + } + + if (BytesPerSample == 8) + { + for(Index = 0; Index < Data.output_frames_gen * NumChannels; Index++) + ResultOut[Index] = lrintf(FloatOut[Index]); + } + else if (BytesPerSample == 16) + { + PUSHORT Res = (PUSHORT)ResultOut; + + for(Index = 0; Index < Data.output_frames_gen * NumChannels; Index++) + Res[Index] = _byteswap_ushort(lrintf(FloatOut[Index])); + } + + *Result = ResultOut; + *ResultLength = Data.output_frames_gen * (BytesPerSample/8) * NumChannels; + ExFreePool(FloatIn); + ExFreePool(FloatOut); + src_delete(State); + KeRestoreFloatingPointState(&FloatSave); + + return STATUS_SUCCESS; +} + NTSTATUS PerformChannelConversion( PUCHAR Buffer, @@ -502,7 +636,7 @@ Pin_fnFastWrite( StreamHeader->DataUsed, InputFormat->WaveFormatEx.nChannels, OutputFormat->WaveFormatEx.nChannels, - InputFormat->WaveFormatEx.wBitsPerSample, + OutputFormat->WaveFormatEx.wBitsPerSample, &BufferOut, &BufferLength); @@ -516,9 +650,20 @@ Pin_fnFastWrite( if (InputFormat->WaveFormatEx.nSamplesPerSec != OutputFormat->WaveFormatEx.nSamplesPerSec) { - /* sample format conversion must be done in a deferred routine */ - DPRINT1("SampleRate conversion not available yet %u %u\n", InputFormat->WaveFormatEx.nSamplesPerSec, OutputFormat->WaveFormatEx.nSamplesPerSec); - return FALSE; + Status = PerformSampleRateConversion(StreamHeader->Data, + StreamHeader->DataUsed, + InputFormat->WaveFormatEx.nSamplesPerSec, + OutputFormat->WaveFormatEx.nSamplesPerSec, + OutputFormat->WaveFormatEx.wBitsPerSample, + OutputFormat->WaveFormatEx.nChannels, + &BufferOut, + &BufferLength); + if (NT_SUCCESS(Status)) + { + ExFreePool(StreamHeader->Data); + StreamHeader->Data = BufferOut; + StreamHeader->DataUsed = BufferLength; + } } if (NT_SUCCESS(Status)) @@ -567,9 +712,13 @@ CreatePin( void * calloc(size_t Elements, size_t ElementSize) { - PVOID Block = ExAllocatePool(NonPagedPool, Elements * ElementSize); - if (Block) - RtlZeroMemory(Block, Elements * ElementSize); + ULONG Index; + PUCHAR Block = ExAllocatePool(NonPagedPool, Elements * ElementSize); + if (!Block) + return NULL; + + for(Index = 0; Index < Elements * ElementSize; Index++) + Block[Index] = 0; return Block; } @@ -584,7 +733,12 @@ void *memset( int c, size_t count) { - RtlFillMemory(dest, count, c); + ULONG Index; + PUCHAR Block = (PUCHAR)dest; + + for(Index = 0; Index < count; Index++) + Block[Index] = c; + return dest; } @@ -593,18 +747,10 @@ void * memcpy( const void* src, size_t count) { - RtlCopyMemory(dest, src, count); + ULONG Index; + PUCHAR Src = (PUCHAR)src, Dest = (PUCHAR)dest; + + for(Index = 0; Index < count; Index++) + Dest[Index] = Src[Index]; return dest; } - -void *memmove( - void* dest, - const void* src, - size_t count) -{ - RtlMoveMemory(dest, src, count); - return dest; -} - - - diff --git a/reactos/drivers/wdm/audio/sysaudio/control.c b/reactos/drivers/wdm/audio/sysaudio/control.c index 613304dc84d..151740dcdb6 100644 --- a/reactos/drivers/wdm/audio/sysaudio/control.c +++ b/reactos/drivers/wdm/audio/sysaudio/control.c @@ -201,6 +201,7 @@ CreatePinWorkerRoutine( PFILE_OBJECT RealFileObject = NULL, VirtualFileObject = NULL; PSYSAUDIO_CLIENT AudioClient; PSYSAUDIO_PIN_HANDLE ClientPinHandle; + PKSDATAFORMAT_WAVEFORMATEX InputFormat; PKSDATAFORMAT_WAVEFORMATEX OutputFormat = NULL; PKSPIN_CONNECT MixerPinConnect = NULL; PPIN_WORKER_CONTEXT WorkerContext = (PPIN_WORKER_CONTEXT)Context; @@ -216,6 +217,11 @@ CreatePinWorkerRoutine( ASSERT(WorkerContext->Entry->Pins); ASSERT(WorkerContext->Entry->NumberOfPins > WorkerContext->PinConnect->PinId); + + /* Fetch input format */ + InputFormat = (PKSDATAFORMAT_WAVEFORMATEX)(WorkerContext->PinConnect + 1); + + /* Let's try to create the audio irp pin */ Status = KsCreatePin(WorkerContext->Entry->Handle, WorkerContext->PinConnect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle); @@ -258,6 +264,8 @@ CreatePinWorkerRoutine( KeBugCheck(0); return; } + DPRINT(" InputFormat: SampleRate %u Bits %u Channels %u\n", InputFormat->WaveFormatEx.nSamplesPerSec, InputFormat->WaveFormatEx.wBitsPerSample, InputFormat->WaveFormatEx.nChannels); + DPRINT("OutputFormat: SampleRate %u Bits %u Channels %u\n", OutputFormat->WaveFormatEx.nSamplesPerSec, OutputFormat->WaveFormatEx.wBitsPerSample, OutputFormat->WaveFormatEx.nChannels); } /* get pin file object */ @@ -286,15 +294,10 @@ CreatePinWorkerRoutine( /* Do we need to transform the audio stream */ if (OutputFormat != NULL) { - PKSDATAFORMAT InputFormat; - - /* Fetch input format */ - InputFormat = (PKSDATAFORMAT)(WorkerContext->PinConnect + 1); - /* Now create the mixer pin */ Status = CreateMixerPinAndSetFormat(WorkerContext->DeviceExtension->KMixerHandle, MixerPinConnect, - InputFormat, + (PKSDATAFORMAT)InputFormat, (PKSDATAFORMAT)OutputFormat, &WorkerContext->DispatchContext->hMixerPin, &WorkerContext->DispatchContext->MixerFileObject); @@ -583,6 +586,7 @@ ComputeCompatibleFormat( AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize); } /* Select best quality available */ + MixerFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX); MixerFormat->DataFormat.Flags = 0; MixerFormat->DataFormat.Reserved = 0; @@ -591,9 +595,23 @@ ComputeCompatibleFormat( MixerFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; MixerFormat->DataFormat.SampleSize = 4; MixerFormat->WaveFormatEx.wFormatTag = ClientFormat->WaveFormatEx.wFormatTag; - MixerFormat->WaveFormatEx.nChannels = min(2, AudioRange->MaximumChannels); /* AC97 does not support mono render / record */ - MixerFormat->WaveFormatEx.nSamplesPerSec = AudioRange->MaximumSampleFrequency; +#ifndef NO_AC97_HACK + /* HACK: AC97 does not support mono render / record */ + MixerFormat->WaveFormatEx.nChannels = 2; + /*HACK: AC97 only supports 16-Bit Bits */ + MixerFormat->WaveFormatEx.wBitsPerSample = 16; + +#else + MixerFormat->WaveFormatEx.nChannels = min(ClientFormat->WaveFormatEx.nSamplesPerSec, AudioRange->MaximumChannels); MixerFormat->WaveFormatEx.wBitsPerSample = AudioRange->MaximumBitsPerSample; +#endif + +#ifdef KMIXER_RESAMPLING_IMPLEMENTED + MixerFormat->WaveFormatEx.nSamplesPerSec = AudioRange->MaximumSampleFrequency; +#else + MixerFormat->WaveFormatEx.nSamplesPerSec = max(AudioRange->MinimumSampleFrequency, min(ClientFormat->WaveFormatEx.nSamplesPerSec, AudioRange->MaximumSampleFrequency)); +#endif + MixerFormat->WaveFormatEx.cbSize = 0; MixerFormat->WaveFormatEx.nBlockAlign = (MixerFormat->WaveFormatEx.nChannels * MixerFormat->WaveFormatEx.wBitsPerSample) / 8; MixerFormat->WaveFormatEx.nAvgBytesPerSec = MixerFormat->WaveFormatEx.nChannels * MixerFormat->WaveFormatEx.nSamplesPerSec * (MixerFormat->WaveFormatEx.wBitsPerSample / 8);