/* band-limited upsampling for integer multiples of base sampling rate */ public static float[] RateConvert( float[] data, int length, int factor) { #if DEBUG if (factor < 2) { Debug.Assert(false); throw new ArgumentException(); } #endif int count = 1; int newLength; while ((newLength = (1 << count)) < length * factor + 1 /*one extra at end*/) { if (count == 31) { Debug.Assert(false); throw new ArgumentException(); } count += 1; } float[] newData; using (FFT fft = FFT.Create(newLength)) { float[] b = fft.Base; int offset = fft.Offset; for (int i = 0; i < length; i++) { b[offset + i * factor + (factor - 1)] = data[i]; } fft.FFTfwd(); //b[offset + 1] = 0; /* kill top frequency bin */ /* kill all bins above original cutoff */ for (int i = ((newLength / factor) & ~1); i < newLength + 2; i += 2) { b[offset + i + 0] = 0; b[offset + i + 1] = 0; } fft.FFTinv(); newData = new float[newLength]; for (int i = 0; i < newLength; i++) { newData[i] = b[offset + i] * fft.ScaleFactor; } } return(newData); }
/* apply the convolution, accumulating into output */ public void Apply( float[] input, int inputOffset, float[] output, int outputOffset, int count, float directGain, float processedGain) { for (int i = 0; i < count; i++) { inBuf.Base[index + blockLength + inBuf.Offset] = input[i + inputOffset]; index++; if (index == blockLength) { index = 0; // prepare workspace with input buffer -- first half is data, second half+2 is zero FloatVectorCopy( inBuf.Base, inBuf.Offset, fft.Base, fft.Offset, blockLength * 2); FloatVectorZero( fft.Base, fft.Offset + blockLength * 2, blockLength * 2 + 2); // frequency domain convolution fft.FFTfwd(); FloatVectorMultiplyComplex( impulseResponseFFT.Base, impulseResponseFFT.Offset, fft.Base, fft.Offset, fft.Base, fft.Offset, blockLength * 4 + 2); fft.FFTinv(); FloatVectorScale( fft.Base, fft.Offset, outBuf.Base, outBuf.Offset, blockLength * 4, fft.ScaleFactor); // shift input buffer by half; restart accumulate of next block into second half FloatVectorCopy( inBuf.Base, blockLength + inBuf.Offset, inBuf.Base, 0 + inBuf.Offset, blockLength); } output[i + outputOffset] += outBuf.Base[index + blockLength + outBuf.Offset] * processedGain + inBuf.Base[index + inBuf.Offset] * directGain; } }