예제 #1
0
            /* 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);
            }
예제 #2
0
            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);
            }
예제 #3
0
            /* 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;
                }
            }