private void FFTWindowChange(Complex[] channelData, FFTWindow window) { switch (window) { case FFTWindow.HannWindow: for (int i = 0; i < channelData.Length; i++) { channelData[i].X = (float)(channelData[i].X * FastFourierTransform.HannWindow(i, bufferSize)); } break; case FFTWindow.HammingWindow: for (int i = 0; i < channelData.Length; i++) { channelData[i].X = (float)(channelData[i].X * FastFourierTransform.HammingWindow(i, bufferSize)); } break; case FFTWindow.BlackmannHarrisWindow: for (int i = 0; i < channelData.Length; i++) { channelData[i].X = (float)(channelData[i].X * FastFourierTransform.BlackmannHarrisWindow(i, bufferSize)); } break; } FastFourierTransform.FFT(false, binaryExponentitation, channelData); }
private void DataAvailable(object sender, WaveInEventArgs e) { // Convert byte[] to float[]. float[] data = ConvertByteToFloat(e.Buffer, e.BytesRecorded); // For all data. Skip right channel on stereo (i += this.Format.Channels). for (int i = 0; i < data.Length; i += this.Format.Channels) { this._fftBuffer[_fftPos].X = (float)(data[i] * FastFourierTransform.HannWindow(_fftPos, _fftLength)); this._fftBuffer[_fftPos].Y = 0; this._fftPos++; if (this._fftPos >= this._fftLength) { this._fftPos = 0; // NAudio FFT implementation. FastFourierTransform.FFT(true, this._m, this._fftBuffer); // Copy to buffer. lock (this._lock) { for (int c = 0; c < this._fftLength; c++) { float amplitude = (float)Math.Sqrt(this._fftBuffer[c].X * this._fftBuffer[c].X + this._fftBuffer[c].Y * this._fftBuffer[c].Y); this._lastFftBuffer[c] = amplitude; } this._fftBufferAvailable = true; } } } }
public IDisposable Subscribe(IObserver <float[]> obs) { var fftBuffer = new Complex[fftLength]; var fftPos = 0; return (source.Subscribe(wave => { for (var i = 0; i < wave.ShortBufferCount; i++) { var value = wave.ShortBuffer[i]; fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HannWindow(fftPos, fftLength)); fftBuffer[fftPos].Y = 0; fftPos++; if (fftPos >= fftBuffer.Length) { fftPos = 0; FastFourierTransform.FFT(true, m, fftBuffer); var result = fftBuffer .Take(fftLength / 2) .Select(GetDb) .ToArray(); obs.OnNext(result); } } }, obs.OnError, obs.OnCompleted )); }
public static void AddSample(float value) { switch (Window) { case FFTWindow.BlackmannHarris: _fftBuffer[_fftPos].X = (float)(value * FastFourierTransform.BlackmannHarrisWindow(_fftPos, _fftLength)); break; case FFTWindow.Hamming: _fftBuffer[_fftPos].X = (float)(value * FastFourierTransform.HammingWindow(_fftPos, _fftLength)); break; case FFTWindow.Hann: _fftBuffer[_fftPos].X = (float)(value * FastFourierTransform.HannWindow(_fftPos, _fftLength)); break; } _fftBuffer[_fftPos].Y = 0; _fftPos++; if (_fftPos >= _fftLength) { _fftPos = 0; FastFourierTransform.FFT(true, _m, _fftBuffer); FftCalculated(); } }
public async IAsyncEnumerable <FrequencyAmplitude[]> EnumerateFrequencyAmplitudesAsync(InputOption option, [EnumeratorCancellation] CancellationToken token) { var samplesCount = Convert.ToInt32(Math.Pow(2, power)); //var complexSamples = new Complex[samplesCount]; var complexSamples = new Complex[samplesCount]; //var doubleSamples = new double[samplesCount]; var position = 0; await foreach (var samples in option.Owner.EnumerateSamplesAsync(option, token)) { int i; for (i = 0; i < samples.Length; i++) { complexSamples[position] = new Complex { X = (float)(samples[i].Values[0] * FastFourierTransform.HannWindow(position, 1024)), Y = 0 //Just the real part }; //doubleSamples[position] = samples[i].Values[0]; position++; if (position >= samplesCount) { FastFourierTransform.FFT(true, (int)Math.Log(samplesCount, 2.0), complexSamples); //var amplitudes = complexSamples.Take(complexSamples.Length / 2).Select( var j = 0; var actualSamplesCount = (complexSamples.Length / 2) + 1; var amplitudes = complexSamples.Take(actualSamplesCount).Select( c => new FrequencyAmplitude( new Frequency(GetFrequency(j++, actualSamplesCount, option.SamplingFrequency)), //new Amplitude(new float[] { Math.Abs(c.X + c.Y) }) //new Amplitude(new float[] { (float) Math.Log(Math.Abs(c.X + c.Y)) }) new Amplitude(new float[] { GetAmplitude(c) }) ) ).ToArray(); yield return(amplitudes); position = 0; } } /*while (complexSamples.Count >= samplesCount) * { * Array.Copy() * FastFourierTransform.FFT(true, power, ) * yield return new FrequencyAmplitude[1] { new FrequencyAmplitude(new Frequency(11), new Amplitude(new float[0])) }; * }*/ } }
public void Add(float value) { if (PerformFFT && FftCalculated != null) { // Remember the window function! There are many others as well. fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HannWindow(fftPos, fftLength)); fftBuffer[fftPos].Y = 0; // This is always zero with audio. fftPos++; if (fftPos >= fftLength) { fftPos = 0; //FastFourierTransform.FFT(true, m, fftBuffer); FftCalculated(this, fftArgs); } } }
public void Add(float value) { if (PerformFFT && FftCalculated != null) { fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HannWindow(fftPos, fftLength)); fftBuffer[fftPos].Y = 0; fftPos++; if (fftPos >= fftLength) { fftPos = 0; FastFourierTransform.FFT(true, m, fftBuffer); FftCalculated(this, fftArgs); } } }
private void DataAvailable(object sender, WaveInEventArgs args) { var count = args.BytesRecorded / 4; // 32-bit var buffer = new WaveBuffer(args.Buffer); for (int i = 0; i < count; ++i) { _fftBuffer[i].X = (float)(buffer.FloatBuffer[i] * FastFourierTransform.HannWindow(i, _fftLength)); _fftBuffer[i].Y = 0; if (i + 1 >= _fftLength) { FastFourierTransform.FFT(true, (int)Math.Log(this._fftLength, 2.0), _fftBuffer); for (int j = 0; j < _fftLength; ++j) { _amplitudes[j] = (float)Math.Sqrt(Math.Pow(_fftBuffer[j].X, 2) + Math.Pow(_fftBuffer[j].Y, 2)); } Visualizer.SetData(_amplitudes); break; } } }
private void Add(float value) { input[fftPos] = value * FastFourierTransform.HannWindow(fftPos, fftLength); input2[fftPos2] = value * FastFourierTransform.HannWindow(fftPos2, fftLength); fftPos++; fftPos2++; if (fftPos >= fftLength || fftPos2 >= fftLength) { var pin = pinIn; if (fftPos2 >= fftLength) { pin = pinIn2; fftPos2 = 0; } else { fftPos = 0; } DFT.FFT(pin, pinOut); for (int i = 1; i < fftLength / 2; i++) { var real = (float)pinOut[i].Real; var img = (float)pinOut[i].Imaginary; var newValue = (float)(Math.Sqrt(real * real + img * img) / fftLength / (2 * 44100)); if (i < spreadBuilder.Count) { spreadBuilder[i] = newValue; } else { spreadBuilder.Add(newValue); } } Spread = spreadBuilder.ToSpread(); } }
/// <summary> /// Inits the capture: /// - inits the capture to listen to the current default output device /// - creates the listener /// - starts recording /// </summary> private void InitCapture() { // Takes the current default output device capture = new WasapiLoopbackCapture(); // Used to get the audio spectrum using FFT int fftPos = 0; int m = (int)Math.Log(fftLength, 2.0); object _lock = new object(); Complex[] fftBuffer = new Complex[fftLength]; // the data lastFftBuffer = new float[fftLength]; // the last data saved capture.DataAvailable += (object sender, WaveInEventArgs args) => { // Interprets the sample as 32 bit floating point audio (-> FloatBuffer) soundLevel = 0; var buffer = new WaveBuffer(args.Buffer); for (int index = 0; index < args.BytesRecorded / 4; index++) { var sample = buffer.FloatBuffer[index]; // Sound level if (sample < 0) { sample = -sample; // abs } if (sample > soundLevel) { soundLevel = sample; } // Bass level if (listenForBass) { // HannWindow sample with amplitude -> amplitude to decibels fftBuffer[fftPos].X = (float)(sample * FastFourierTransform.HannWindow(fftPos, fftLength)); fftBuffer[fftPos].Y = 0; fftPos++; if (fftPos >= fftLength) { fftPos = 0; FastFourierTransform.FFT(true, m, fftBuffer); lock (_lock) { bufferAvailible = false; for (int c = 0; c < fftLength; c++) { float amplitude = (float)Math.Sqrt(fftBuffer[c].X * fftBuffer[c].X + fftBuffer[c].Y * fftBuffer[c].Y); lastFftBuffer[c] = amplitude; } bufferAvailible = true; } } } } }; capture.StartRecording(); }
public static AudioData GetFrequencyBands(float[] sampleArray) { NAudio.Dsp.Complex[] complices = new NAudio.Dsp.Complex[sampleArray.Length]; List <float>[] amplitudeLists = GetEmptyFloatListArray(); // Collates the amplitudes into complexes wtih the Hann window applied for (int fftPosition = 0; fftPosition < sampleArray.Length; fftPosition++) { complices[fftPosition].X = Convert.ToSingle(sampleArray[fftPosition] * FastFourierTransform.HannWindow(fftPosition, sampleArray.Length)); complices[fftPosition].Y = 0; } // Performs the FFT to get the frequencies out FastFourierTransform.FFT(true, (int)Math.Log(sampleArray.Length, 2.0), complices); float[] realFrequencies = new float[complices.Length]; // Gets the real numbers out of the complex numbers for (int realPosition = 0; realPosition < complices.Length; realPosition++) { realFrequencies[realPosition] = Convert.ToSingle(Math.Pow(complices[realPosition].X, 2) + Math.Pow(complices[realPosition].Y, 2)); } // Creates an array of empty numbers to collate the counts of categorisation int[] counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; float maxFrequency = realFrequencies.Max(); for (int lightPosition = 0; lightPosition < realFrequencies.Length; lightPosition++) { // Gets the frequency on a scale from 0 to 1 in this window float realFrequencyNormal = realFrequencies[lightPosition] / maxFrequency; int lightToIncrement; // If the max frequency in this time slice is 0, that means that all of the values are 0 and we should avoid doing any more maths if (maxFrequency == 0) { lightToIncrement = 0; } else { lightToIncrement = Convert.ToInt32(Math.Round(16 * (Math.Sqrt(realFrequencyNormal)))); } // Prevents the index from going over the maximum range if (lightToIncrement == 16) { lightToIncrement = 15; } counts[lightToIncrement]++; amplitudeLists[lightToIncrement].Add(sampleArray[lightPosition]); } float[] averageAmplitudes = new float[16]; for (int averageAmplitudePosition = 0; averageAmplitudePosition < averageAmplitudes.Length; averageAmplitudePosition++) { if (amplitudeLists[averageAmplitudePosition].Count != 0) { averageAmplitudes[averageAmplitudePosition] = Math.Abs(amplitudeLists[averageAmplitudePosition].Average()); } else { averageAmplitudes[averageAmplitudePosition] = 0; } } AudioData output = new AudioData(counts, averageAmplitudes); // These mask functions were intended to distribute values, solving the issue of the frequencies dogpiling the first band, but I found these did more harm than good, and commented them out //Vector<short> countVector = GetLightVector(counts); //for (int vectorPosition = 0; vectorPosition < counts.Length; vectorPosition++) //{ // Vector<short> currentMask = GetMaskVector(vectorPosition); // countVector = Vector.Divide(countVector, currentMask); //} //for (int vectorToArrayPosition = 0; vectorToArrayPosition < 16; vectorToArrayPosition++) //{ // counts[vectorToArrayPosition] = Convert.ToInt32(countVector[vectorToArrayPosition]); //} return(output); }