private void FilterStream(CrossTimeDspConfiguration configuration, SampleBuffer inputBuffer, SampleType dataPathSampleType, SampleType outputSampleType) { // setup FilterBank filters = new FilterBank(configuration.Engine.Precision, inputBuffer.WaveFormat.SampleRate, inputBuffer.WaveFormat.Channels, configuration.Engine.Q31Adaptive.Q31_32x64_Threshold, configuration.Engine.Q31Adaptive.Q31_64x64_Threshold); foreach (Filter filter in configuration.Filters) { filter.AddTo(filters); } // time duration of reverse time pass DateTime filteringStartedUtc = DateTime.UtcNow; using (SampleBuffer reverseTimeBuffer = new SampleBuffer(inputBuffer.WaveFormat.SampleRate, outputSampleType.BitsPerSample(), inputBuffer.WaveFormat.Channels)) { SampleBlock recirculatingDataPathBlock = null; for (LinkedListNode <SampleBlock> blockNode = inputBuffer.Blocks.Last; blockNode != null; blockNode = blockNode.Previous) { SampleBlock filteredBlock = filters.FilterReverse(blockNode.Value, dataPathSampleType, outputSampleType, ref recirculatingDataPathBlock); reverseTimeBuffer.Blocks.AddFirst(filteredBlock); } if (recirculatingDataPathBlock != null) { recirculatingDataPathBlock.Dispose(); } reverseTimeBuffer.RecalculateBlocks(); DateTime filteringStoppedUtc = DateTime.UtcNow; if (filters.TimingAvailable) { this.TestContext.WriteLine("{0} ({1} {2} {3})", (filteringStoppedUtc - filteringStartedUtc).ToString(Constant.ElapsedTimeFormat), filters.ToDataPathTime.ToString(Constant.ElapsedTimeFormat), filters.FilterTime.ToString(Constant.ElapsedTimeFormat), filters.ToOutputTime.ToString(Constant.ElapsedTimeFormat)); } else { this.TestContext.WriteLine("{0}", (filteringStoppedUtc - filteringStartedUtc).ToString(Constant.ElapsedTimeFormat)); } } }
private WaveStream FilterStream(WaveStream inputStream, out StreamPerformance performance) { performance = new StreamPerformance(); // populate filters FilterBank forwardTimeFilters = new FilterBank(this.Configuration.Engine.Precision, inputStream.WaveFormat.SampleRate, inputStream.WaveFormat.Channels, this.Configuration.Engine.Q31Adaptive.Q31_32x64_Threshold, this.Configuration.Engine.Q31Adaptive.Q31_64x64_Threshold); FilterBank reverseTimeFilters = new FilterBank(this.Configuration.Engine.Precision, inputStream.WaveFormat.SampleRate, inputStream.WaveFormat.Channels, this.Configuration.Engine.Q31Adaptive.Q31_32x64_Threshold, this.Configuration.Engine.Q31Adaptive.Q31_64x64_Threshold); foreach (Filter filter in this.Configuration.Filters) { switch (filter.TimeDirection) { case TimeDirection.Forward: filter.AddTo(forwardTimeFilters); break; case TimeDirection.Reverse: filter.AddTo(reverseTimeFilters); break; default: throw new NotSupportedException(String.Format("Unhandled time direction {0}.", filter.TimeDirection)); } } // do reverse time pass // If the only reverse time filter is the anti-clipping gain then there's nothing to do. SampleType dataPathSampleType = this.Configuration.Engine.Precision == FilterPrecision.Double ? SampleType.Double : SampleType.Int32; bool hasForwardTimeFilters = forwardTimeFilters.FilterCount > 0; SampleType outputSampleType = SampleTypeExtensions.FromBitsPerSample(this.Configuration.Output.BitsPerSample); if (reverseTimeFilters.FilterCount > 0 && (this.Stopping == false)) { using (SampleBuffer inputBuffer = new SampleBuffer(inputStream)) { // set up buffer for output of reverse time pass and dispose input stream as it's no longer needed performance.ReverseBufferCompleteUtc = DateTime.UtcNow; SampleType reverseTimeSampleType = hasForwardTimeFilters ? dataPathSampleType : outputSampleType; SampleBuffer reverseTimeBuffer = new SampleBuffer(inputStream.WaveFormat.SampleRate, reverseTimeSampleType.BitsPerSample(), inputStream.WaveFormat.Channels); inputStream.Dispose(); // input blocks are disposed as they're processed to limit peak memory consumption (and removed from the input buffer for completeness) SampleBlock recirculatingDataPathBlock = null; for (LinkedListNode <SampleBlock> blockNode = inputBuffer.Blocks.Last; blockNode != null; blockNode = blockNode.Previous, inputBuffer.Blocks.RemoveLast()) { using (SampleBlock block = blockNode.Value) { SampleBlock filteredBlock = reverseTimeFilters.FilterReverse(block, dataPathSampleType, reverseTimeSampleType, ref recirculatingDataPathBlock); reverseTimeBuffer.Blocks.AddFirst(filteredBlock); } if (this.Stopping) { break; } } if (recirculatingDataPathBlock != null) { recirculatingDataPathBlock.Dispose(); } // prepare to apply forward time pass to output of reverse time pass or just to write output reverseTimeBuffer.RecalculateBlocks(); inputStream = reverseTimeBuffer; performance.ReverseTimeCompleteUtc = DateTime.UtcNow; } } // do forward time pass if (hasForwardTimeFilters && (this.Stopping == false)) { SampleBuffer outputStream = new SampleBuffer(inputStream.WaveFormat.SampleRate, outputSampleType.BitsPerSample(), inputStream.WaveFormat.Channels); SampleBlock recirculatingDataPathBlock = null; if (inputStream is SampleBuffer) { SampleBuffer inputBlocks = (SampleBuffer)inputStream; for (LinkedListNode <SampleBlock> blockNode = inputBlocks.Blocks.First; blockNode != null; blockNode = blockNode.Next, inputBlocks.Blocks.RemoveFirst()) { using (SampleBlock block = blockNode.Value) { SampleBlock filteredBlock = forwardTimeFilters.Filter(block, dataPathSampleType, outputSampleType, ref recirculatingDataPathBlock); outputStream.Blocks.AddLast(filteredBlock); } if (this.Stopping) { break; } } } else { byte[] inputBuffer = new byte[Constant.SampleBlockSizeInBytes]; while (inputStream.CanRead) { int bytesRead = inputStream.Read(inputBuffer, 0, inputBuffer.Length); if (bytesRead < 1) { // workaround for NAudio bug: WaveStream.CanRead is hard coded to true regardless of position break; } using (SampleBlock block = new SampleBlock(inputBuffer, bytesRead, SampleTypeExtensions.FromBitsPerSample(inputStream.WaveFormat.BitsPerSample))) { SampleBlock filteredBlock = forwardTimeFilters.Filter(block, dataPathSampleType, outputSampleType, ref recirculatingDataPathBlock); outputStream.Blocks.AddLast(filteredBlock); } if (this.Stopping) { return(null); } } } if (recirculatingDataPathBlock != null) { recirculatingDataPathBlock.Dispose(); } // release input stream as it's no longer needed and complete output inputStream.Dispose(); outputStream.RecalculateBlocks(); inputStream = outputStream; } forwardTimeFilters.Dispose(); reverseTimeFilters.Dispose(); performance.CompleteTimeUtc = DateTime.UtcNow; return(inputStream); }