Skip to content

Instantly share code, notes, and snippets.

@MysteryDash
Created March 24, 2019 19:05
Show Gist options
  • Save MysteryDash/e4ec58ea98fec66ec73105b8559e079c to your computer and use it in GitHub Desktop.
Save MysteryDash/e4ec58ea98fec66ec73105b8559e079c to your computer and use it in GitHub Desktop.
// MIT License
// Original Work Copyright(c) 2017 Tim
// Modified Work Copyright(c) 2019 Alexandre Quoniou
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Modified version of NWaves.Transforms.Fft from https://github.com/ar1st0crat/NWaves
// with added support to Span<T> (unnecessary features were stripped away).
using System;
namespace Spectro
{
class FftSpan
{
private readonly int _fftSize;
/// <summary>
/// Constructor accepting the size of FFT
/// </summary>
/// <param name="fftSize">Size of FFT</param>
public FftSpan(int fftSize)
{
var pow = (int)Math.Log(fftSize, 2);
if (fftSize != 1 << pow)
{
throw new ArgumentException("FFT size must be a power of 2!");
}
_fftSize = fftSize;
var tblSize = (int)Math.Log(fftSize, 2);
_cosTbl = new float[tblSize];
_sinTbl = new float[tblSize];
var pos = 0;
for (var i = 1; i < _fftSize; i *= 2)
{
_cosTbl[pos] = (float)Math.Cos(2 * Math.PI * i / _fftSize);
_sinTbl[pos] = (float)Math.Sin(2 * Math.PI * i / _fftSize);
pos++;
}
}
/// <summary>
/// Fast Fourier Transform algorithm
/// </summary>
/// <param name="re">Array of real parts</param>
/// <param name="im">Array of imaginary parts</param>
public void Direct(Span<float> re, Span<float> im)
{
float t1, t2;
int i, j;
int L, M, S;
L = _fftSize;
M = _fftSize >> 1;
S = _fftSize - 1;
var ti = 0;
while (L >= 2)
{
var l = L >> 1;
var u1 = 1.0f;
var u2 = 0.0f;
var c = _cosTbl[ti];
var s = -_sinTbl[ti];
ti++;
for (j = 0; j < l; j++)
{
for (i = j; i < _fftSize; i += L)
{
var p = i + l;
t1 = re[i] + re[p];
t2 = im[i] + im[p];
var t3 = re[i] - re[p];
var t4 = im[i] - im[p];
re[p] = t3 * u1 - t4 * u2;
im[p] = t4 * u1 + t3 * u2;
re[i] = t1;
im[i] = t2;
}
var u3 = u1 * c - u2 * s;
u2 = u2 * c + u1 * s;
u1 = u3;
}
L >>= 1;
}
j = 0;
for (i = 0; i < S; i++)
{
if (i > j)
{
t1 = re[j];
t2 = im[j];
re[j] = re[i];
im[j] = im[i];
re[i] = t1;
im[i] = t2;
}
var k = M;
while (j >= k)
{
j -= k;
k >>= 1;
}
j += k;
}
}
private readonly float[] _cosTbl;
private readonly float[] _sinTbl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment