//////////////////////////////////////////////////////////////////////////////// // // Function: createUnscaledH // // Arguments: h: The impulse response. // fftSize: The size of the complex vector that will be // created. // // Returns: A pointer to a newly-allocated vector containing the // complex spectrum of h. // // Description: This function takes h, an arbitrary impulse response (filter // kernel), and creates H, the complex spectrum of h. The // spectrum is put into a complex vector with the length // of fftSize. If needed, this vector is zero-padded. This // function creates the unscaled version of H. // //////////////////////////////////////////////////////////////////////////////// private Complex[] createUnscaledH(double[] h, int fftSize) { // Make sure we have a valid pointer argument if (h == null) { throw new ArgumentNullException("h"); } // Make sure the fft size is as big or bigger than the h vector size if (fftSize < h.Length) { throw new ArgumentOutOfRangeException("h.Length", "" + h.Length); } // Create the H buffer to hold the FFT of h Complex[] H = new Complex[fftSize]; // Copy h[] into H[] vector, converting from real numbers to complex. // Zero padding is already done, since the H vector is filled with zeros // when it is created. for (int i = 0; i < h.Length; i++) { H[i] = h[i]; } // Do an in-place unscaled FFT on h, to give H FourierAnalysis.complexUnscaledFFT(H); // Return a pointer to the newly created complex H vector return(H); }
private Complex[] createIdentityKernel(int fftSize) { Complex[] H = new Complex[fftSize]; H[(int)Math.Floor((double)fftSize / 2.0)] = new Complex(1.0, 0.0); FourierAnalysis.complexUnscaledFFT(H); return(H); }
private void drawFFT(PictureBox pBox, PaintEventArgs e, int channelNum) { e.Graphics.FillRegion(Brushes.Black, new Region(new Rectangle(0, 0, pBox.Width, pBox.Height))); if (sampleTap == null || !chkDrawFFTs.Checked) { return; } Complex[] fft = new Complex[sampleData[channelNum].Length]; for (int i = 0; i < sampleData[channelNum].Length; i++) { fft[i] = sampleData[channelNum][i]; } FourierAnalysis.complexUnscaledFFT(fft); Point[] drawPts = new Point[fft.Length / 2]; for (int i = 0; i < drawPts.Length && i * 2 < fft.Length; i++) { double magnitude = 20; if (sampleTap.BitsPerSample == 24) { magnitude = 15; } try { magnitude *= Math.Log10(Math.Sqrt(fft[i].Real * fft[i].Real + fft[i].Imaginary * fft[i].Imaginary)); } catch (OverflowException) { magnitude = 0; } if (magnitude > pBox.Height || Double.IsInfinity(magnitude) || Double.IsNaN(magnitude)) { magnitude = pBox.Height; } double y = pBox.Height - magnitude; drawPts[i] = new Point(i, (int)Math.Floor(y)); } e.Graphics.DrawLines(Pens.White, drawPts); }
/// <summary> /// Performs the convolution on the next input segment. /// </summary> private void performNextConvolve() { // We only do the convolution when in the normal state if (currentState != States.Normal && currentState != States.LastReadIncomplete) { throw new Exception("Can only be called when in the Normal or LastReadIncomplete state"); } double[] sourceData = new double[inputSegmentSize * source.NumberOfChannels]; // Read frames from audio source int framesRead = source.read(sourceData, 0, sourceData.Length); if (framesRead == 0) { // If we previously had an incomplete read and now we are EOF, then we are EOF if (currentState == States.LastReadIncomplete) { currentState = States.EndOfInput; return; } // TODO: The above if is still not right. We really should remember framesRead from the // final read and then return part of the overlap buffer to complete one final read... // ... I think... // Otherwise if the last read was complete and EOF lines up with the buffers, then // overlap contains the last bit of data Array.Copy(overlapLeftWoofer, 0, bufferLeftWoofer, 0, overlapLeftWoofer.Length); Array.Copy(overlapLeftMidrange, 0, bufferLeftMidrange, 0, overlapLeftMidrange.Length); Array.Copy(overlapLeftUpperMidrange, 0, bufferLeftMidrange, 0, overlapLeftUpperMidrange.Length); Array.Copy(overlapLeftTweeter, 0, bufferLeftTweeter, 0, overlapLeftTweeter.Length); Array.Copy(overlapRightWoofer, 0, bufferRightWoofer, 0, overlapRightWoofer.Length); Array.Copy(overlapRightMidrange, 0, bufferRightMidrange, 0, overlapRightMidrange.Length); Array.Copy(overlapRightUpperMidrange, 0, bufferRightMidrange, 0, overlapRightUpperMidrange.Length); Array.Copy(overlapRightTweeter, 0, bufferRightTweeter, 0, overlapRightTweeter.Length); currentState = States.LastOverlapBuffer; return; } if (framesRead < 0 || framesRead > sourceData.Length) { throw new Exception("Audio source returned unexpected number of samples: " + framesRead); } if ((framesRead % source.NumberOfChannels) != 0) { throw new Exception("Audio source returned uneven number of samples"); } if (framesRead < sourceData.Length) { currentState = States.LastReadIncomplete; } // Copy source data into left and right structures for (int i = 0; i < framesRead; i += 2) { bufferLeftWoofer[i / 2] = sourceData[i]; bufferRightWoofer[i / 2] = sourceData[i + 1]; } framesRead /= 2; // Pad remaining part of these two buffers with zeros Array.Clear(bufferLeftWoofer, framesRead, bufferLeftWoofer.Length - framesRead); Array.Clear(bufferRightWoofer, framesRead, bufferRightWoofer.Length - framesRead); // Do an in-place unscaled FFT on the two buffers, giving us the // spectra X of the stereo input signals (i.e. X_left and X_right) FourierAnalysis.complexUnscaledFFT(bufferLeftWoofer); FourierAnalysis.complexUnscaledFFT(bufferRightWoofer); // Copy the left and right spectra into the midrange and tweeter // buffers. Once this is done, we will have X_left in three buffers // (channels) and X_right the other three buffers. Array.Copy(bufferLeftWoofer, bufferLeftMidrange, bufferLeftWoofer.Length); Array.Copy(bufferLeftWoofer, bufferLeftUpperMidrange, bufferLeftWoofer.Length); Array.Copy(bufferLeftWoofer, bufferLeftTweeter, bufferLeftWoofer.Length); Array.Copy(bufferRightWoofer, bufferRightMidrange, bufferRightWoofer.Length); Array.Copy(bufferRightWoofer, bufferRightUpperMidrange, bufferRightWoofer.Length); Array.Copy(bufferRightWoofer, bufferRightTweeter, bufferRightWoofer.Length); // Do the point-by-point complex multiply of H times X, which yields Y for (int i = 0; i < bufferLeftWoofer.Length; i++) { bufferLeftWoofer[i] *= H_woofer[i]; bufferLeftMidrange[i] *= H_midrange[i]; bufferLeftUpperMidrange[i] *= H_upperMidrange[i]; bufferLeftTweeter[i] *= H_tweeter[i]; bufferRightWoofer[i] *= H_woofer[i]; bufferRightMidrange[i] *= H_midrange[i]; bufferRightUpperMidrange[i] *= H_upperMidrange[i]; bufferRightTweeter[i] *= H_tweeter[i]; } // Do an in-place scaled IFFT on the six buffers containing Y, // to yield 6 channels of y FourierAnalysis.complexScaledIFFT(bufferLeftWoofer); FourierAnalysis.complexScaledIFFT(bufferLeftMidrange); FourierAnalysis.complexScaledIFFT(bufferLeftUpperMidrange); FourierAnalysis.complexScaledIFFT(bufferLeftTweeter); FourierAnalysis.complexScaledIFFT(bufferRightWoofer); FourierAnalysis.complexScaledIFFT(bufferRightMidrange); FourierAnalysis.complexScaledIFFT(bufferRightUpperMidrange); FourierAnalysis.complexScaledIFFT(bufferRightTweeter); // Add the contents of the overlap buffers to the first part of the // y buffers for (int i = 0; i < overlapLeftWoofer.Length; i++) { bufferLeftWoofer[i] += overlapLeftWoofer[i]; bufferLeftMidrange[i] += overlapLeftMidrange[i]; bufferLeftUpperMidrange[i] += overlapLeftUpperMidrange[i]; bufferLeftTweeter[i] += overlapLeftTweeter[i]; bufferRightWoofer[i] += overlapRightWoofer[i]; bufferRightMidrange[i] += overlapRightMidrange[i]; bufferRightUpperMidrange[i] += overlapRightUpperMidrange[i]; bufferRightTweeter[i] += overlapRightTweeter[i]; } Array.Copy(bufferLeftWoofer, inputSegmentSize, overlapLeftWoofer, 0, overlapLeftWoofer.Length); Array.Copy(bufferLeftMidrange, inputSegmentSize, overlapLeftMidrange, 0, overlapLeftMidrange.Length); Array.Copy(bufferLeftUpperMidrange, inputSegmentSize, overlapLeftUpperMidrange, 0, overlapLeftUpperMidrange.Length); Array.Copy(bufferLeftTweeter, inputSegmentSize, overlapLeftTweeter, 0, overlapLeftTweeter.Length); Array.Copy(bufferRightWoofer, inputSegmentSize, overlapRightWoofer, 0, overlapRightWoofer.Length); Array.Copy(bufferRightMidrange, inputSegmentSize, overlapRightMidrange, 0, overlapRightMidrange.Length); Array.Copy(bufferRightUpperMidrange, inputSegmentSize, overlapRightUpperMidrange, 0, overlapRightUpperMidrange.Length); Array.Copy(bufferRightTweeter, inputSegmentSize, overlapRightTweeter, 0, overlapRightTweeter.Length); return; }