/* 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); }
private FFT fft; // BlockLength*4+2 /* initialize convolver stream. The impulse response should be sampled at */ /* the nominal rate. If oversampling is being employed, it will check SynthParams */ /* and interpolate the impulse response to the real sampling rate. */ public ConvolveStreamSimple( float[] impulseResponse, int impulseResponseLength, int latency, int lOversampling) { if (lOversampling > 1) { float[] impulseResponseConverted = RateConvert( impulseResponse, impulseResponseLength, lOversampling); impulseResponse = impulseResponseConverted; impulseResponseLength *= lOversampling; } /* compute truncated latency (smallest block size we need to process) */ Debug.Assert(latency >= impulseResponseLength); latency |= latency >> 1; latency |= latency >> 2; latency |= latency >> 4; latency |= latency >> 8; latency |= latency >> 16; blockLength = latency + 1; inBuf = new AlignedWorkspace(this.blockLength * 2); outBuf = new AlignedWorkspace(this.blockLength * 4 + 2 /*for convlv*/); impulseResponseFFT = new AlignedWorkspace(this.blockLength * 4 + 2 /*for convlv*/); fft = FFT.Create(this.blockLength * 4); /* transform impulse response section to frequency domain */ FloatVectorCopyUnaligned( impulseResponse, // not guarranteed to be vector-aligned 0, fft.Base, fft.Offset, impulseResponseLength); fft.FFTfwd(); FloatVectorCopy( fft.Base, fft.Offset, impulseResponseFFT.Base, impulseResponseFFT.Offset, blockLength * 4 + 2); }