public void ProcessReverb3d(CommandList context, ref Reverb3dState state) { Debug.Assert(Parameter.IsChannelCountValid()); if (IsEffectEnabled && Parameter.IsChannelCountValid()) { Span <IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount]; Span <IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount]; for (int i = 0; i < Parameter.ChannelCount; i++) { inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]); outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]); } switch (Parameter.ChannelCount) { case 1: ProcessReverb3dMono(ref state, outputBuffers, inputBuffers, context.SampleCount); break; case 2: ProcessReverb3dStereo(ref state, outputBuffers, inputBuffers, context.SampleCount); break; case 4: ProcessReverb3dQuadraphonic(ref state, outputBuffers, inputBuffers, context.SampleCount); break; case 6: ProcessReverb3dSurround(ref state, outputBuffers, inputBuffers, context.SampleCount); break; default: throw new NotImplementedException(Parameter.ChannelCount.ToString()); } } else { for (int i = 0; i < Parameter.ChannelCount; i++) { if (InputBufferIndices[i] != OutputBufferIndices[i]) { context.CopyBuffer(OutputBufferIndices[i], InputBufferIndices[i]); } } } }
private unsafe void ProcessReverb3dGeneric(ref Reverb3dState state, ReadOnlySpan <IntPtr> outputBuffers, ReadOnlySpan <IntPtr> inputBuffers, uint sampleCount, ReadOnlySpan <int> outputEarlyIndicesTable, ReadOnlySpan <int> targetEarlyDelayLineIndicesTable, ReadOnlySpan <int> targetOutputFeedbackIndicesTable) { const int delayLineSampleIndexOffset = 1; bool isMono = Parameter.ChannelCount == 1; bool isSurround = Parameter.ChannelCount == 6; Span <float> outputValues = stackalloc float[Constants.ChannelCountMax]; Span <float> channelInput = stackalloc float[Parameter.ChannelCount]; Span <float> feedbackValues = stackalloc float[4]; Span <float> feedbackOutputValues = stackalloc float[4]; Span <float> values = stackalloc float[4]; for (int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) { outputValues.Fill(0); float tapOut = state.PreDelayLine.TapUnsafe(state.ReflectionDelayTime, delayLineSampleIndexOffset); for (int i = 0; i < targetEarlyDelayLineIndicesTable.Length; i++) { int earlyDelayIndex = targetEarlyDelayLineIndicesTable[i]; int outputIndex = outputEarlyIndicesTable[i]; float tempTapOut = state.PreDelayLine.TapUnsafe(state.EarlyDelayTime[earlyDelayIndex], delayLineSampleIndexOffset); outputValues[outputIndex] += tempTapOut * state.EarlyGain[earlyDelayIndex]; } float targetPreDelayValue = 0; for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++) { channelInput[channelIndex] = *((float *)inputBuffers[channelIndex] + sampleIndex); targetPreDelayValue += channelInput[channelIndex]; } for (int i = 0; i < Parameter.ChannelCount; i++) { outputValues[i] *= state.EarlyReflectionsGain; } state.PreviousPreDelayValue = (targetPreDelayValue * state.TargetPreDelayGain) + (state.PreviousPreDelayValue * state.PreviousPreDelayGain); state.PreDelayLine.Update(state.PreviousPreDelayValue); for (int i = 0; i < state.FdnDelayLines.Length; i++) { float fdnValue = state.FdnDelayLines[i].Read(); float feedbackOutputValue = fdnValue * state.DecayDirectFdnGain[i] + state.PreviousFeedbackOutputDecayed[i]; state.PreviousFeedbackOutputDecayed[i] = (fdnValue * state.DecayCurrentFdnGain[i]) + (feedbackOutputValue * state.DecayCurrentOutputGain[i]); feedbackOutputValues[i] = feedbackOutputValue; } feedbackValues[0] = feedbackOutputValues[2] + feedbackOutputValues[1]; feedbackValues[1] = -feedbackOutputValues[0] - feedbackOutputValues[3]; feedbackValues[2] = feedbackOutputValues[0] - feedbackOutputValues[3]; feedbackValues[3] = feedbackOutputValues[1] - feedbackOutputValues[2]; for (int i = 0; i < state.DecayDelays1.Length; i++) { float temp = state.DecayDelays1[i].Update(tapOut * state.LateReverbGain + feedbackValues[i]); values[i] = state.DecayDelays2[i].Update(temp); state.FdnDelayLines[i].Update(values[i]); } for (int channelIndex = 0; channelIndex < targetOutputFeedbackIndicesTable.Length; channelIndex++) { int targetOutputFeedbackIndex = targetOutputFeedbackIndicesTable[channelIndex]; if (targetOutputFeedbackIndex >= 0) { *((float *)outputBuffers[channelIndex] + sampleIndex) = (outputValues[channelIndex] + values[targetOutputFeedbackIndex] + channelInput[channelIndex] * state.DryGain); } } if (isMono) { *((float *)outputBuffers[0] + sampleIndex) += values[1]; } if (isSurround) { *((float *)outputBuffers[4] + sampleIndex) += (outputValues[4] + state.FrontCenterDelayLine.Update((values[2] - values[3]) * 0.5f) + channelInput[4] * state.DryGain); } } }
private void ProcessReverb3dSurround(ref Reverb3dState state, ReadOnlySpan <IntPtr> outputBuffers, ReadOnlySpan <IntPtr> inputBuffers, uint sampleCount) { ProcessReverb3dGeneric(ref state, outputBuffers, inputBuffers, sampleCount, OutputEarlyIndicesTableSurround, TargetEarlyDelayLineIndicesTableSurround, TargetOutputFeedbackIndicesTableSurround); }