- 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
This commit is contained in:
Johannes Anderwald 2009-04-15 10:41:41 +00:00
parent 2b9ed04e31
commit 27c2bd90eb
2 changed files with 193 additions and 29 deletions

View file

@ -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;
}

View file

@ -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);